Skip to content

Instantly share code, notes, and snippets.

@missoxd
Last active July 29, 2022 17:25
Show Gist options
  • Save missoxd/51022026929a2a6c9d109727622804fa to your computer and use it in GitHub Desktop.
Save missoxd/51022026929a2a6c9d109727622804fa to your computer and use it in GitHub Desktop.
<?php
class Container
{
private array $instances = [];
public function set(string $key, $value): void
{
if (is_string($value) || is_callable($value)) {
$value = $this->resolve($value);
}
$this->instances[$key] = $value;
}
public function get(string $id)
{
if ($this->has($id)) {
return $this->instances[$id];
}
try {
return $this->instances[$id] = $this->resolve($id);
} catch (ReflectionException $ex) {
throw new Exception($ex->getMessage());
} catch (Exception $ex) {
throw new Exception($ex->getMessage());
}
}
public function has(string $id): bool
{
return isset($this->instances[$id]);
}
private function resolve($id)
{
if (is_callable($id)) {
return $id();
}
return $this->instance(new ReflectionClass($id));
}
private function instance(ReflectionClass $class)
{
$constructor = $class->getConstructor();
if (is_null($constructor) || $constructor->getNumberOfRequiredParameters() === 0) {
return $class->newInstance();
}
$args = array_reduce($constructor->getParameters(), fn(array $carry, $arg) => (($type = $arg->getType()) ? $carry + [$this->get($type->getName())] : $carry), []);
return $class->newInstanceArgs($args);
}
}
class Test1 {
public string $name = 'Default Test 1 Name';
}
class Test2
{
public string $name = 'Default Test 2 Name';
public function __construct(
private Test1 $test1
) {}
}
class Test3
{
public string $name = 'Default Test 3 Name';
public function __construct(
private Test2 $test2
) {}
}
$customTest1 = new Test1;
$customTest1->name = 'Custom Test 1 Name';
$ioc = new Container;
$ioc->set(Test1::class, $customTest1);
var_dump($ioc->get(Test3::class));
/*
PHP 8.1.x
Output:
object(Test3)#6 (2) {
["name"]=>
string(19) "Default Test 3 Name"
["test2":"Test3":private]=>
object(Test2)#11 (2) {
["name"]=>
string(19) "Default Test 2 Name"
["test1":"Test2":private]=>
object(Test1)#1 (1) {
["name"]=>
string(18) "Custom Test 1 Name"
}
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment