📄 next.pm
字号:
# handle here } else { # try elsewhere shift()->NEXT::ACTUAL::AUTOLOAD(@_); } }By using C<NEXT::ACTUAL>, if there is no other C<AUTOLOAD> to handle themethod call, an exception will be thrown (as usually happens in the absence ofa suitable C<AUTOLOAD>).=head2 Avoiding repetitionsIf C<NEXT> redispatching is used in the methods of a "diamond" class hierarchy: # A B # / \ / # C D # \ / # E use NEXT; package A; sub foo { print "called A::foo\n"; shift->NEXT::foo() } package B; sub foo { print "called B::foo\n"; shift->NEXT::foo() } package C; @ISA = qw( A ); sub foo { print "called C::foo\n"; shift->NEXT::foo() } package D; @ISA = qw(A B); sub foo { print "called D::foo\n"; shift->NEXT::foo() } package E; @ISA = qw(C D); sub foo { print "called E::foo\n"; shift->NEXT::foo() } E->foo();then derived classes may (re-)inherit base-class methods through two ormore distinct paths (e.g. in the way C<E> inherits C<A::foo> twice --through C<C> and C<D>). In such cases, a sequence of C<NEXT> redispatcheswill invoke the multiply inherited method as many times as it isinherited. For example, the above code prints: called E::foo called C::foo called A::foo called D::foo called A::foo called B::foo(i.e. C<A::foo> is called twice).In some cases this I<may> be the desired effect within a diamond hierarchy,but in others (e.g. for destructors) it may be more appropriate to call each method only once during a sequence of redispatches.To cover such cases, you can redispatch methods via: $self->NEXT::DISTINCT::method();rather than: $self->NEXT::method();This causes the redispatcher to only visit each distinct C<method> methodonce. That is, to skip any classes in the hierarchy that it hasalready visited during redispatch. So, for example, if theprevious example were rewritten: package A; sub foo { print "called A::foo\n"; shift->NEXT::DISTINCT::foo() } package B; sub foo { print "called B::foo\n"; shift->NEXT::DISTINCT::foo() } package C; @ISA = qw( A ); sub foo { print "called C::foo\n"; shift->NEXT::DISTINCT::foo() } package D; @ISA = qw(A B); sub foo { print "called D::foo\n"; shift->NEXT::DISTINCT::foo() } package E; @ISA = qw(C D); sub foo { print "called E::foo\n"; shift->NEXT::DISTINCT::foo() } E->foo();then it would print: called E::foo called C::foo called A::foo called D::foo called B::fooand omit the second call to C<A::foo> (since it would not be distinctfrom the first call to C<A::foo>).Note that you can also use: $self->NEXT::DISTINCT::ACTUAL::method();or: $self->NEXT::ACTUAL::DISTINCT::method();to get both unique invocation I<and> exception-on-failure.Note that, for historical compatibility, you can also useC<NEXT::UNSEEN> instead of C<NEXT::DISTINCT>.=head2 Invoking all versions of a method with a single callYet another pseudo-class that NEXT.pm provides is C<EVERY>.Its behaviour is considerably simpler than that of the C<NEXT> family.A call to: $obj->EVERY::foo();calls I<every> method named C<foo> that the object in C<$obj> has inherited.That is: use NEXT; package A; @ISA = qw(B D X); sub foo { print "A::foo " } package B; @ISA = qw(D X); sub foo { print "B::foo " } package X; @ISA = qw(D); sub foo { print "X::foo " } package D; sub foo { print "D::foo " } package main; my $obj = bless {}, 'A'; $obj->EVERY::foo(); # prints" A::foo B::foo X::foo D::fooPrefixing a method call with C<EVERY::> causes every method in theobject's hierarchy with that name to be invoked. As the above exampleillustrates, they are not called in Perl's usual "left-most-depth-first"order. Instead, they are called "breadth-first-dependency-wise".That means that the inheritance tree of the object is traversed breadth-firstand the resulting order of classes is used as the sequence in which methodsare called. However, that sequence is modified by imposing a rule that theappropriate method of a derived class must be called before the same method ofany ancestral class. That's why, in the above example, C<X::foo> is calledbefore C<D::foo>, even though C<D> comes before C<X> in C<@B::ISA>.In general, there's no need to worry about the order of calls. They will beleft-to-right, breadth-first, most-derived-first. This works perfectly formost inherited methods (including destructors), but is inappropriate forsome kinds of methods (such as constructors, cloners, debuggers, andinitializers) where it's more appropriate that the least-derived methods becalled first (as more-derived methods may rely on the behaviour of their"ancestors"). In that case, instead of using the C<EVERY> pseudo-class: $obj->EVERY::foo(); # prints" A::foo B::foo X::foo D::foo you can use the C<EVERY::LAST> pseudo-class: $obj->EVERY::LAST::foo(); # prints" D::foo X::foo B::foo A::foo which reverses the order of method call.Whichever version is used, the actual methods are called in the samecontext (list, scalar, or void) as the original call via C<EVERY>, and return:=over=item *A hash of array references in list context. Each entry of the hash has thefully qualified method name as its key and a reference to an array containingthe method's list-context return values as its value.=item *A reference to a hash of scalar values in scalar context. Each entry of the hash has thefully qualified method name as its key and the method's scalar-context return values as its value.=item *Nothing in void context (obviously).=back=head2 Using C<EVERY> methodsThe typical way to use an C<EVERY> call is to wrap it in another basemethod, that all classes inherit. For example, to ensure that everydestructor an object inherits is actually called (as opposed to just theleft-most-depth-first-est one): package Base; sub DESTROY { $_[0]->EVERY::Destroy } package Derived1; use base 'Base'; sub Destroy {...} package Derived2; use base 'Base', 'Derived1'; sub Destroy {...}et cetera. Every derived class than needs its own clean-upbehaviour simply adds its own C<Destroy> method (I<not> a C<DESTROY> method),which the call to C<EVERY::LAST::Destroy> in the inherited destructorthen correctly picks up.Likewise, to create a class hierarchy in which every initializer inherited bya new object is invoked: package Base; sub new { my ($class, %args) = @_; my $obj = bless {}, $class; $obj->EVERY::LAST::Init(\%args); } package Derived1; use base 'Base'; sub Init { my ($argsref) = @_; ... } package Derived2; use base 'Base', 'Derived1'; sub Init { my ($argsref) = @_; ... }et cetera. Every derived class than needs some additional initializationbehaviour simply adds its own C<Init> method (I<not> a C<new> method),which the call to C<EVERY::LAST::Init> in the inherited constructorthen correctly picks up.=head1 AUTHORDamian Conway (damian@conway.org)=head1 BUGS AND IRRITATIONSBecause it's a module, not an integral part of the interpreter, NEXT.pmhas to guess where the surrounding call was found in the methodlook-up sequence. In the presence of diamond inheritance patternsit occasionally guesses wrong.It's also too slow (despite caching).Comment, suggestions, and patches welcome.=head1 COPYRIGHT Copyright (c) 2000-2001, Damian Conway. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -