ConstructorInjector [PHP5.1.3+]

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

ConstructorInjector [PHP5.1.3+]

Post by Jenk »

After the discussions in T+D I came up with this:

Code: Select all

class ConstructorInjector
{
    public static $instance;
    private $_components;
    
    private function __construct()
    {
        $this->components = array();
    }
    
    public static function getInstance()
    {
        if (!(self::$instance instanceof self)) self::$instance = new self;
        
        return self::$instance;
    }
    
    public function addComponent($class)
    {
        if (!class_exists($class))
        {
            throw new InvalidArgumentException('Class ' . $class . ' has not been defined.');
        }
        else
        {
            $this->_components[$class] = array();
            $object = new ReflectionClass($class);
            $params = $object->getConstructor()->getParameters();

            foreach ($params as $param)
            {
                if ($var = $param->getClass())
                {
                    $this->_components[$class][] = $var->getName();
                }
            }
        }
    }
    
    public function instantiateObject($class)
    {
        if (!isset($this->_components[$class]))
        {
            try
            {
                $this->addComponent($class);
            }
            catch (Exception $e)
            {
                throw $e;
            }
        }
        
        $args = array();
        foreach ($this->_components[$class] as $comp)
        {
            $args[] = $this->instantiateObject($comp);
        }
        
        $reflect = new ReflectionClass($class);
        return $reflect->newInstanceArgs($args);
    }
}
Tis not perfect, hence it being in here (or perhaps should be T+D?). :)

First thing on my TODO is add a check for the dependency being an instance or class, and for __constructor() because if any of the dependencies don't have one, the injector dies :P

I didn't create a full unit-test for this, however it's pretty easy to see the test I did:

Code: Select all

<?php

include 'ConstructorInjector.php';

class Bar {}

class Foo
    public $bar;

    public constructor(Bar $bar)
    {
        $this->bar = $bar;
    }
}

$in = ConstructorInjector::getInstance();

$foo = $in->instantiateObject('Foo');

echo get_class($foo->bar); // outputs 'Bar'

?>
Anywho.. time for sleep at last.

N.B. 5.1.3+ because of the use of ReflectionClass::newInstanceArgs()
Post Reply