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
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
namespace DevCoder\DependencyInjection\Exception;
use Psr\Container\NotFoundExceptionInterface;
/**
* Class NotFoundException
* @package DevCoder\DependencyInjection\Exception
*/
class NotFoundException extends \InvalidArgumentException implements NotFoundExceptionInterface
{
}
How to use ?
// 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
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
How can we improve this object?
- add autowire option to Auto resolution of constructor parameters
Top comments (5)
Was this code even tested?
Declaration of App\Container::has($id) must be compatible with Psr\Container\ContainerInterface::has(string $id): bool in ...
This absolutely does not work. This tutorial is more of a service locator pattern with a PSR-11 container.
What not to do.
This code has been tested successfully! You are using a newer version of Psr\Container which introduced a return type of 'bool'. This did not exist at the time this tutorial was created! This is a tutorial and will remain a tutorial!
Why isn't the version of the PSR container specified, if that's the case? This tutorial frustrates more than helps.
public function has($id)
Needs a return type. Are you sure you want to keep this up?
This code is broken. And fraught with errors. It is nothing like PHP-DI.
PDO:class
You mean
PDO::class?
yes, thanks
Some comments have been hidden by the post's author - find out more