1
\$\begingroup\$

I am currently working on a small framework and one of its main components is a dependency injection container I made. I am not a professional dev and I would like someone more experienced than I am to review this class.

The class itself is pretty easy to use and documented:

<?php

class Container
{

    protected $parameters = array();
    protected $services   = array();

    /**
     * Sets a parameter.
     * 
     * @param   string  $index  The parameter's index.
     * @param   mixed   $value  The parameter.
     * 
     * @return  $this
     */
    public function set($index, $value)
    {
        $this->parameters[$index] = $value;
        return $this;
    }

    /**
     * Returns a parameter.
     * 
     * @param   string  $index  The parameter's index.
     * 
     * @return  mixed           The parameter.
     */
    public function get($index)
    {
        if (!isset($this->parameters[$index]))
            throw new \OutOfBoundsException("Parameter '$index' isn't set.");

        return $this->parameters[$index];
    }

    /**
     * Registers a new service.
     * 
     * @param   string                  $index      The service's index.
     * @param   object|array|string     $service    The service as a closure or an array, or it's class name.
     * 
     * @return  $this
     */
    public function register($index, $service)
    {
        // If it's a string, we need to make the service a valid array.
        if (is_string($service)) {
            if (!class_exists($service))
                throw new \InvalidArgumentException("Cannot register service '$index', class '$service' doesn't exist.");

            $service = array(
                            'class'  => $service,
                            'shared' => true,
                            'args'   => array()
                        );
        }

        if (is_array($service)) {
            if (!isset($service['class'])) {
                throw new \InvalidArgumentException("Cannot register service '$index', index 'class' missing.");
            } elseif (!class_exists($service['class'])) {
                throw new \InvalidArgumentException("Cannot register service '$index', class '" . $service['class'] . "' doesn't exist.");
            }
        }

        $this->services[$index] = $service;
        return $this;
    }


    public function &__get($name)
    {
        if (!isset($this->services[$name]))
            throw new \OutOfBoundsException("Cannot get unregistered service '$name'.");

        return $this->services[$name];
    }

    public function __call($method, $args)
    {       
        if (!isset($this->services[$method]))
            throw new \OutOfBoundsException("Cannot call unregistered service '$method'.");

        $service = &$this->services[$method];

        // If our service is a closure.
        if (is_object($service))
            return $service($this);

        // If a service instance already exists, then return it.
        if (isset($service['instance']))
            return $service['instance'];

        // Fixing the arguments in case they're not set.
        $args = $service['args'] ?: array();

        $reflection = new \ReflectionClass($service['class']);
        $instance   = $reflection->newInstanceArgs($service['args']);

        // Store the instance if it's shared.
        if ($service['shared'])
            $service['instance'] = $instance;

        return $instance;
    }

}

And here is an exemple of how it's used:

<?php

class Dependecy
{
    private $_text;

    public function __contstruct($text)
    {
        $this->_text = $text;
    }

    public function SayIt()
    {
        echo $this->_text;
    }
}

class Dependent extends Container
{

    public function __construct()
    {
        $this->register('dependency', 'Dependency');
    }

    public function DependencySayIt($text)
    {
        $this->dependency['args'][] = $text;
        $this->dependency()->SayIt();
    }

}

$dependent = new Dependent;
$dependent->DependencySayIt('Hello world!');

?>

What do you think of the Container class? Is there any feature that I should add, anything I should change? I have fully understood what a DIC should do?

\$\endgroup\$
  • \$\begingroup\$ I can't comment on the overall design of the class (no experience with DI), but what would confuse me as a user of your class would be if I try to retrieve a non-existing service and get a OutOfBoundsException back. In this case, for me, "out of bounds" is an implementation problem, not a user problem. I'd change it to a more generic Exception or even write your own NoSuchServiceException. \$\endgroup\$ – S22h Jan 14 '16 at 10:36
  • \$\begingroup\$ Thank you for your answer! I will change this so it make for a less confusing code for the user. Thanks! \$\endgroup\$ – TheKitsuneWithATie Jan 18 '16 at 19:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.