Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass Dependency Injection Container to static method

Tags:

php

symfony

I have some Legacy classes. Many classes are instantiated using a Factory Class.

There is also a Singleton-Class.

In the future I want to replace them completely with the DIC. For the moment the codebase is to large to do this.

Now my goal is to inject the DI-Container into every Service instantiated by the Singleton class. The Singleton class has a static method with this signature.

final class Singleton
{
  private static $singletonCache = array();

  public static function getInstance($namespace, $className)
  {
  }
}

inside of this function I want to check for:

$instance = new $className();

if($instance instanceof ContainerAwareInterface)
{
  // TODO: how do we get the container here
  $instance->setContainer($container);
}

But how can I best get the container inside of my "singleton class", which is only called statically?

like image 845
Patrick Avatar asked Jan 05 '16 14:01

Patrick


3 Answers

Another approach is to access the container globally when you need it:

public static function getInstance($namespace, $className)
{
  $container = $_GLOBAL['kernel']->getContainer();
}

Of course there are sorts of things wrong with this approach but as long as you are transitioning then it's enough to get by.

like image 160
Cerad Avatar answered Oct 04 '22 20:10

Cerad


Somewhere early in your bootstrapping code, but after the container is instantiated, you can pass the container to your singleton class:

Singleton::setContainer($container);

It would store the container in a static property:

final class Singleton
{
    // ...

    private static $container;

    public static function setContainer(ContainerInterface $container)
    {
        self::$container = $container;
    }
}

However, as you learned on the example of your singleton class, all global state gives you is headaches. Passing the container around (and using ContainerAware) is something to avoid. By passing the container to your services you're making them rely on the whole world of services. It's cleaner to only pass collaborator you actually need. It's also far easier to test.

like image 23
Jakub Zalas Avatar answered Oct 04 '22 20:10

Jakub Zalas


Another solution is presented in this answer, which is pretty much the same as the other answer to this question, just using the global keyword instead of the $_GLOBAL array to access the kernel object.

public static function getInstance($namespace, $className)
{
  global $kernel;
  $container = $kernel->getContainer();
}
like image 21
Cave Johnson Avatar answered Oct 04 '22 22:10

Cave Johnson