note 50246 added to language.oop5.decon
| From: | caliban at darklock dot com | Date: | Tue, 22 Feb 2005 22:00:19 +0000 |
| Subject: | note 50246 added to language.oop5.decon | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-85392@lists.php.net to get a copy of this message | ||
(Referring to the earlier example code and comment)
The "final" keyword forbids the Baz object to define its own constructor; defining an
override for a "final" method creates a fatal error. Without the "final"
keyword, if the Baz object defines a constructor, the Foo constructor will not be called
automatically; instead, the Baz constructor will be called and the Foo constructor will not.
If the Foo constructor SHOULD be called, e.g. to open files or initialise member variables, Baz will
need to call parent::__construct() explicitly. In most cases, this is what you will want to do when
extending a class, but you can't just do it as a matter of habit... because if Foo does not
HAVE a constructor, parent::__construct() is a fatal error. This creates a problem. (The problem can
be easily solved with @parent::__construct(), if you don't care about OTHER errors that might
arise.)
So given an object Foo with no constructor, any extension objects MUST NOT call
parent::__construct() in their own constructors. If Foo later *adds* a constructor, the extension
objects SHOULD call parent::__construct() if they have constructors themselves. (If they don't,
Foo's constructor will be called automatically.) A whole slew of problems pop up as a result,
so what we need is a way to say "call the parent class constructor if there is one".
An immediate avenue presents itself with
is_callable(array("parent","__construct")), but this isn't as useful as you
might expect because it doesn't handle old-style constructors. Basically, if Foo has a
constructor named Foo(), parent::__construct() will call parent::Foo(), but
is_callable(array("parent","__construct")) returns FALSE.
Fortunately, this is easily resolved with a call to
is_callable(array("parent",get_parent_class($this))). Adding that bit of code into the
constructor of your derived classes will achieve exactly what we want, namely to call the
parent's constructor if there is one.
But there always seems to be a catch... this only works one level down. If Baz extends Bar extends
Foo, this code will get Baz to call Bar's constructor, but Bar can't call Foo's
constructor with it -- because $this is an instance of Baz, not Bar, so Bar cannot determine its
parent class name correctly. (It is noteworthy that if Bar does not *have* a constructor, Baz will
still happily pass a request through to Foo's constructor.) The reflection interface is the
most obvious way to go about fixing this, but that gets a little too complex to be called a
"note".
----
Manual Page -- http://www.php.net/manual/en/language.oop5.decon.php
Edit -- http://master.php.net/manage/user-notes.php?action=edit+50246
Delete: added to the manual -- http://master.php.net/manage/user-notes.php?action=delete+50246&report=yes&reason=added+to+the+manual
Delete: bad code -- http://master.php.net/manage/user-notes.php?action=delete+50246&report=yes&reason=bad+code
Delete: spam -- http://master.php.net/manage/user-notes.php?action=delete+50246&report=yes&reason=spam
Delete: useless -- http://master.php.net/manage/user-notes.php?action=delete+50246&report=yes&reason=useless
Delete: other reasons -- http://master.php.net/manage/user-notes.php?action=delete+50246&report=yes
Reject -- http://master.php.net/manage/user-notes.php?action=reject+50246&report=yes
Search -- http://master.php.net/manage/user-notes.php