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

📄 perltoot.1

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 1
📖 第 1 页 / 共 5 页
字号:
\&    }\&\&    sub age {\&        my $self = shift;\&        if (@_) { $self\->{AGE} = shift }\&        return $self\->{AGE};\&    }\&\&    sub peers {\&        my $self = shift;\&        if (@_) { @{ $self\->{PEERS} } = @_ }\&        return @{ $self\->{PEERS} };\&    }\&\&    1;  # so the require or use succeeds.Ve.PPWe've created three methods to access an object's data, \fIname()\fR, \fIage()\fR,and \fIpeers()\fR.  These are all substantially similar.  If called with anargument, they set the appropriate field; otherwise they return thevalue held by that field, meaning the value of that hash key..Sh "Planning for the Future: Better Constructors".IX Subsection "Planning for the Future: Better Constructors"Even though at this point you may not even know what it means, somedayyou're going to worry about inheritance.  (You can safely ignore thisfor now and worry about it later if you'd like.)  To ensure that thisall works out smoothly, you must use the double-argument form of \fIbless()\fR.The second argument is the class into which the referent will be blessed.By not assuming our own class as the default second argument and insteadusing the class passed into us, we make our constructor inheritable..PP.Vb 9\&    sub new {\&        my $class = shift;\&        my $self  = {};\&        $self\->{NAME}   = undef;\&        $self\->{AGE}    = undef;\&        $self\->{PEERS}  = [];\&        bless ($self, $class);\&        return $self;\&    }.Ve.PPThat's about all there is for constructors.  These methods bring objectsto life, returning neat little opaque bundles to the user to be used insubsequent method calls..Sh "Destructors".IX Subsection "Destructors"Every story has a beginning and an end.  The beginning of the object'sstory is its constructor, explicitly called when the object comes intoexistence.  But the ending of its story is the \fIdestructor\fR, a methodimplicitly called when an object leaves this life.  Any per-objectclean-up code is placed in the destructor, which must (in Perl) be called\&\s-1DESTROY\s0..PPIf constructors can have arbitrary names, then why not destructors?Because while a constructor is explicitly called, a destructor is not.Destruction happens automatically via Perl's garbage collection (\s-1GC\s0)system, which is a quick but somewhat lazy reference-based \s-1GC\s0 system.To know what to call, Perl insists that the destructor be named \s-1DESTROY\s0.Perl's notion of the right time to call a destructor is not well-definedcurrently, which is why your destructors should not rely on when they arecalled..PPWhy is \s-1DESTROY\s0 in all caps?  Perl on occasion uses purely uppercasefunction names as a convention to indicate that the function willbe automatically called by Perl in some way.  Others that are calledimplicitly include \s-1BEGIN\s0, \s-1END\s0, \s-1AUTOLOAD\s0, plus all methods used bytied objects, described in perltie..PPIn really good object-oriented programming languages, the user doesn'tcare when the destructor is called.  It just happens when it's supposedto.  In low-level languages without any \s-1GC\s0 at all, there's no way todepend on this happening at the right time, so the programmer mustexplicitly call the destructor to clean up memory and state, crossingtheir fingers that it's the right time to do so.   Unlike \*(C+, anobject destructor is nearly never needed in Perl, and even when it is,explicit invocation is uncalled for.  In the case of our Person class,we don't need a destructor because Perl takes care of simple matterslike memory deallocation..PPThe only situation where Perl's reference-based \s-1GC\s0 won't work iswhen there's a circularity in the data structure, such as:.PP.Vb 1\&    $this\->{WHATEVER} = $this;.Ve.PPIn that case, you must delete the self-reference manually if you expectyour program not to leak memory.  While admittedly error-prone, this isthe best we can do right now.  Nonetheless, rest assured that when yourprogram is finished, its objects' destructors are all duly called.So you are guaranteed that an object \fIeventually\fR gets properlydestroyed, except in the unique case of a program that never exits.(If you're running Perl embedded in another application, this full \s-1GC\s0pass happens a bit more frequently\*(--whenever a thread shuts down.).Sh "Other Object Methods".IX Subsection "Other Object Methods"The methods we've talked about so far have either been constructors orelse simple \*(L"data methods\*(R", interfaces to data stored in the object.These are a bit like an object's data members in the \*(C+ world, exceptthat strangers don't access them as data.  Instead, they should onlyaccess the object's data indirectly via its methods.  This is animportant rule: in Perl, access to an object's data should \fIonly\fRbe made through methods..PPPerl doesn't impose restrictions on who gets to use which methods.The public-versus-private distinction is by convention, not syntax.(Well, unless you use the Alias module described below in\&\*(L"Data Members as Variables\*(R".)  Occasionally you'll see method names beginning or endingwith an underscore or two.  This marking is a convention indicatingthat the methods are private to that class alone and sometimes to itsclosest acquaintances, its immediate subclasses.  But this distinctionis not enforced by Perl itself.  It's up to the programmer to behave..PPThere's no reason to limit methods to those that simply access data.Methods can do anything at all.  The key point is that they're invokedagainst an object or a class.  Let's say we'd like object methods thatdo more than fetch or set one particular field..PP.Vb 5\&    sub exclaim {\&        my $self = shift;\&        return sprintf "Hi, I\*(Aqm %s, age %d, working with %s",\&            $self\->{NAME}, $self\->{AGE}, join(", ", @{$self\->{PEERS}});\&    }.Ve.PPOr maybe even one like this:.PP.Vb 4\&    sub happy_birthday {\&        my $self = shift;\&        return ++$self\->{AGE};\&    }.Ve.PPSome might argue that one should go at these this way:.PP.Vb 5\&    sub exclaim {\&        my $self = shift;\&        return sprintf "Hi, I\*(Aqm %s, age %d, working with %s",\&            $self\->name, $self\->age, join(", ", $self\->peers);\&    }\&\&    sub happy_birthday {\&        my $self = shift;\&        return $self\->age( $self\->age() + 1 );\&    }.Ve.PPBut since these methods are all executing in the class itself, thismay not be critical.  There are tradeoffs to be made.  Using directhash access is faster (about an order of magnitude faster, in fact), andit's more convenient when you want to interpolate in strings.  But usingmethods (the external interface) internally shields not just the users ofyour class but even you yourself from changes in your data representation..SH "Class Data".IX Header "Class Data"What about \*(L"class data\*(R", data items common to each object in a class?What would you want that for?  Well, in your Person class, you mightlike to keep track of the total people alive.  How do you implement that?.PPYou \fIcould\fR make it a global variable called \f(CW$Person::Census\fR.  But aboutonly reason you'd do that would be if you \fIwanted\fR people to be able toget at your class data directly.  They could just say \f(CW$Person::Census\fRand play around with it.  Maybe this is ok in your design scheme.You might even conceivably want to make it an exported variable.  To beexportable, a variable must be a (package) global.  If this were atraditional module rather than an object-oriented one, you might do that..PPWhile this approach is expected in most traditional modules, it'sgenerally considered rather poor form in most object modules.  In anobject module, you should set up a protective veil to separate interfacefrom implementation.  So provide a class method to access class datajust as you provide object methods to access object data..PPSo, you \fIcould\fR still keep \f(CW$Census\fR as a package global and rely uponothers to honor the contract of the module and therefore not play aroundwith its implementation.  You could even be supertricky and make \f(CW$Census\fR atied object as described in perltie, thereby intercepting all accesses..PPBut more often than not, you just want to make your class data afile-scoped lexical.  To do so, simply put this at the top of the file:.PP.Vb 1\&    my $Census = 0;.Ve.PPEven though the scope of a \fImy()\fR normally expires when the block in whichit was declared is done (in this case the whole file being required orused), Perl's deep binding of lexical variables guarantees that thevariable will not be deallocated, remaining accessible to functionsdeclared within that scope.  This doesn't work with global variablesgiven temporary values via \fIlocal()\fR, though..PPIrrespective of whether you leave \f(CW$Census\fR a package global or makeit instead a file-scoped lexical, you should make thesechanges to your \fIPerson::new()\fR constructor:.PP.Vb 10\&    sub new {\&        my $class = shift;\&        my $self  = {};\&        $Census++;\&        $self\->{NAME}   = undef;\&        $self\->{AGE}    = undef;\&        $self\->{PEERS}  = [];\&        bless ($self, $class);\&        return $self;\&    }\&\&    sub population {\&        return $Census;\&    }.Ve.PPNow that we've done this, we certainly do need a destructor so thatwhen Person is destroyed, the \f(CW$Census\fR goes down.  Here's howthis could be done:.PP.Vb 1\&    sub DESTROY { \-\-$Census }.Ve.PPNotice how there's no memory to deallocate in the destructor?  That'ssomething that Perl takes care of for you all by itself..PPAlternatively, you could use the Class::Data::Inheritable module from\&\s-1CPAN\s0..Sh "Accessing Class Data".IX Subsection "Accessing Class Data"It turns out that this is not really a good way to go about handlingclass data.  A good scalable rule is that \fIyou must never reference classdata directly from an object method\fR.  Otherwise you aren't building ascalable, inheritable class.  The object must be the rendezvous pointfor all operations, especially from an object method.  The globals(class data) would in some sense be in the \*(L"wrong\*(R" package in yourderived classes.  In Perl, methods execute in the context of the classthey were defined in, \fInot\fR that of the object that triggered them.Therefore, namespace visibility of package globals in methods is unrelatedto inheritance..PPGot that?  Maybe not.  Ok, let's say that some other class \*(L"borrowed\*(R"(well, inherited) the \s-1DESTROY\s0 method as it was defined above.  When thoseobjects are destroyed, the original \f(CW$Census\fR variable will be altered,not the one in the new class's package namespace.  Perhaps this is whatyou want, but probably it isn't..PPHere's how to fix this.  We'll store a reference to the data in thevalue accessed by the hash key \*(L"_CENSUS\*(R".  Why the underscore?  Well,mostly because an initial underscore already conveys strong feelingsof magicalness to a C programmer.  It's really just a mnemonic deviceto remind ourselves that this field is special and not to be used asa public data member in the same way that \s-1NAME\s0, \s-1AGE\s0, and \s-1PEERS\s0 are.(Because we've been developing this code under the strict pragma, priorto perl version 5.004 we'll have to quote the field name.).PP.Vb 12\&    sub new {\&        my $class = shift;\&        my $self  = {};\&        $self\->{NAME}     = undef;\&        $self\->{AGE}      = undef;\&        $self\->{PEERS}    = [];\&        # "private" data\&        $self\->{"_CENSUS"} = \e$Census;\&        bless ($self, $class);\&        ++ ${ $self\->{"_CENSUS"} };\&        return $self;\&    }\&\&    sub population {\&        my $self = shift;\&        if (ref $self) {\&            return ${ $self\->{"_CENSUS"} };\&        } else {\&            return $Census;\&        }\&    }\&\&    sub DESTROY {\&        my $self = shift;\&        \-\- ${ $self\->{"_CENSUS"} };\&    }.Ve.Sh "Debugging Methods".IX Subsection "Debugging Methods"It's common for a class to have a debugging mechanism.  For example,you might want to see when objects are created or destroyed.  To do that,add a debugging variable as a file-scoped lexical.  For this, we'll pullin the standard Carp module to emit our warnings and fatal messages.That way messages will come out with the caller's filename andline number instead of our own; if we wanted them to be from our ownperspective, we'd just use \fIdie()\fR and \fIwarn()\fR directly instead of \fIcroak()\fRand \fIcarp()\fR respectively..PP.Vb 2\&    use Carp;\&    my $Debugging = 0;.Ve.PPNow add a new class method to access the variable..PP.Vb 6\&    sub debug {\&        my $class = shift;\&        if (ref $class)  { confess "Class method called as object method" }\&        unless (@_ == 1) { confess "usage: CLASSNAME\->debug(level)" }\&        $Debugging = shift;\&    }.Ve.PPNow fix up \s-1DESTROY\s0 to murmur a bit as the moribund object expires:.PP.Vb 5\&    sub DESTROY {\&        my $self = shift;\&        if ($Debugging) { carp "Destroying $self " . $self\->name }\&        \-\- ${ $self\->{"_CENSUS"} };\&    }.Ve.PPOne could conceivably make a per-object debug state.  Thatway you could call both of these:.PP.Vb 2\&    Person\->debug(1);   # entire class\&    $him\->debug(1);     # just this object.Ve.PPTo do so, we need our debugging method to be a \*(L"bimodal\*(R" one, one thatworks on both classes \fIand\fR objects.  Therefore, adjust the \fIdebug()\fRand \s-1DESTROY\s0 methods as follows:

⌨️ 快捷键说明

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