📄 next.3
字号:
\& # \e /\& # E\&\& use NEXT;\&\& package A; \& sub foo { print "called A::foo\en"; shift\->NEXT::foo() }\&\& package B; \& sub foo { print "called B::foo\en"; shift\->NEXT::foo() }\&\& package C; @ISA = qw( A );\& sub foo { print "called C::foo\en"; shift\->NEXT::foo() }\&\& package D; @ISA = qw(A B);\& sub foo { print "called D::foo\en"; shift\->NEXT::foo() }\&\& package E; @ISA = qw(C D);\& sub foo { print "called E::foo\en"; shift\->NEXT::foo() }\&\& E\->foo();.Ve.PPthen derived classes may (re\-)inherit base-class methods through two ormore distinct paths (e.g. in the way \f(CW\*(C`E\*(C'\fR inherits \f(CW\*(C`A::foo\*(C'\fR twice \*(--through \f(CW\*(C`C\*(C'\fR and \f(CW\*(C`D\*(C'\fR). In such cases, a sequence of \f(CW\*(C`NEXT\*(C'\fR redispatcheswill invoke the multiply inherited method as many times as it isinherited. For example, the above code prints:.PP.Vb 6\& called E::foo\& called C::foo\& called A::foo\& called D::foo\& called A::foo\& called B::foo.Ve.PP(i.e. \f(CW\*(C`A::foo\*(C'\fR is called twice)..PPIn some cases this \fImay\fR 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..PPTo cover such cases, you can redispatch methods via:.PP.Vb 1\& $self\->NEXT::DISTINCT::method();.Ve.PPrather than:.PP.Vb 1\& $self\->NEXT::method();.Ve.PPThis causes the redispatcher to only visit each distinct \f(CW\*(C`method\*(C'\fR methodonce. That is, to skip any classes in the hierarchy that it hasalready visited during redispatch. So, for example, if theprevious example were rewritten:.PP.Vb 2\& package A; \& sub foo { print "called A::foo\en"; shift\->NEXT::DISTINCT::foo() }\&\& package B; \& sub foo { print "called B::foo\en"; shift\->NEXT::DISTINCT::foo() }\&\& package C; @ISA = qw( A );\& sub foo { print "called C::foo\en"; shift\->NEXT::DISTINCT::foo() }\&\& package D; @ISA = qw(A B);\& sub foo { print "called D::foo\en"; shift\->NEXT::DISTINCT::foo() }\&\& package E; @ISA = qw(C D);\& sub foo { print "called E::foo\en"; shift\->NEXT::DISTINCT::foo() }\&\& E\->foo();.Ve.PPthen it would print:.PP.Vb 5\& called E::foo\& called C::foo\& called A::foo\& called D::foo\& called B::foo.Ve.PPand omit the second call to \f(CW\*(C`A::foo\*(C'\fR (since it would not be distinctfrom the first call to \f(CW\*(C`A::foo\*(C'\fR)..PPNote that you can also use:.PP.Vb 1\& $self\->NEXT::DISTINCT::ACTUAL::method();.Ve.PPor:.PP.Vb 1\& $self\->NEXT::ACTUAL::DISTINCT::method();.Ve.PPto get both unique invocation \fIand\fR exception-on-failure..PPNote that, for historical compatibility, you can also use\&\f(CW\*(C`NEXT::UNSEEN\*(C'\fR instead of \f(CW\*(C`NEXT::DISTINCT\*(C'\fR..Sh "Invoking all versions of a method with a single call".IX Subsection "Invoking all versions of a method with a single call"Yet another pseudo-class that \s-1NEXT\s0.pm provides is \f(CW\*(C`EVERY\*(C'\fR.Its behaviour is considerably simpler than that of the \f(CW\*(C`NEXT\*(C'\fR family.A call to:.PP.Vb 1\& $obj\->EVERY::foo();.Ve.PPcalls \fIevery\fR method named \f(CW\*(C`foo\*(C'\fR that the object in \f(CW$obj\fR has inherited.That is:.PP.Vb 1\& 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 {}, \*(AqA\*(Aq;\& $obj\->EVERY::foo(); # prints" A::foo B::foo X::foo D::foo.Ve.PPPrefixing a method call with \f(CW\*(C`EVERY::\*(C'\fR 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 \*(L"left-most-depth-first\*(R"order. Instead, they are called \*(L"breadth-first-dependency-wise\*(R"..PPThat 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, \f(CW\*(C`X::foo\*(C'\fR is calledbefore \f(CW\*(C`D::foo\*(C'\fR, even though \f(CW\*(C`D\*(C'\fR comes before \f(CW\*(C`X\*(C'\fR in \f(CW@B::ISA\fR..PPIn 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\&\*(L"ancestors\*(R"). In that case, instead of using the \f(CW\*(C`EVERY\*(C'\fR pseudo-class:.PP.Vb 1\& $obj\->EVERY::foo(); # prints" A::foo B::foo X::foo D::foo.Ve.PPyou can use the \f(CW\*(C`EVERY::LAST\*(C'\fR pseudo-class:.PP.Vb 1\& $obj\->EVERY::LAST::foo(); # prints" D::foo X::foo B::foo A::foo.Ve.PPwhich reverses the order of method call..PPWhichever version is used, the actual methods are called in the samecontext (list, scalar, or void) as the original call via \f(CW\*(C`EVERY\*(C'\fR, and return:.IP "\(bu" 4A 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..IP "\(bu" 4A 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..IP "\(bu" 4Nothing in void context (obviously)..ie n .Sh "Using ""EVERY"" methods".el .Sh "Using \f(CWEVERY\fP methods".IX Subsection "Using EVERY methods"The typical way to use an \f(CW\*(C`EVERY\*(C'\fR 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):.PP.Vb 2\& package Base;\& sub DESTROY { $_[0]\->EVERY::Destroy }\&\& package Derived1; \& use base \*(AqBase\*(Aq;\& sub Destroy {...}\&\& package Derived2; \& use base \*(AqBase\*(Aq, \*(AqDerived1\*(Aq;\& sub Destroy {...}.Ve.PPet cetera. Every derived class than needs its own clean-upbehaviour simply adds its own \f(CW\*(C`Destroy\*(C'\fR method (\fInot\fR a \f(CW\*(C`DESTROY\*(C'\fR method),which the call to \f(CW\*(C`EVERY::LAST::Destroy\*(C'\fR in the inherited destructorthen correctly picks up..PPLikewise, to create a class hierarchy in which every initializer inherited bya new object is invoked:.PP.Vb 6\& package Base;\& sub new {\& my ($class, %args) = @_;\& my $obj = bless {}, $class;\& $obj\->EVERY::LAST::Init(\e%args);\& }\&\& package Derived1; \& use base \*(AqBase\*(Aq;\& sub Init {\& my ($argsref) = @_;\& ...\& }\&\& package Derived2; \& use base \*(AqBase\*(Aq, \*(AqDerived1\*(Aq;\& sub Init {\& my ($argsref) = @_;\& ...\& }.Ve.PPet cetera. Every derived class than needs some additional initializationbehaviour simply adds its own \f(CW\*(C`Init\*(C'\fR method (\fInot\fR a \f(CW\*(C`new\*(C'\fR method),which the call to \f(CW\*(C`EVERY::LAST::Init\*(C'\fR in the inherited constructorthen correctly picks up..SH "AUTHOR".IX Header "AUTHOR"Damian Conway (damian@conway.org).SH "BUGS AND IRRITATIONS".IX Header "BUGS AND IRRITATIONS"Because it's a module, not an integral part of the interpreter, \s-1NEXT\s0.pmhas to guess where the surrounding call was found in the methodlook-up sequence. In the presence of diamond inheritance patternsit occasionally guesses wrong..PPIt's also too slow (despite caching)..PPComment, suggestions, and patches welcome..SH "COPYRIGHT".IX Header "COPYRIGHT".Vb 3\& 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..Ve
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -