PHP-DI Dependency Injection Container

website·Indexed 35 days ago

http://php-di.org/doc/

A dependency injection container for PHP. The documentation covers core concepts like scopes, lazy injection, and annotations, as well as integration with frameworks such as Slim, Silex, and Zend Framework 2. It includes migration guides for versions 4.0, 6.0, and 7.0, and details on the compiled container introduced in PHP-DI 6 for maximum performance.

Tokens
25.5K
Snippets
158
Records
207
Agent score
71%

What's inside PHP-DI

  1. Use autowiring to automatically inject dependencies

    Autowiring allows the PHP-DI container to automatically create and inject dependencies by using PHP's reflection to detect the required parameters of a constructor. If a constructor parameter is type-hinted with a class, PHP-DI will automatically instantiate that class (if not already created) and pass it to the constructor without requiring manual configuration.
    class UserRepository
    {
        // ...
    }
    
    class UserRegistrationService
    {
        public function __construct(UserRepository $repository)
        {
            // ...
        }
    }
    // PHP-DI automatically resolves UserRegistrationService by injecting UserRepository
  2. Understand the difference between Dependency Injection and DI Containers

    Dependency Injection (DI) is a coding method used to write better, decoupled code by inverting the control of dependencies. A DI Container (like PHP-DI) is a tool that automates the process of creating and injecting those dependencies, removing the manual work of instantiating objects and passing them into constructors.
  3. Understand the PHP-DI global architecture

    PHP-DI is centered around the Container class, which is typically instantiated via a ContainerBuilder helper. The container acts as the coordinator that returns entries based on a provided entry name. To resolve an entry, the container utilizes two primary sub-components:

    1. DefinitionSource: Locates the Definition associated with a specific entry name.
    2. DefinitionResolver: A list of resolvers that take a Definition and resolve it into a final value (e.g., instantiating an object).
    $entry = $container->get('entryName');
  4. Optimize autowired classes for container compilation

    PHP-DI cannot compile definitions for autowired classes that are not explicitly listed in the configuration. To maximize performance, list these classes in your definition files using autowire(). This allows PHP-DI to know about the classes and compile their definitions, even if you don't need to provide specific configuration for them.
    return [
        // ... (your definitions)
    
        UserController::class => autowire(),
        BlogController::class => autowire(),
        ProductController::class => autowire(),
    ];
  5. General rules for using PHP-DI and dependency injection

    To maintain a decoupled and maintainable architecture, follow these core principles:

    1. Never retrieve entries from the container directly; always use dependency injection.
    2. Write code that is decoupled from the container.
    3. Type-hint against interfaces and configure the specific implementation to use within the container configuration.
  6. Define dependencies in PHP-DI

    PHP-DI provides three primary methods to specify what should be injected and where: autowiring, PHP attributes, and PHP configuration files. These methods can be used individually or in combination.
  7. Run PHP-DI tests using PHPUnit

    PHP-DI uses PHPUnit to execute its test suite. Run the following command from the project root to verify the build.
    $ phpunit
  8. Retrieve the requested entry name in a factory

    When a single factory is used to create multiple services (e.g., when using wildcards in definitions), you can determine which specific entry is being constructed by type-hinting the DI\Factory\RequestedEntry object in the closure parameters. Use the getName() method on the RequestedEntry object to retrieve the name of the entry.
    return [
        'Acme\Repository\*Repository' => function(EntityManager $entityManager, RequestedEntry $e) {
            $class = $e->getName();
            return new $class($entityManager);
        },
    ];
  9. Install and initialize PHP-DI bridge for Slim

    To use PHP-DI with Slim 3, install the php-di/slim-bridge package and replace the standard Slim\App instantiation with DI\Bridge\Slim\App. This allows the application to use PHP-DI as its dependency injection container.
    composer require php-di/slim-bridge
    <?php
    require 'vendor/autoload.php';
    
    // Use the PHP-DI bridge App instead of Slim\App
    $app = new \DI\Bridge\Slim\App;
    
    $app->run();
  10. Configure complex dependencies using factories in PHP-DI 4

    For complex dependency setups—such as those requiring multiple method calls, property injections, or logic that is too verbose for the fluent API—use the factory() helper. This allows you to write standard PHP code within a closure to instantiate and configure your objects.
    use function DI\factory;
    
    return [
        ArticleRepositoryInterface::class => factory(function (Container $c) {
            $dependency = new PrivateSubDependency(PrivateSubDependency::MY_CONSTANT);
    
            $repository = new ArticleRepository($c->get(EntityManager::class), $dependency, 'some.param');
            $repository->setFoo($c->get(Foo::class));
            $repository->setBar($c->get(Bar::class));
            $repository->configureStuff('localhost', 8080);
            $repository->logger = $c->get(LoggerInterface::class);
    
            return $repository;
        }),
    ];
  11. Inject dependencies into an existing object instance using injectOn

    When an object is created outside of the PHP-DI container (e.g., by a third-party framework or manually), you can use the injectOn() method to resolve its dependencies. This method performs setter injection and property injection on the provided instance.

    Note that injectOn() cannot perform constructor injection because the object has already been instantiated. If the object requires constructor dependencies, you must provide them manually during instantiation before calling injectOn().

    // Case 1: Object created manually with constructor dependencies
    $object = new MyClass($someDependency, $someOtherDependency);
    $container->injectOn($object);
    
    // Case 2: Object created by a framework/library
    $container->injectOn($object);