Skip to content

Instantly share code, notes, and snippets.

@webmozart
Created October 25, 2010 15:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save webmozart/645111 to your computer and use it in GitHub Desktop.
Save webmozart/645111 to your computer and use it in GitHub Desktop.
Benchmark to compare runtime Configurable with annotation-based OptionSupport behaviour
<?php
abstract class Configurable
{
private $options = array();
private $knownOptions = array();
private $requiredOptions = array();
public function __construct(array $options = array())
{
$this->options = array_merge($this->options, $options);
$this->configure();
// check option names
if ($diff = array_diff_key($this->options, $this->knownOptions)) {
throw new InvalidOptionsException(sprintf('%s does not support the following options: "%s".', get_class($this), implode('", "', array_keys($diff))), array_keys($diff));
}
// check required options
if ($diff = array_diff_key($this->requiredOptions, $this->options)) {
throw new MissingOptionsException(sprintf('%s requires the following options: \'%s\'.', get_class($this), implode('", "', array_keys($diff))), array_keys($diff));
}
}
protected function configure()
{
}
protected function addOption($name, $value = null)
{
$this->knownOptions[$name] = true;
if (!array_key_exists($name, $this->options)) {
$this->options[$name] = $value;
}
}
protected function addRequiredOption($name)
{
$this->knownOptions[$name] = true;
$this->requiredOptions[$name] = true;
}
}
class OptionSupport
{
protected static $definitions = array();
public static function initialize($object, array $options)
{
$class = get_class($object);
$definition = self::getDefinition($class);
// check option names
if ($diff = array_diff_key($options, $definition[0])) {
throw new InvalidOptionsException(sprintf('%s does not support the following options: "%s".', get_class($this), implode('", "', array_keys($diff))), array_keys($diff));
}
// check required options
if ($diff = array_diff_key($definition[1], $options)) {
throw new MissingOptionsException(sprintf('%s requires the following options: \'%s\'.', get_class($this), implode('", "', array_keys($diff))), array_keys($diff));
}
foreach ($options as $property => $value) {
$definition[0][$property]->setValue($object, $value);
}
}
protected static function getDefinition($class)
{
$className = $class instanceof \ReflectionClass ? $class->getName() : $class;
if (isset(self::$definitions[$className])) {
return self::$definitions[$className];
}
if (!$class instanceof \ReflectionClass) {
$class = new \ReflectionClass($class);
}
$parentClass = $class->getParentClass();
$definition = $parentClass ? self::getDefinition($parentClass) : array(
array(), // known options
array(), // required options
);
foreach ($class->getProperties() as $property) {
if (strpos($property->getDocComment(), '@option') !== false) {
$definition[0][$property->getName()] = $property;
if (!$property->isDefault()) {
$definition[1][$property->getName()] = true;
}
$property->setAccessible(true);
}
}
self::$definitions[$className] = $definition;
return $definition;
}
}
class A_Configurable extends Configurable
{
public function __construct(array $options = array())
{
parent::__construct($options);
}
protected function configure()
{
$this->addOption('a', 1);
$this->addOption('b', 2);
$this->addRequiredOption('c');
$this->addRequiredOption('d');
}
}
class B_Configurable extends A_Configurable
{
protected function configure()
{
parent::configure();
$this->addOption('e', 3);
$this->addRequiredOption('f');
}
}
class C_Configurable extends B_Configurable
{
protected function configure()
{
parent::configure();
$this->addOption('g', 4);
$this->addRequiredOption('h');
}
}
class A_OptionSupport
{
/** @option */
protected $a = 1;
/** @option */
protected $b = 2;
/** @option */
protected $c;
/** @option */
protected $d;
public function __construct(array $options)
{
OptionSupport::initialize($this, $options);
}
}
class B_OptionSupport extends A_OptionSupport
{
/** @option */
protected $e = 3;
/** @option */
protected $f;
}
class C_OptionSupport extends B_OptionSupport
{
/** @option */
protected $g = 4;
/** @option */
protected $h;
}
define('COUNT', 3);
// benchmark Configurable
echo "\nConfigurable\n";
echo "------------\n";
$start1 = microtime(true);
new C_Configurable(array(
'c' => 1,
'd' => 1,
'f' => 1,
'h' => 1,
));
echo 'Object 1: ' . (microtime(true) - $start1) . "ms\n";
$start2 = microtime(true);
for ($i = 0; $i < (COUNT - 1); ++$i) {
new C_Configurable(array(
'c' => 1,
'd' => 1,
'f' => 1,
'h' => 1,
));
}
echo 'Object 2-' . COUNT . ': ' . (microtime(true) - $start2) . "ms\n";
echo 'Total: ' . (microtime(true) - $start1) . "ms\n";
// benchmark OptionSupport
echo "\nOptionSupport\n";
echo "-------------\n";
$start1 = microtime(true);
new C_OptionSupport(array(
'c' => 1,
'd' => 1,
'f' => 1,
'h' => 1,
));
echo 'Object 1: ' . (microtime(true) - $start1) . "ms\n";
$start2 = microtime(true);
for ($i = 0; $i < (COUNT - 1); ++$i) {
new C_OptionSupport(array(
'c' => 1,
'd' => 1,
'f' => 1,
'h' => 1,
));
}
echo 'Object 2-' . COUNT . ': ' . (microtime(true) - $start2) . "ms\n";
echo 'Total: ' . (microtime(true) - $start1) . "ms\n";
@webmozart
Copy link
Author

My results for 3 objects:

Configurable
------------
Object 1: 0.000177145004272ms
Object 2-3: 0.000209093093872ms
Total: 0.000420093536377ms

OptionSupport
-------------
Object 1: 0.000524044036865ms
Object 2-3: 0.000108957290649ms
Total: 0.000654935836792ms

And for 10 objects:

Configurable
------------
Object 1: 0.000163078308105ms
Object 2-10: 0.000825881958008ms
Total: 0.00102305412292ms

OptionSupport
-------------
Object 1: 0.000497102737427ms
Object 2-10: 0.000417947769165ms
Total: 0.000935077667236ms

The conclusion:

If we use a decent cache, OptionSupport is always faster than Configurable (except for the first time when the cache is filled). If we use an in-memory array cache only, OptionSupport is faster once we create 10 or more objects of the same class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment