Closed pprkut closed 9 years ago
Here's an easier testcase:
<?
class C {
public function to_be_mocked()
{
return 1;
}
}
class A
{
private $test = 1; //private var
public function to_be_mocked()
{
//this method is executed in the context of B, so the properties are looked up there
var_dump($this->test);
return 1;
}
}
class B extends C
{
public function foo()
{
return 1 + $this->to_be_mocked();
}
}
runkit_class_emancipate('B');
runkit_class_adopt('B', "A");
$o = new B();
$o->foo();
?>
The problem is that there is a property 'cache' - properties_table for each zend_object. This table is created and filled using the default class properties (and parent class properties) when the object initialized. In this case the initial parent (class C) doesn't have any properties, so the table is empty. The "adopted" parent does have a property, hence PHP expects to find it in the object that should have inherited it. To fix this particular case it's enough to update B class default properties when adopting it, but there is a more complex version of the reproduce case, when the object is created before changing the classes:
$o = new B();
runkit_class_emancipate('B');
runkit_class_adopt('B', "A");
In this case updating B won't be enough since the object is already initialized at the time of the change, so all the object of class B have to be updated too to reflect these changes.
runkit_class_adopt doesn't add anything except ancestral methods to the adopted class (see http://php.net/manual/en/function.runkit-class-adopt.php). Trying to access nonexisting properties leads to segmentation fault.
I'm trying the use runkit to replace the parent class of the class with a Mock version of it, which could make phpunit tests a bit simpler. Unfortunately I get a segfault when I try to execute the code. I put together a small testcase:
running this using "phpunit testcase.php" gives:
Tested with php 5.5.7, phpunit 3.7.28 and runkit master.