⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perltooc.pod

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 POD
📖 第 1 页 / 共 4 页
字号:
=head1 NAMEperltooc - Tom's OO Tutorial for Class Data in Perl=head1 DESCRIPTIONWhen designing an object class, you are sometimes faced with the situationof wanting common state shared by all objects of that class.Such I<class attributes> act somewhat like global variables for the entireclass, but unlike program-wide globals, class attributes have meaning only tothe class itself.Here are a few examples where class attributes might come in handy:=over 4=item *to keep a count of the objects you've created, or how many arestill extant.=item *to extract the name or file descriptor for a logfile used by a debuggingmethod.=item *to access collective data, like the total amount of cash dispensed byall ATMs in a network in a given day.=item *to access the last object created by a class, or the most accessed object,or to retrieve a list of all objects.=backUnlike a true global, class attributes should not be accessed directly.Instead, their state should be inspected, and perhaps altered, onlythrough the mediated access of I<class methods>.  These class attributesaccessor methods are similar in spirit and function to accessors usedto manipulate the state of instance attributes on an object.  They provide aclear firewall between interface and implementation.You should allow access to class attributes through either the classname or any object of that class.  If we assume that $an_object is oftype Some_Class, and the &Some_Class::population_count method accessesclass attributes, then these two invocations should both be possible,and almost certainly equivalent.    Some_Class->population_count()    $an_object->population_count()The question is, where do you store the state which that method accesses?Unlike more restrictive languages like C++, where these are calledstatic data members, Perl provides no syntactic mechanism to declareclass attributes, any more than it provides a syntactic mechanism todeclare instance attributes.  Perl provides the developer with a broadset of powerful but flexible features that can be uniquely crafted tothe particular demands of the situation.A class in Perl is typically implemented in a module.  A module consistsof two complementary feature sets: a package for interfacing with theoutside world, and a lexical file scope for privacy.  Either of thesetwo mechanisms can be used to implement class attributes.  That means youget to decide whether to put your class attributes in package variablesor to put them in lexical variables.And those aren't the only decisions to make.  If you choose to use packagevariables, you can make your class attribute accessor methods either ignorantof inheritance or sensitive to it.  If you choose lexical variables,you can elect to permit access to them from anywhere in the entire filescope, or you can limit direct data access exclusively to the methodsimplementing those attributes.=head1 Class Data in a CanOne of the easiest ways to solve a hard problem is to let someone elsedo it for you!  In this case, Class::Data::Inheritable (available on aCPAN near you) offers a canned solution to the class data problemusing closures.  So before you wade into this document, considerhaving a look at that module.=head1 Class Data as Package VariablesBecause a class in Perl is really just a package, using package variablesto hold class attributes is the most natural choice.  This makes it simplefor each class to have its own class attributes.  Let's say you have a classcalled Some_Class that needs a couple of different attributes that you'dlike to be global to the entire class.  The simplest thing to do is touse package variables like $Some_Class::CData1 and $Some_Class::CData2to hold these attributes.  But we certainly don't want to encourageoutsiders to touch those data directly, so we provide methodsto mediate access.In the accessor methods below, we'll for now just ignore the firstargument--that part to the left of the arrow on method invocation, which is either a class name or an object reference.    package Some_Class;    sub CData1 {	shift;	# XXX: ignore calling class/object	$Some_Class::CData1 = shift if @_;	return $Some_Class::CData1;    }     sub CData2 {	shift;	# XXX: ignore calling class/object	$Some_Class::CData2 = shift if @_;	return $Some_Class::CData2;    } This technique is highly legible and should be completely straightforwardto even the novice Perl programmer.  By fully qualifying the packagevariables, they stand out clearly when reading the code.  Unfortunately,if you misspell one of these, you've introduced an error that's hardto catch.  It's also somewhat disconcerting to see the class name itselfhard-coded in so many places.Both these problems can be easily fixed.  Just add the C<use strict>pragma, then pre-declare your package variables.  (The C<our> operatorwill be new in 5.6, and will work for package globals just like C<my>works for scoped lexicals.)    package Some_Class;    use strict;    our($CData1, $CData2);   	# our() is new to perl5.6    sub CData1 {	shift;	# XXX: ignore calling class/object	$CData1 = shift if @_;	return $CData1;    }     sub CData2 {	shift;	# XXX: ignore calling class/object	$CData2 = shift if @_;	return $CData2;    } As with any other global variable, some programmers prefer to start theirpackage variables with capital letters.  This helps clarity somewhat, butby no longer fully qualifying the package variables, their significancecan be lost when reading the code.  You can fix this easily enough bychoosing better names than were used here.=head2 Putting All Your Eggs in One BasketJust as the mindless enumeration of accessor methods for instance attributesgrows tedious after the first few (see L<perltoot>), so too does therepetition begin to grate when listing out accessor methods for classdata.  Repetition runs counter to the primary virtue of a programmer:Laziness, here manifesting as that innate urge every programmer feelsto factor out duplicate code whenever possible.Here's what to do.  First, make just one hash to hold all class attributes.    package Some_Class;    use strict;    our %ClassData = (   	# our() is new to perl5.6	CData1 => "",	CData2 => "",    );Using closures (see L<perlref>) and direct access to the package symboltable (see L<perlmod>), now clone an accessor method for each key inthe %ClassData hash.  Each of these methods is used to fetch or storevalues to the specific, named class attribute.    for my $datum (keys %ClassData) {	no strict "refs";	# to register new methods in package	*$datum = sub {	    shift;	# XXX: ignore calling class/object	    $ClassData{$datum} = shift if @_;	    return $ClassData{$datum};	}     } It's true that you could work out a solution employing an &AUTOLOADmethod, but this approach is unlikely to prove satisfactory.  Yourfunction would have to distinguish between class attributes and objectattributes; it could interfere with inheritance; and it would have tocareful about DESTROY.  Such complexity is uncalled for in most cases,and certainly in this one.You may wonder why we're rescinding strict refs for the loop.  We'remanipulating the package's symbol table to introduce new function namesusing symbolic references (indirect naming), which the strict pragmawould otherwise forbid.  Normally, symbolic references are a dodgynotion at best.  This isn't just because they can be used accidentallywhen you aren't meaning to.  It's also because for most usesto which beginning Perl programmers attempt to put symbolic references,we have much better approaches, like nested hashes or hashes of arrays.But there's nothing wrong with using symbolic references to manipulatesomething that is meaningful only from the perspective of the packagesymbol table, like method names or package variables.  In otherwords, when you want to refer to the symbol table, use symbol references.Clustering all the class attributes in one place has several advantages.They're easy to spot, initialize, and change.  The aggregation alsomakes them convenient to access externally, such as from a debuggeror a persistence package.  The only possible problem is that we don'tautomatically know the name of each class's class object, should it haveone.  This issue is addressed below in L<"The Eponymous Meta-Object">.=head2 Inheritance ConcernsSuppose you have an instance of a derived class, and you access classdata using an inherited method call.  Should that end up referringto the base class's attributes, or to those in the derived class?How would it work in the earlier examples?  The derived class inheritsall the base class's methods, including those that access class attributes.But what package are the class attributes stored in?The answer is that, as written, class attributes are stored in the package intowhich those methods were compiled.  When you invoke the &CData1 methodon the name of the derived class or on one of that class's objects, theversion shown above is still run, so you'll access $Some_Class::CData1--orin the method cloning version, C<$Some_Class::ClassData{CData1}>.Think of these class methods as executing in the context of their baseclass, not in that of their derived class.  Sometimes this is exactlywhat you want.  If Feline subclasses Carnivore, then the population ofCarnivores in the world should go up when a new Feline is born.But what if you wanted to figure out how many Felines you have apartfrom Carnivores?  The current approach doesn't support that.You'll have to decide on a case-by-case basis whether it makes any sensefor class attributes to be package-relative.  If you want it to be so,then stop ignoring the first argument to the function.  Either it willbe a package name if the method was invoked directly on a class name,or else it will be an object reference if the method was invoked on anobject reference.  In the latter case, the ref() function provides theclass of that object.    package Some_Class;    sub CData1 {	my $obclass = shift;		my $class   = ref($obclass) || $obclass;	my $varname = $class . "::CData1";	no strict "refs"; 	# to access package data symbolically	$$varname = shift if @_;	return $$varname;    } And then do likewise for all other class attributes (such as CData2,etc.) that you wish to access as package variables in the invoking packageinstead of the compiling package as we had previously.Once again we temporarily disable the strict references ban, becauseotherwise we couldn't use the fully-qualified symbolic name forthe package global.  This is perfectly reasonable: since all packagevariables by definition live in a package, there's nothing wrong withaccessing them via that package's symbol table.  That's what it's therefor (well, somewhat).What about just using a single hash for everything and then cloningmethods?  What would that look like?  The only difference would be theclosure used to produce new method entries for the class's symbol table.    no strict "refs";	    *$datum = sub {	my $obclass = shift;		my $class   = ref($obclass) || $obclass;	my $varname = $class . "::ClassData";	$varname->{$datum} = shift if @_;	return $varname->{$datum};    }=head2 The Eponymous Meta-ObjectIt could be argued that the %ClassData hash in the previous example isneither the most imaginative nor the most intuitive of names.  Is theresomething else that might make more sense, be more useful, or both?As it happens, yes, there is.  For the "class meta-object", we'll usea package variable of the same name as the package itself.  Within thescope of a package Some_Class declaration, we'll use the eponymouslynamed hash %Some_Class as that class's meta-object.  (Using an eponymouslynamed hash is somewhat reminiscent of classes that name their constructorseponymously in the Python or C++ fashion.  That is, class Some_Class woulduse &Some_Class::Some_Class as a constructor, probably even exporting thatname as well.  The StrNum class in Recipe 13.14 in I<The Perl Cookbook>does this, if you're looking for an example.)This predictable approach has many benefits, including having a well-knownidentifier to aid in debugging, transparent persistence,or checkpointing.  It's also the obvious name for monadic classes andtranslucent attributes, discussed later.Here's an example of such a class.  Notice how the name of the hash storing the meta-object is the same as the name of the packageused to implement the class.    package Some_Class;    use strict;    # create class meta-object using that most perfect of names    our %Some_Class = (   	# our() is new to perl5.6	CData1 => "",	CData2 => "",    );    # this accessor is calling-package-relative    sub CData1 {	my $obclass = shift;		my $class   = ref($obclass) || $obclass;	no strict "refs"; 	# to access eponymous meta-object	$class->{CData1} = shift if @_;	return $class->{CData1};    }    # but this accessor is not    sub CData2 {	shift;			# XXX: ignore calling class/object	no strict "refs"; 	# to access eponymous meta-object	__PACKAGE__ -> {CData2} = shift if @_;	return __PACKAGE__ -> {CData2};    } In the second accessor method, the __PACKAGE__ notation was used fortwo reasons.  First, to avoid hardcoding the literal package namein the code in case we later want to change that name.  Second, toclarify to the reader that what matters here is the package currentlybeing compiled into, not the package of the invoking object or class.If the long sequence of non-alphabetic characters bothers you, you canalways put the __PACKAGE__ in a variable first.    sub CData2 {	shift;			# XXX: ignore calling class/object	no strict "refs"; 	# to access eponymous meta-object	my $class = __PACKAGE__;	$class->{CData2} = shift if @_;	return $class->{CData2};    } 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -