mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 15:57:21 +01:00
Add basic container implementation
This commit is contained in:
82
src/Support/Container.php
Normal file
82
src/Support/Container.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Support;
|
||||
|
||||
use Pest\Exceptions\ShouldNotHappen;
|
||||
use ReflectionClass;
|
||||
use ReflectionParameter;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Container
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private $instances = [];
|
||||
|
||||
/**
|
||||
* Gets a dependency from the container.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function get(string $id)
|
||||
{
|
||||
if (array_key_exists($id, $this->instances)) {
|
||||
return $this->instances[$id];
|
||||
}
|
||||
|
||||
$this->instances[$id] = $this->build($id);
|
||||
|
||||
return $this->instances[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given instance to the container.
|
||||
*
|
||||
* @param mixed $instance
|
||||
*/
|
||||
public function add(string $id, $instance): void
|
||||
{
|
||||
$this->instances[$id] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to build the given instance.
|
||||
*/
|
||||
private function build(string $id): object
|
||||
{
|
||||
/** @phpstan-ignore-next-line */
|
||||
$reflectionClass = new ReflectionClass($id);
|
||||
|
||||
if ($reflectionClass->isInstantiable()) {
|
||||
$constructor = $reflectionClass->getConstructor();
|
||||
|
||||
if ($constructor !== null) {
|
||||
$params = array_map(
|
||||
function (ReflectionParameter $param) use ($id) {
|
||||
$candidate = null;
|
||||
|
||||
if ($param->getType() !== null && $param->getType()->isBuiltin()) {
|
||||
$candidate = $param->getName();
|
||||
} elseif ($param->getClass() !== null) {
|
||||
$candidate = $param->getClass()->getName();
|
||||
} else {
|
||||
throw ShouldNotHappen::fromMessage(sprintf('The type of `$%s` in `%s` cannot be determined.', $id, $param->getName()));
|
||||
}
|
||||
|
||||
return $this->get($candidate);
|
||||
},
|
||||
$constructor->getParameters()
|
||||
);
|
||||
|
||||
return $reflectionClass->newInstanceArgs($params);
|
||||
}
|
||||
}
|
||||
|
||||
throw ShouldNotHappen::fromMessage(sprintf('A dependency with the name `%s` cannot be resolved.', $id));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user