in PHP, is there is there a way to differentiate when magic method is called through a PHP construct or directly?
E.g.: public function __clone() {}
is called each time an object is cloned through the clone
keyword:
$a = new ObjectA();
$clone = clone $a; // Calls __clone()
However, someone can even (do not know why someone should do that, but, anyway) call __clone()
directly:
$a = new ObjectA();
$clone = $a->__clone(); // Call __clone() directly
Same goes for other PHP magic methods (__call()
, __debugInfo
, etc.).
Can we differentiate between the two cases somehow?
Thank you for the attention!
EDIT: Assume the following scenario:
I have a dynamic proxy class, which extends a base class and internally creates an instance of the base class only when the object is effectively used:
class A {
...
public function __clone() {
echo "clone A!!!";
}
...
}
class DynamicProxy extends A {
protected $a = NULL;
public function __clone() {
$this->createA();
if ( /* __clone() is triggered by `clone $obj`, I need to clone $a: */ ) {
clone $this->a;
}
else {
// But if someone, for some reason (I do not now why, but it could be, and I would like to be consistent), have called `$obj->__clone();`, I do not have to call `clone $obj`, but proxy the call:
return $this->a->__clone();
}
}
protected function createA() {
if (is_null($this->a)) {
$this->a = new A();
}
}
}
$obj = new DynamicProxy();
Many of your assumptions are incorrect, one can not call __clone()
directly and get a clone of the object to be returned because the docs says:
void __clone ( void )
and
An object's __clone() method cannot be called directly.
It is a bit misleading because it can actually be called, but the result is like calling any other object's method, and will not make a clone of the original object.
Consider this snippet:
<?php
class Foo {
function __construct($x) {
$this->x = $x;
}
function __clone() {
echo "I'm a clone";
}
function getX() {
echo $this->x;
}
}
$a = new Foo('foo');
$b = $a->__clone(); # > I'm a clone
var_dump($b); # > NULL
$b->getX(); # Exception: Call to a member function getX() on null
?>
__clone
method is called on newly created, clone object after it has been cloned. It's more like a callback and it does not produce a clone.
Maybe it would be better if PHP threw an exception when someone tried to call __clone
directly, but there are many things PHP could do better.
What you can do is to deeply test if what you think is possible is really possible.