I'm currently using PHP4 and I'm evaluating PHP5 for its new exciting features.
I have some remarks, split into distinct posts.
The first one is about the current implementation of __clone():
- a derived __clone() can't call parent::__clone() because $that is only declared for the first __clone() call. So a derived __clone() has to include the code of its parent's __clone(). It's not only bad programming, but it can't work when a parent implements private members.
- when a class implements __clone(), all its derived classes have also to implement it to transfer their own members.
There are a several possibilities to get round the first point, but in order to also simplify __clone() implementation, here is a way it could be implemented, close to __construct() implementation:
- the system firstly does a bit for bit copy of the source object,
- then it calls __clone() (which at worst does nothing, if no class implements it),
- __clone() accesses members using $this to handle those (and only those) that need particular actions,
- this is the responsibility of a derived __clone() to call (or not) parent::__clone().
Advantages:
- same behaviour as __construct(), except that $this is already initialized,
- it guaranties that all members will be transfered, by reference for objects, by copy for the others,
- __clone() just needs to be implemented to handle members that need particular actions,
- derived classes do not need to implement __clone() when one of its parents does,
- no more need of $that.
In terms of performance, I don't think this implementation is bad, because a bit for bit copy is certainly faster than an interpreted member-to-member transfer, except if all members have to be handled in a particular way.
I also consider the __clone() implementation not coherent with its calling syntax.
Indeed "$newObj = $obj->__clone();" lets think of an implementation like this:
<?
class Foo {
function __clone() {
$o = new Foo($this->..., $this->...);
$o->...; // eventually
return $o;
}
}
?>
Because __clone() is considered as a copy constructor, it could be implemented in a similar way as for object construction, for example: "$newObj = clone $obj;", "clone" being a language keyword.
Regards,
Stephane
Hello Stephane,
you're right $that must be available in the derived __clone().
Thursday, January 22, 2004, 3:37:11 PM, you wrote:
I'm currently using PHP4 and I'm evaluating PHP5 for its new exciting features.
I have some remarks, split into distinct posts.
The first one is about the current implementation of __clone():
- a derived __clone() can't call parent::__clone() because $that is
only declared for the first __clone() call. So a derived __clone() has to
include the code of its parent's __clone(). It's not only bad programming,
but it can't work when a parent implements private members.- when a class implements __clone(), all its derived classes have also
to implement it to transfer their own members.
There are a several possibilities to get round the first point, but in
order to also simplify __clone() implementation, here is a way it could be
implemented, close to __construct() implementation:
- the system firstly does a bit for bit copy of the source object,
- then it calls __clone() (which at worst does nothing, if no class implements it),
- __clone() accesses members using $this to handle those (and only
those) that need particular actions,- this is the responsibility of a derived __clone() to call (or not) parent::__clone().
Advantages:
- same behaviour as __construct(), except that $this is already initialized,
- it guaranties that all members will be transfered, by reference for objects, by copy for the others,
- __clone() just needs to be implemented to handle members that need particular actions,
- derived classes do not need to implement __clone() when one of its parents does,
- no more need of $that.
In terms of performance, I don't think this implementation is bad,
because a bit for bit copy is certainly faster than an interpreted
member-to-member transfer, except if all members have to be handled in a
particular way.
I also consider the __clone() implementation not coherent with its calling syntax.
Indeed "$newObj = $obj->__clone();" lets think of an implementation like this:
<?
class Foo {
function __clone() {
$o = new Foo($this->..., $this->...);
$o->...; // eventually
return $o;
}
}
?>>
Because __clone() is considered as a copy constructor, it could be
implemented in a similar way as for object construction, for example:
"$newObj = clone $obj;", "clone" being a language keyword.
Regards,
Stephane
--
Best regards,
Marcus mailto:helly@php.net
Stephane,
Andi and I have revisited the __clone() implementation and must agree that
it wasn't quite right (mainly due to it not working with inheritance).
We have rewritten it now (major change!!!) because we didn't want PHP 5 to
be released with a fundamentally flawed mechanism.
Here's our commit message:
Redesign the clone() feature to fix some fundamental flaws in the previous
implementation.
Using clone directly is now done using
$replica = clone $src;
Clone methods must now be declared as follows:
function __clone($that)
{
}
Clone methods in derived classes can call the __clone method of their parent
classes using parent::__clone($that)
Zeev
At 16:37 22/01/2004, Stephane Drouard wrote:
I'm currently using PHP4 and I'm evaluating PHP5 for its new exciting
features.I have some remarks, split into distinct posts.
The first one is about the current implementation of __clone():
- a derived __clone() can't call parent::__clone() because $that is only
declared for the first __clone() call. So a derived __clone() has to
include the code of its parent's __clone(). It's not only bad programming,
but it can't work when a parent implements private members.- when a class implements __clone(), all its derived classes have also to
implement it to transfer their own members.There are a several possibilities to get round the first point, but in
order to also simplify __clone() implementation, here is a way it could be
implemented, close to __construct() implementation:
- the system firstly does a bit for bit copy of the source object,
- then it calls __clone() (which at worst does nothing, if no class
implements it),- __clone() accesses members using $this to handle those (and only those)
that need particular actions,- this is the responsibility of a derived __clone() to call (or not)
parent::__clone().Advantages:
- same behaviour as __construct(), except that $this is already initialized,
- it guaranties that all members will be transfered, by reference for
objects, by copy for the others,- __clone() just needs to be implemented to handle members that need
particular actions,- derived classes do not need to implement __clone() when one of its
parents does,- no more need of $that.
In terms of performance, I don't think this implementation is bad, because
a bit for bit copy is certainly faster than an interpreted
member-to-member transfer, except if all members have to be handled in a
particular way.I also consider the __clone() implementation not coherent with its calling
syntax.
Indeed "$newObj = $obj->__clone();" lets think of an implementation like this:<?
class Foo {
function __clone() {
$o = new Foo($this->..., $this->...);
$o->...; // eventually
return $o;
}
}
?>Because __clone() is considered as a copy constructor, it could be
implemented in a similar way as for object construction, for example:
"$newObj = clone $obj;", "clone" being a language keyword.Regards,
Stephane
Using clone directly is now done using
$replica = clone $src;
Clone methods must now be declared as follows:
function __clone($that)
{
}
Finally! I've suggested this change several times before
(engine2@lists.zend.com) but no one was interested (0 feedback).
But now that it will be included I'm very happy!
--
Ferdinand Beyer
<fb@fbeyer.com
Clone methods must now be declared as follows:
function __clone($that)
{
}
I just had a look at zend_compile.c - it seems as if the variable name
$that was mandantory:
[...]
|| strcmp(CG(active_op_array)->arg_info[0].name, "that")!=0)) {
zend_error(E_COMPILE_ERROR, "The clone method
must be declared as __clone($that)");
[...]
Why shouldn't I be able to name it as I want, e.g. $clone? Don't
understand the reason for that...
--
Ferdinand Beyer
<fb@fbeyer.com