Dependency injection in PHP (slim, php-di)

2.1k views Asked by At

I have a Slim Php (slim4) application to which I added Monolog for logging purposes. I'm adding the logger to the application like this:

$containerBuilder->addDefinitions([
  LoggerInterface::class => function (ContainerInterface $c) {
     $logger = new Logger('appname');
     ...
     return $logger

This works fine for injecting the logger in most of my classes, by just doing:

public function __construct(ContainerInterface $container = null, LoggerInterface $logger)
{
    // I can use $logger here

Now I'd also like to use the logger in the middleware like authentication. I don't see how I can properly do this. I can get this working by adding the logger as a named entry in the container like this:

$containerBuilder->addDefinitions([
  "LoggerInterface" => function (ContainerInterface $c) {

and then passing it to the middleware as a constructor parameter by getting it back from the container:

$middlewares[] = new MyAuthentication(..., $container->get('LoggerInterface'));

But this:

  • a) breaks the injection by classname for the other classes
  • b) is apparently not a best practice

So what is the correct way to get this logger injected in the middleware?

3

There are 3 answers

1
Woodrow On BEST ANSWER

Without adding the LoggerInterface as a named entry to the container, could you just inject the LoggerInterface class directly to your middleware via $container->get()? I.E. in a routes.php App function:

$container = $app->getContainer();
$app->add(new MiddleWare\MyAuthentication(..., $container->get(LoggerInterface::class)));
2
Alex Barker On

In short, I do not think you are going to be able to auto-wire the dependencies for the middleware as they need to be constructed before being appended to the router. You would need to explicitly inject the dependency as suggested by @Woodrow, although I would opt for method injection instead of constructor injection for the LoggerInterface as it would adhere to the LoggerAwareInterface.

0
odan On

You could let the dependency injection container (PHP-DI) resolve and inject all dependencies into your middleware:

LoggerInterface::class => function (ContainerInterface $container) {
    return new Logger('name');
},

Then just register the middleware with the class name:

$app->add(\MiddleWare\MyAuthentication::class);

(You should not inject the container itself into the middleware)

That's all.