In the section dealing with inheritance, he mentions that if a
subclass is defined, the superclass constructor will not necessarily
be run and one has to include special code in the constructor for the
subclass to run the constructor in the superclass.
He also mentions that the constructor could be either a method with
the same name as the class (deprecated) or a method named __construct.
Since it might not be obvious, how would one write a subclass and make
sure to invoke the constructor without actually inspecting the code of
the superclass to see what form of constructor was used? And even if
one does, and the superclass gets rewritten, then it might break the
subclass.
Am I over-thinking this and there is a simple answer to this?
Thanks.
Really simple.
Subclass constructor.-
function __construct()
{
parent::__construct();
/* whatever code you want to add */
}
I understand that, but deprecated code might have the parent class
constructor as follows:
class userClass
{
function userClass()
{
// constructor code
}
}
Now if I use the code you showed, sill it still invoke the parent
constructor, even though it is named userClass?
No idea about that case. Try it and see what happens... if it is the
case, then use the proper name.
Anyway as it is deprecated you should patch that code and use a
__construct function.
Well, like any other library, you don't know what's available in a class
unless you inspect it. And once a class is finished, it should be "cast
in concrete" - that is, no changes to the interface (private and
protected member declarations), other than additions. Such changes can
have unknown effects on other code, not just derived classes.
True not only in PHP, but any OO language. But more of a problem in PHP
because of the occasional changes in the language which are incompatible
with previous versions.
--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstu...@attglobal.net
==================
You don't need to worry about it. parent::__construct() will call the
php4 style constructor if it exists (and the php5 style magic method
does not).
eg:
class Foo {
public $state = "foo";
function Foo() {
$this->state = "bar";
}
}
class Bar extends Foo {
function __construct() {
parent::__construct();
}
}
$b = new Bar();
echo $b->state; // "bar";
I'm afraid it's not that simple:
<?php
class Foo{
public $name;
public function __construct($name){
$this->name = $name;
}
}
class Bar extends Foo{
public $age;
public function __construct($age){
parent::__construct();
$this->age = $age;
}
}
$b = new Bar(33); // Warning: Missing argument 1 for Foo::__construct()
?>
As far as I know, you cannot extend a class and disregard its signature.
You need to know what it constructor looks like and if the base class
changes, child classes are subject to breaking.
--
-- http://alvaro.es - Álvaro G. Vicario - Burgos, Spain
-- Mi sitio sobre programación web: http://borrame.com
-- Mi web de humor satinado: http://www.demogracia.com
--
> I'm afraid it's not that simple:
>
> <?php
>
> class Foo{
> public $name;
>
> public function __construct($name){
> $this->name = $name;
> }
> }
>
> class Bar extends Foo{
> public $age;
>
> public function __construct($age){
> parent::__construct();
> $this->age = $age;
> }
> }
>
> $b = new Bar(33); // Warning: Missing argument 1 for Foo::__construct()
>
> ?>
>
> As far as I know, you cannot extend a class and disregard its signature.
> You need to know what it constructor looks like...
Of course you need to know. If you want to extend a class, you need to
know it's API. This includes "protected" IMO in case of inheriting. If
you want to use a class, you also must know it's API.
> and if the base class
> changes, child classes are subject to breaking.
Yes, of course. And if a class changes it's API, all depending client
classes will break. And that's the cause, why you shouldn't/must not
change the API of a class in a way that breaks client code ("Client"
means here "Code, that uses this class").
The above is true for both, if you use a class in your code or if you
extend it. There's no difference, because the extending class is also a
kind of client of the base class.
I can't see the problem here, because IMO this is OOP basics.
>
> > As far as I know, you cannot extend a class and disregard its signature.
> > You need to know what it constructor looks like...
>
> Of course you need to know. If you want to extend a class, you need to
> know it's API. This includes "protected" IMO in case of inheriting. If
> you want to use a class, you also must know it's API.
>
> > and if the base class
> > changes, child classes are subject to breaking.
>
> Yes, of course. And if a class changes it's API, all depending client
> classes will break. And that's the cause, why you shouldn't/must not
> change the API of a class in a way that breaks client code ("Client"
> means here "Code, that uses this class").
>
> The above is true for both, if you use a class in your code or if you
> extend it. There's no difference, because the extending class is also a
> kind of client of the base class.
>
> I can't see the problem here, because IMO this is OOP basics.
OK, if someone wouldn't mind explaining to me, since I'm only learning
this stuff.
My understanding of OOP is that I have classes and that only th eAPI
is exposed to users of those classes. It is possible to extend the
classes with subclasses and inherit the methods of the parent class.
But the internals of the class is "hidden" from the callers, allowing
one to rewrite the methods (if the API is preserved) to improve the
class, for instance.
Also, I didn't realize that the class constructor is part of the API.
Since PHP changed the way the constructor is defined, would that not
mean that over time one would rewrite all classes to implement the new
__construct method in favor of the old classname constructor? So by
doing this one might break all subclasses? Wow.
So if one has an old class that may be implemented in many pieces of
code, one should *never* attempt to refactor the constructor of that
class?
Since the old method of class constructors is now deprecated, should
one expect that in the fullness of time, that method will go away and
then code will be broken and one cannot fix it unless one can track
down all subclasses of the code?
True.
> Also, I didn't realize that the class constructor is part of the API.
> Since PHP changed the way the constructor is defined, would that not
> mean that over time one would rewrite all classes to implement the new
> __construct method in favor of the old classname constructor? So by
> doing this one might break all subclasses? Wow.
>
Anything public or protected is part of the interface. Only private
members (data and functions) and the actual code in your functions is
considered internal.
> So if one has an old class that may be implemented in many pieces of
> code, one should *never* attempt to refactor the constructor of that
> class?
>
Not necessarily. But you have to be very careful when doing it.
> Since the old method of class constructors is now deprecated, should
> one expect that in the fullness of time, that method will go away and
> then code will be broken and one cannot fix it unless one can track
> down all subclasses of the code?
Yes, I expect eventually the old class name constructor will be deleted.
But by that time you probably should have rewritten the code anyway,
for other reasons - like to take advantage of other, newer features of PHP.
Of course, you can also just add a redirector, i.e.
class MyClass {
public MyClass() {
... construction code here ...
}
public __construct() {
this->MyClass();
>Since the old method of class constructors is now deprecated, should
>one expect that in the fullness of time, that method will go away and
Yes. When a feature becomes deprecated, it shouldn't be used anymore and
code relying on it should be rewritten. While it will be still around
for a while, but disabled by default, in some coming version it will be
completely removed.
The old constructor naming scheme is a relic from PHP 4. For backwards
compatibility it still works in PHP 5, but I wouldn't expect it to still
work in PHP 6.
So it's about time to fix any code that still uses this feature. The
same is true for even more ugly things like register_globals and magic
quotes for example - these "features" will be definitely removed from
PHP 6.
>then code will be broken and one cannot fix it unless one can track
>down all subclasses of the code?
You're responsible for your own code and should keep it up-to-date.
Deprecated features should be removed and those parts of the code be
rewritten. If this breaks any other code, which uses your classes, but
is not under your control, it's that third party programmer's task to
fix it, not yours.
Micha
x2, these are very good suggestions, MikeB.
Yep; old style constructors are already gone for namespaced classes, and
that's only going to extend to other classes as things go forward.
> So it's about time to fix any code that still uses this feature. The
> same is true for even more ugly things like register_globals and magic
> quotes for example - these "features" will be definitely removed from
> PHP 6.
To confirm, they've already been removed from trunk.
Adam
It becomes clear when you use the PHP/5 syntax:
public function __construct(){...}
^^^^^^
> Since PHP changed the way the constructor is defined, would that not
> mean that over time one would rewrite all classes to implement the new
> __construct method in favor of the old classname constructor? So by
> doing this one might break all subclasses? Wow.
In this case, the syntax does not matter. What matters is what
parameters it expects:
<?php
class Foo{
var $name;
function Foo($name){
$this->name = $name;
}
}
class Bar extends Foo{
public $age;
public function __construct($age){
parent::__construct('Anonymous');
$this->age = $age;
}
}
$b = new Bar(33);
echo $b->name; // Prints "Anonymous"
?>
The opposite case, however, would be different:
<?php
class Foo{
public $name;
public function __construct($name){
$this->name = $name;
}
}
class Bar extends Foo{
var $age;
function Bar($age){
parent::Foo('Anonymous'); // Fatal error: Call to undefined method
Foo::Foo()
$this->age = $age;
}
}
$b = new Bar(33);
echo $b->name;
?>
> So if one has an old class that may be implemented in many pieces of
> code, one should *never* attempt to refactor the constructor of that
> class?
>
> Since the old method of class constructors is now deprecated, should
> one expect that in the fullness of time, that method will go away and
> then code will be broken and one cannot fix it unless one can track
> down all subclasses of the code?
Basically, that's it. You normally have several years to port code:
deprecated functions do not disappear that quickly. The problem comes
when you don't care about it and you're suddently forced to run your
legacy code in a newer PHP version (for instance, because the old server
died).
> My understanding of OOP is that I have classes and that only th eAPI
> is exposed to users of those classes.
Yes, that's true. But, as I already wrote: protected methods/members are
IMO a part of the API for inheriting classes, because they are
accessible by them.
> But the internals of the class is "hidden" from the callers,...
Yes, but think an extending class also as a caller/user of the parent class.
> allowing
> one to rewrite the methods (if the API is preserved) to improve the
> class, for instance.
"Extending" is IMO better word than "improving". The API can be
extended. But it also must be preserved. More abstract: The rules say:
If you have a class "Vehicle" and a class "Car", that extends "Vehicle"
(for example in adding a method that returns the number of doors of the
car, which would extend the API). Whenever an instance of a "Vehicle" is
required, you can also use an instance of "Car". But if you use an
instance of "Car" as "Vehicle", you can/should only use the API of the
"Vehicle" class.
> Also, I didn't realize that the class constructor is part of the API.
It depends. You can also write classes with a private constructor. Then
the constructor is not part of the API. And only the class itself can
create instances of it. It must have a static method, that creates the
instance and returns it, otherwise it would be useless ;). And there's a
special exception to this also: You can also write a class only with
static methods or constants and a private constructor. That would make
the whole class static: you can never have an instance of it.
But if the constructor is public, it is part of the API: It defines for
users, how to create instances of it.
> Since PHP changed the way the constructor is defined, would that not
> mean that over time one would rewrite all classes to implement the new
> __construct method in favor of the old classname constructor? So by
> doing this one might break all subclasses? Wow.
[...]
> So if one has an old class that may be implemented in many pieces of
> code, one should *never* attempt to refactor the constructor of that
> class?
Yes and no. One must have in mind the consequences of every refactoring.
And then he has to decide, whether to do it or not. If this class is
only part of your own code, you might do a refactoring, but you must of
course also refactor the parts of the code, that use this class.
If it's part of a library, you can also refactor the constructors. But
then you should publish those changes as a new version, and inform users
of the backward-incompatibilities. Users can then decide whether to
refactor their code or stick to the old version.
> Since the old method of class constructors is now deprecated, should
> one expect that in the fullness of time, that method will go away and
> then code will be broken and one cannot fix it unless one can track
> down all subclasses of the code?
Also yes and no. The code will be broken for new versions of a PHP
interpreter. So if you want to run on a new PHP version, it might be
necessary to do the refactoring. But if you stick to the old version of
the interpreter, there's no need to change anything. And sometimes, the
disadvantages of an "upgrade" might weight more than the benefits.
Helmut