What are the reasons for PHP Frameworks to use a Dependency Injection Container for object instantiation?

252 views Asked by At

I am going to focus on Zend Framework, becasue I know it best, but this is certainly applicable to other similar mechanisms found in other PHP Frameworks that use an Inverstion of Control container.

In case of Zend Framework, with a bit of refactoring/manipulation it is entirely possible to not use a container.

Working Example

Looking at the docs, currently Zend Framework is doing something like this with $container (taken from here):

function getServiceConfig()
{
    return [
        'factories' => [
            Model\AlbumTable::class => function ($container)
            {
                $tableGateway = $container->get(Model\AlbumTableGateway::class);
                return new Model\AlbumTable($tableGateway);
            },
            Model\AlbumTableGateway::class => function ($container)
            {
                $dbAdapter = $container->get(AdapterInterface::class);
                $resultSetPrototype = new ResultSet();
                $resultSetPrototype->setArrayObjectPrototype(new Model\Album());
                return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
            }
        ]
    ];
}

//to call
$albumTable = $container->get(Model\AlbumTable::class)

The left side of => contains "keys", which could be any string including a class definition string. The right side is a callback or a FQDN for class name. In the above example it's an anonymous PHP function that acts like a factory to instantiate a new entity, using a DiC $container that's passed to that function via a Framework call.

Why not remove the container and do something like this:

//define
function AlbumTableFactory()
{
    $tableGateway = AlbumTableGatewayFactory();
    return new Model\AlbumTable($tableGateway);
}

function AlbumTableGatewayFactory()
{
    $dbAdapter = AdapterInterface();
    $resultSetPrototype = new ResultSet();
    $resultSetPrototype->setArrayObjectPrototype(new Model\Album());
    return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
}

//to call
$albumTable = AlbumTableFactory();

Above could be converted to classes, if bare functions are bothersome.

In the above I removed the $container and replaced any container use with hardcoded new function calls and since there were no supplied parameters

Since the factories array is part of configuration of the Zend's container, to truly factor it out I'd have to replace any other instances of container calling the Model\AlbumTable::class with a factory call, in order to return the Model\AlbumTable instance. Once it's done I can have a container-less Zend implementation to where I call factories directly instead of calling them through a container with all dependencies explicitly defined.

The question spirit is .. why use a container, what exactly does it provide, and why not just use "real PHP code" with the benefit that no dependencies will be hidden via a container.

0

There are 0 answers