📄 perlboot.pod
字号:
=head1 NAMEperlboot - Beginner's Object-Oriented Tutorial=head1 DESCRIPTIONIf you're not familiar with objects from other languages, some of theother Perl object documentation may be a little daunting, such asL<perlobj>, a basic reference in using objects, and L<perltoot>, whichintroduces readers to the peculiarities of Perl's object system in atutorial way.So, let's take a different approach, presuming no prior objectexperience. It helps if you know about subroutines (L<perlsub>),references (L<perlref> et. seq.), and packages (L<perlmod>), so becomefamiliar with those first if you haven't already.=head2 If we could talk to the animals...Let's let the animals talk for a moment: sub Cow::speak { print "a Cow goes moooo!\n"; } sub Horse::speak { print "a Horse goes neigh!\n"; } sub Sheep::speak { print "a Sheep goes baaaah!\n"; } Cow::speak; Horse::speak; Sheep::speak;This results in: a Cow goes moooo! a Horse goes neigh! a Sheep goes baaaah!Nothing spectacular here. Simple subroutines, albeit from separatepackages, and called using the full package name. So let's createan entire pasture: # Cow::speak, Horse::speak, Sheep::speak as before @pasture = qw(Cow Cow Horse Sheep Sheep); foreach $animal (@pasture) { &{$animal."::speak"}; }This results in: a Cow goes moooo! a Cow goes moooo! a Horse goes neigh! a Sheep goes baaaah! a Sheep goes baaaah!Wow. That symbolic coderef de-referencing there is pretty nasty.We're counting on C<no strict subs> mode, certainly not recommendedfor larger programs. And why was that necessary? Because the name ofthe package seems to be inseparable from the name of the subroutine wewant to invoke within that package.Or is it?=head2 Introducing the method invocation arrowFor now, let's say that C<< Class->method >> invokes subroutineC<method> in package C<Class>. (Here, "Class" is used in its"category" meaning, not its "scholastic" meaning.) That's notcompletely accurate, but we'll do this one step at a time. Now let'suse it like so: # Cow::speak, Horse::speak, Sheep::speak as before Cow->speak; Horse->speak; Sheep->speak;And once again, this results in: a Cow goes moooo! a Horse goes neigh! a Sheep goes baaaah!That's not fun yet. Same number of characters, all constant, novariables. But yet, the parts are separable now. Watch: $a = "Cow"; $a->speak; # invokes Cow->speakAhh! Now that the package name has been parted from the subroutinename, we can use a variable package name. And this time, we've gotsomething that works even when C<use strict refs> is enabled.=head2 Invoking a barnyardLet's take that new arrow invocation and put it back in the barnyardexample: sub Cow::speak { print "a Cow goes moooo!\n"; } sub Horse::speak { print "a Horse goes neigh!\n"; } sub Sheep::speak { print "a Sheep goes baaaah!\n"; } @pasture = qw(Cow Cow Horse Sheep Sheep); foreach $animal (@pasture) { $animal->speak; }There! Now we have the animals all talking, and safely at that,without the use of symbolic coderefs.But look at all that common code. Each of the C<speak> routines has asimilar structure: a C<print> operator and a string that containscommon text, except for two of the words. It'd be nice if we couldfactor out the commonality, in case we decide later to change it allto C<says> instead of C<goes>.And we actually have a way of doing that without much fuss, but wehave to hear a bit more about what the method invocation arrow isactually doing for us.=head2 The extra parameter of method invocationThe invocation of: Class->method(@args)attempts to invoke subroutine C<Class::method> as: Class::method("Class", @args);(If the subroutine can't be found, "inheritance" kicks in, but we'llget to that later.) This means that we get the class name as thefirst parameter (the only parameter, if no arguments are given). Sowe can rewrite the C<Sheep> speaking subroutine as: sub Sheep::speak { my $class = shift; print "a $class goes baaaah!\n"; }And the other two animals come out similarly: sub Cow::speak { my $class = shift; print "a $class goes moooo!\n"; } sub Horse::speak { my $class = shift; print "a $class goes neigh!\n"; }In each case, C<$class> will get the value appropriate for thatsubroutine. But once again, we have a lot of similar structure. Canwe factor that out even further? Yes, by calling another method inthe same class.=head2 Calling a second method to simplify thingsLet's call out from C<speak> to a helper method called C<sound>.This method provides the constant text for the sound itself. { package Cow; sub sound { "moooo" } sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } }Now, when we call C<< Cow->speak >>, we get a C<$class> of C<Cow> inC<speak>. This in turn selects the C<< Cow->sound >> method, whichreturns C<moooo>. But how different would this be for the C<Horse>? { package Horse; sub sound { "neigh" } sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } }Only the name of the package and the specific sound change. So can wesomehow share the definition for C<speak> between the Cow and theHorse? Yes, with inheritance!=head2 Inheriting the windpipesWe'll define a common subroutine package called C<Animal>, with thedefinition for C<speak>: { package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } }Then, for each animal, we say it "inherits" from C<Animal>, alongwith the animal-specific sound: { package Cow; @ISA = qw(Animal); sub sound { "moooo" } }Note the added C<@ISA> array. We'll get to that in a minute.But what happens when we invoke C<< Cow->speak >> now?First, Perl constructs the argument list. In this case, it's justC<Cow>. Then Perl looks for C<Cow::speak>. But that's not there, soPerl checks for the inheritance array C<@Cow::ISA>. It's there,and contains the single name C<Animal>.Perl next checks for C<speak> inside C<Animal> instead, as inC<Animal::speak>. And that's found, so Perl invokes that subroutinewith the already frozen argument list.Inside the C<Animal::speak> subroutine, C<$class> becomes C<Cow> (thefirst argument). So when we get to the step of invokingC<< $class->sound >>, it'll be looking for C<< Cow->sound >>, whichgets it on the first try without looking at C<@ISA>. Success!=head2 A few notes about @ISAThis magical C<@ISA> variable (pronounced "is a" not "ice-uh"), hasdeclared that C<Cow> "is a" C<Animal>. Note that it's an array,not a simple single value, because on rare occasions, it makes senseto have more than one parent class searched for the missing methods.If C<Animal> also had an C<@ISA>, then we'd check there too. Thesearch is recursive, depth-first, left-to-right in each C<@ISA> bydefault (see L<mro> for alternatives). Typically, each C<@ISA> hasonly one element (multiple elements means multiple inheritance andmultiple headaches), so we get a nice tree of inheritance.When we turn on C<use strict>, we'll get complaints on C<@ISA>, sinceit's not a variable containing an explicit package name, nor is it alexical ("my") variable. We can't make it a lexical variable though(it has to belong to the package to be found by the inheritance mechanism),so there's a couple of straightforward ways to handle that.The easiest is to just spell the package name out: @Cow::ISA = qw(Animal);Or allow it as an implicitly named package variable: package Cow; use vars qw(@ISA); @ISA = qw(Animal);If you're bringing in the class from outside, via an object-orientedmodule, you change: package Cow; use Animal; use vars qw(@ISA); @ISA = qw(Animal);into just: package Cow; use base qw(Animal);And that's pretty darn compact.=head2 Overriding the methodsLet's add a mouse, which can barely be heard: # Animal package from before { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; print "[but you can barely hear it!]\n"; } } Mouse->speak;which results in: a Mouse goes squeak! [but you can barely hear it!]Here, C<Mouse> has its own speaking routine, so C<< Mouse->speak >>doesn't immediately invoke C<< Animal->speak >>. This is known as"overriding". In fact, we didn't even need to say that a C<Mouse> wasan C<Animal> at all, since all of the methods needed for C<speak> arecompletely defined with C<Mouse>.But we've now duplicated some of the code from C<< Animal->speak >>,and this can once again be a maintenance headache. So, can we avoidthat? Can we say somehow that a C<Mouse> does everything any otherC<Animal> does, but add in the extra comment? Sure!First, we can invoke the C<Animal::speak> method directly: # Animal package from before { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; Animal::speak($class); print "[but you can barely hear it!]\n"; } }Note that we have to include the C<$class> parameter (almost surelythe value of C<"Mouse">) as the first parameter to C<Animal::speak>,since we've stopped using the method arrow. Why did we stop? Well,if we invoke C<< Animal->speak >> there, the first parameter to themethod will be C<"Animal"> not C<"Mouse">, and when time comes for itto call for the C<sound>, it won't have the right class to come backto this package.Invoking C<Animal::speak> directly is a mess, however. What ifC<Animal::speak> didn't exist before, and was being inherited from aclass mentioned in C<@Animal::ISA>? Because we are no longer usingthe method arrow, we get one and only one chance to hit the rightsubroutine.Also note that the C<Animal> classname is now hardwired into thesubroutine selection. This is a mess if someone maintains the code,changing C<@ISA> for C<Mouse> and didn't notice C<Animal> there inC<speak>. So, this is probably not the right way to go.=head2 Starting the search from a different placeA better solution is to tell Perl to search from a higher placein the inheritance chain: # same Animal as before { package Mouse; # same @ISA, &sound as before sub speak { my $class = shift; $class->Animal::speak; print "[but you can barely hear it!]\n"; } }Ahh. This works. Using this syntax, we start with C<Animal> to findC<speak>, and use all of C<Animal>'s inheritance chain if not foundimmediately. And yet the first parameter will be C<$class>, so thefound C<speak> method will get C<Mouse> as its first entry, andeventually work its way back to C<Mouse::sound> for the details.But this isn't the best solution. We still have to keep the C<@ISA>and the initial search package coordinated. Worse, if C<Mouse> hadmultiple entries in C<@ISA>, we wouldn't necessarily know which onehad actually defined C<speak>. So, is there an even better way?=head2 The SUPER way of doing thingsBy changing the C<Animal> class to the C<SUPER> class in thatinvocation, we get a search of all of our super classes (classeslisted in C<@ISA>) automatically: # same Animal as before { package Mouse; # same @ISA, &sound as before sub speak { my $class = shift; $class->SUPER::speak; print "[but you can barely hear it!]\n"; } }So, C<SUPER::speak> means look in the current package's C<@ISA> forC<speak>, invoking the first one found. Note that it does I<not> look inthe C<@ISA> of C<$class>.=head2 Where we're at so far...So far, we've seen the method arrow syntax: Class->method(@args);or the equivalent: $a = "Class"; $a->method(@args);which constructs an argument list of: ("Class", @args)and attempts to invoke Class::method("Class", @Args);However, if C<Class::method> is not found, then C<@Class::ISA> is examined(recursively) to locate a package that does indeed contain C<method>,and that subroutine is invoked instead.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -