PHP - Create Dependency Injection Container PSR-11 like PHP-DI (DI)
Tags: php, codequality, tutorial, laravel
Published: 2021-01-23 17:08:22

# PHP Dependency Injection Container PSR-11


Install the standard interfaces for Container.:

```
composer require psr/container
```

Let's create the class that will implement the containerInterface

```php
<?php

namespace DevCoder\DependencyInjection;

use DevCoder\DependencyInjection\Exception\NotFoundException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;

class Container implements ContainerInterface
{
    /**
     * @var array
     */
    private $definitions = [];

    /**
     * @var array
     */
    private $resolvedEntries = [];

    public function __construct(array $definitions)
    {
        $this->definitions = array_merge(
            $definitions,
            [ContainerInterface::class => $this]
        );
    }

    /**
     * Finds an entry of the container by its identifier and returns it.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return mixed Entry.
     * @throws ContainerExceptionInterface Error while retrieving the entry.
     *
     * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.
     */
    public function get($id)
    {
        if (!$this->has($id)) {
            throw new NotFoundException("No entry or class found for '$id'");
        }

        if (array_key_exists($id, $this->resolvedEntries)) {
            return $this->resolvedEntries[$id];
        }

        $value = $this->definitions[$id];
        if ($value instanceof \Closure) {
            $value = $value($this);
        }

        $this->resolvedEntries[$id] = $value;
        return $value;
    }

    /**
     * Returns true if the container can return an entry for the given identifier.
     * Returns false otherwise.
     *
     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return bool
     */
    public function has($id)
    {
        return array_key_exists($id, $this->definitions) || array_key_exists($id, $this->resolvedEntries);
    }
}

```
Let's create the class that will implement the NotFoundExceptionInterface
```php
<?php

namespace DevCoder\DependencyInjection\Exception;

use Psr\Container\NotFoundExceptionInterface;

/**
 * Class NotFoundException
 * @package DevCoder\DependencyInjection\Exception
 */
class NotFoundException extends \InvalidArgumentException implements NotFoundExceptionInterface
{
}

```
**How to use ?**

``` php
// services.php
<?php

use Psr\Container\ContainerInterface;

return [
    'database.host' => '127.0.0.1',
    'database.port' => null,
    'database.name' => '',
    'database.user' => 'root',
    'database.password' => null,
    'google.key' => 'YQ4FcwaXD165Xm72lx53qzzNzkz7AUUN',
    PDO::class => static function (ContainerInterface $container) {
        return new PDO(
            sprintf('mysql:host=%s;dbname=%s;', $container->get('database.host'), $container->get('database.name')),
            $container->get('database.user'),
            $container->get('database.password'),
            [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
        );
    },
];
```

``` php
<?php

use DevCoder\DependencyInjection\Container;

$services = require 'services.php';
$container = new Container($services);

var_dump($container->get(PDO::class));
// object(PDO)[18]


var_dump($container->get('google.key'));
// YQ4FcwaXD165Xm72lx53qzzNzkz7AUUN
```
Ideal for small project
Simple and easy!
[https://github.com/devcoder-xyz/php-dependency-injection](https://github.com/devcoder-xyz/php-dependency-injection)

**How can we improve this object?**
* add autowire option to Auto resolution of constructor parameters