Have fun with PHP: how to bypass an object constructor

Submitted by Frederic Marand on

Some of the features in PHP may be surprising. Think for instance of the way PDO is able to create classed results, place the query results into them, and only then invoke the constructor when using PDO::FETCH_CLASS fetch mode without the additional PDO::FETCH_PROPS_LATE. Every wished you could do this in userland code ? Turns out this has long been possible, and is even simpler since PHP 5.4.

Creating objects without __construct() in PHP 5.0, 5.1, 5.2, 5.3 and later

<?phpclass Foo {  public $property = "Not constructed";  public function __construct() {    $this->property = "Constructed";  }  public function talk() {    echo "I was {$this->property}.\n";  }  public static function frankenstein() {    $rc = new ReflectionClass(__CLASS__);    $properties = $rc->getDefaultProperties();    $prefix = 'O:' . strlen(__CLASS__) . ':"' . __CLASS__ . '":' . count($properties) . ':{';    $suffix = '}';    $hash = array();    foreach ($properties as $name => $value) {      $hash[] = serialize($name) . serialize($value);    }    $serialized = $prefix . implode($hash) . $suffix;    return unserialize($serialized);  }}// Normal instantiation.$x = new Foo();var_dump($x);$x->talk();// Paranormal instantiation.$y = Foo::frankenstein();var_dump($y);$y->talk();$y->__construct();$y->talk();?>

Creating objects without __construct() in PHP 5.4, 5.5 and later

PHP 5.4 introduces a new, much simpler and more reliable way to achieve the same result.

<?phpclass Foo {  public $property = "Not constructed";  public function __construct() {    $this->property = "Constructed";  }  public function talk() {    echo "I was {$this->property}.\n";  }  public static function fronkonstine() {    $rc = new ReflectionClass(__CLASS__);    return $rc->newInstanceWithoutConstructor();  }}// Normal instantiation.$x = new Foo();var_dump($x);$x->talk();// Paranormal instantiation.$y = Foo::fronkonstine();var_dump($y);$y->talk();echo "But now...\n";$y->__construct();$y->talk();?>

Bypassing __construct() in real life ?

Just because these mechanisms have been available for a long time does not mean they are good for general use. Nonetheless, there is a very much used package using this technique: PHPUnit, which was the inspiration for this story. You can find code like it in PHPUnit_Framework_MockObject_Generator::getObject(), where it is used to create mocks bypassing the original constructor:

<?phpclass PHPUnit_Framework_MockObject_Generator/* ... */    protected static function getObject($code, $className, $originalClassName = '', $callOriginalConstructor = FALSE, $callAutoload = FALSE, array $arguments = array())    {     /* ... */            // Use a trick to create a new object of a class            // without invoking its constructor.            $object = unserialize(              sprintf('O:%d:"%s":0:{}', strlen($className), $className)            );    /* ... */    }?>

Invoking __construct after construction

The most disturbing in all of this might well be the last two lines in each example:

<?php$y->__construct();$y->talk();?>

As these examples show, it is indeed possible to invoke the constructor after the actual object creation, just like any other method. Which completes the ability to create / set properties and only then invoke the constructor, just like PDO in non-late-props mode. Can you think of meaningful use cases for it all, beyond building test doubles (mocks) ? If so, by all means comment on this article !

Rajapriya (not verified)

Mon, 2017-07-03 12:06

Interesting article to read.. After reading this article i got clear information about php constructors which helpful to make a constructors program easily..