Pragmatism in the real world

Dependency Injection in Slim 4

In contrast with Slim 2 and Slim 3, Slim 4 does not ship with a DI container, but instead, supports any PSR-11 compatibly DI container that you provide. This is part of Slim 4’s commitment to interoperability via the PHP-FIG standards.

The easiest way to add a container to your Slim application is to call AppFactory::setContainer() before you call AppFactory::create(). The setContainer() method expects any PSR-11 container.

Register the container with Slim

Let’s look at how it works using PHP-DI as our container which can be installed using composer require php-di/php-di.

To configure PHP-DI, we use the ContainerBuilder() to configure what we want and then create the container itself using build():

use DI\ContainerBuilder;
use Slim\Factory\AppFactory;

$containerBuilder = new ContainerBuilder();
// configure PHP-DI here

AppFactory::setContainer($containerBuilder->build());
$app = AppFactory::create();

Configuring PHP-DI

PHP-DI is relatively easy to configure using the builder’s addDefiniton() method. For example, to add settings to the container for use with other factories, we can do:

    $containerBuilder->addDefinitions([
        'settings' => [
            'displayErrorDetails' => true, // Should be set to false in production
            'logger' => [
                'name' => 'my-app',
                'path' => 'php://stderr',
                'level' => Logger::DEBUG,
            ],
        ],
    ]);

PHP-DI can automatically instantiate any class that has either has no dependencies or has dependencies that it can resolve. Resolvable dependencies are type-hinted constructor parameters to either an interface name or a concrete class name – where interface names are preferable.

For example, consider this handler:

use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;

class HomePageHandler implements RequestHandlerInterface
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    // class continues...

As HomePageHandler has one dependency, $logger, PHP-DI can create an instance of this class as long as it can find a way to instantiate a LoggerInterface. As this is not a concrete class, we need to tell PHP-DI how to create it by writing a factory or providing a map to a concrete class.

A factory that instantiates an instance of Monolog (which implements PSR-3‘s LoggerInterface) is:

use Psr\Container\ContainerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;

$containerBuilder->addDefinitions([
    LoggerInterface::class => function (ContainerInterface $c) {
        $settings = $c->get('settings')['logger'];

        $logger = new Logger($settings['name']);
        $handler = new StreamHandler($settings['path'], $settings['level']);
        $logger->pushHandler($handler);

        return $logger;
    },
]);

This factory is a closure that looks up the settings that we registered in the container and then instantiates a Logger and configures it. As with all DI factories, it then returns the instance of the object.

Registering your handler

In order for Slim to use the DI container to instantiate your handler which will then instantiate its dependencies, you must register the class as a string. For a PSR-15 handler, this is most easily done using ::class:

$app->get('/', HomePageHandler::class);

That’s all that’s needed. When resolving the class name, Slim will ask the container if it can instantiate an instance of HomePageHandler. PHP-DI will say “yes” and then instantiate it, having first instantiated the Monolog instance.

That’s it

Slim 4 has built-in support for any PSR-11 DI container, but doesn’t require one. However, I recommend that you use one such as PHP-DI as Dependency Injection coupled with coding to interfaces makes for a much more maintainable application.

5 thoughts on “Dependency Injection in Slim 4

  1. Where do I put this code? Do I just put this on settings.php?

    "`
    use DI\ContainerBuilder;
    use Slim\Factory\AppFactory;

    $containerBuilder = new ContainerBuilder();
    // configure PHP-DI here

    AppFactory::setContainer($containerBuilder->build());
    $app = AppFactory::create();
    "`

  2. I just have problem with these code as to I don't know where to put them but they are very well explained.

Comments are closed.