Latest sites

Quick news

  • 2014-03-27: MongoDB Watchdog module ported to Drupal 8 at the Szeged Dev Days.
  • 2014-01-26: My post on the Symfony web profiler in Silex selected in Week of Symfony. w00t !
  • 2013-10-18: My first commit went into MongoDB today. And, guess what ? It's in JavaScript
  • 2013-09-20 to 29: Working on Drupal 8 EntityAPI at the extended code sprints during and around DrupalCon Prague
  • 2012-08-19: Working on Drupal 8 EntityAPI at Drupalcon Munich
  • 2012-06-15: Working on Drupal 8 EntityAPI at DrupalDevDays Barcelona
  • 2012-03-23: Working on the future Drupal Document Oriented Storage at DrupalCon Denver. D8 or later ? Bets are on Later

Have fun with PHP: how to bypass an object constructor

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

<?php
class 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.

<?php
class 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:

<?php
class 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 !