summaryrefslogtreecommitdiff
path: root/pod/perlfunc.pod
diff options
context:
space:
mode:
authorYves Orton <demerphq@gmail.com>2022-12-19 19:32:03 +0100
committerYves Orton <demerphq@gmail.com>2023-03-18 20:57:59 +0800
commit93f6f9654a81b66c47c07ca982e4c00558bd4159 (patch)
treeeb352f43ebad63b8813f6b3ef7b2084fd91df13f /pod/perlfunc.pod
parent2f920c2f73ae58b754ccf1d897f1104e0cc3a4c6 (diff)
downloadperl-93f6f9654a81b66c47c07ca982e4c00558bd4159.tar.gz
pp_ctl.c - add support for hooking require.
This defines a new magic hash C<%{^HOOK}> which is intended to be used for hooking keywords. It is similar to %SIG in that the values it contains are validated on set, and it is not allowed to store something in C<%{^HOOK}> that isn't supposed to be there. Hooks are expected to be coderefs (people can use currying if they really want to put an object in there, the API is deliberately simple.) The C<%{^HOOK}> hash is documented to have keys of the form "${keyword}__${phase}" where $phase is either "before" or "after" and in this initial release two hooks are supported, "require__before" and "require__after": The C<require__before> hook is called before require is executed, including any @INC hooks that might be fired. It is called with the path of the file being required, just as would be stored in %INC. The hook may alter the filename by writing to $_[0] and it may return a coderef to be executed *after* the require has completed, otherwise the return is ignored. This coderef is also called with the path of the file which was required, and it will be called regardless as to whether the require (or its dependencies) die during execution. This mechanism makes it trivial and safe to share state between the initial hook and the coderef it returns. The C<require__after> hook is similar to the C<require__before> hook however except that it is called after the require completes (successfully or not), and its return is ignored always.
Diffstat (limited to 'pod/perlfunc.pod')
-rw-r--r--pod/perlfunc.pod64
1 files changed, 63 insertions, 1 deletions
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod
index 90f07afbe8..5a26941e75 100644
--- a/pod/perlfunc.pod
+++ b/pod/perlfunc.pod
@@ -7064,7 +7064,69 @@ require executes at all.
As of 5.37.7 C<@INC> values of undef will be silently ignored.
-For a yet-more-powerful import facility, see
+The function C<require()> is difficult to wrap properly. Many modules
+consult the stack to find information about their caller, and injecting
+a new stack frame by wrapping C<require()> often breaks things.
+Nevertheless it can be very helpful to have the ability to perform
+actions before and after a C<require>, for instance for trace utilities
+like C<Devel::TraceUse> or to measure time to load and the memory
+consumption of the require graph. Because of the difficulties in safely
+creating a C<require()> wrapper in 5.37.10 we introduced a new mechanism.
+
+As of 5.37.10, prior to any other actions it performs, C<require> will
+check if C<${^HOOK}{require__before}> contains a coderef, and if it does
+it will be called with the filename form of the item being loaded. The hook
+may modify C<$_[0]> to load a different filename, or it may throw a fatal
+exception to cause the require to fail, which will be treated as though the
+required code itself had thrown an exception.
+
+The C<${^HOOK}{require__before}> hook may return a code reference, in
+which case the code reference will be executed (in an eval with the
+filname as a parameter) after the require completes. It will be executed
+regardless of how the compilation completed, and even if the require
+throws a fatal exception. The function may consult C<%INC> to determine
+if the require failed or not. For instance the following code will print
+some diagnostics before and after every C<require> statement. The
+example also includes logic to chain the signal, so that multiple
+signals can cooperate. Well behaved C<${^HOOK}{require__before}>
+handlers should always take this into account.
+
+ {
+ use Scalar::Util qw(reftype);
+ my $old_hook = ${^HOOK}{require__before};
+ local ${^HOOK}{require__before} = sub {
+ my ($name) = @_;
+ my $old_hook_ret;
+ $old_hook_ret = $old_hook->($name) if $old_hook;
+ warn "Requiring: $name\n";
+ return sub {
+ $old_hook_ret->() if ref($old_hook_ret)
+ && reftype($old_hook_ret) eq "CODE";
+ warn sprintf "Finished requiring %s: %s\n",
+ $name, $INC{$name} ? "loaded" :"failed";
+ };
+ };
+ require Whatever;
+ }
+
+This hook executes for ALL C<require> statements, unlike C<INC> and
+C<INCDIR> hooks, which are only executed for relative file names, and it
+executes first before any other special behaviour inside of require.
+Note that the initial hook in C<${^HOOK}{require__before}> is *not*
+executed inside of an eval, and throwing an exception will stop further
+processing, but the after hook it may return is executed inside of an
+eval, and any exceptions it throws will be silently ignored. This is
+because it executes inside of the scope cleanup logic that is triggered
+after the require completes, and an exception at this time would not
+stop the module from being loaded, etc.
+
+There is a similar hook that fires after require completes,
+C<${^HOOK}{require__after}>, which will be called after each require statement
+completes, either via an exception or successfully. It will be called with
+the filename of the most recently executed require statement. It is executed
+in an eval, and will not in any way affect execution.
+
+For a yet-more-powerful import facility built around C<require>, see
L<C<use>|/use Module VERSION LIST> and L<perlmod>.
=item reset EXPR