|
|
|
@@ -5,21 +5,55 @@ declare(strict_types=1); |
|
|
|
namespace Core; |
|
|
|
|
|
|
|
use Exception; |
|
|
|
use ReflectionClass; |
|
|
|
use ReflectionFunction; |
|
|
|
use ReflectionFunctionAbstract; |
|
|
|
use ReflectionMethod; |
|
|
|
|
|
|
|
class App |
|
|
|
{ |
|
|
|
protected array $bindings = []; |
|
|
|
|
|
|
|
protected array $instances = []; |
|
|
|
|
|
|
|
public function bind(string $name, mixed $value): void |
|
|
|
{ |
|
|
|
$this->bindings[$name] = $value; |
|
|
|
} |
|
|
|
|
|
|
|
public function instance(string $name, mixed $value): void |
|
|
|
{ |
|
|
|
$this->instances[$name] = $value; |
|
|
|
} |
|
|
|
|
|
|
|
public function make(string $className): object |
|
|
|
{ |
|
|
|
if (isset($this->bindings[$className])) { |
|
|
|
$binding = $this->bindings[$className]; |
|
|
|
|
|
|
|
if (is_string($binding) && is_a($binding, $className, true)) { |
|
|
|
return $this->instantiate($binding); |
|
|
|
} |
|
|
|
|
|
|
|
return $binding; |
|
|
|
} |
|
|
|
|
|
|
|
if (isset($this->instances[$className])) { |
|
|
|
return $this->instances[$className]; |
|
|
|
} |
|
|
|
|
|
|
|
return $this->instantiate($className); |
|
|
|
} |
|
|
|
|
|
|
|
public function clear(): void |
|
|
|
{ |
|
|
|
$this->bindings = []; |
|
|
|
$this->instances = []; |
|
|
|
} |
|
|
|
|
|
|
|
public function get(string $name): mixed |
|
|
|
{ |
|
|
|
return $this->bindings[$name] ?? null; |
|
|
|
return $this->instances[$name] ?? $this->bindings[$name] ?? null; |
|
|
|
} |
|
|
|
|
|
|
|
public function call(callable|array|string $handler, array $parameters = []): mixed |
|
|
|
@@ -72,8 +106,20 @@ class App |
|
|
|
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) { |
|
|
|
$typeName = $type->getName(); |
|
|
|
|
|
|
|
if (array_key_exists($typeName, $this->instances)) { |
|
|
|
$args[] = $this->instances[$typeName]; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (array_key_exists($typeName, $this->bindings)) { |
|
|
|
$args[] = $this->bindings[$typeName]; |
|
|
|
$binding = $this->bindings[$typeName]; |
|
|
|
|
|
|
|
if (is_string($binding) && is_a($binding, $typeName, true)) { |
|
|
|
$args[] = $this->instantiate($binding); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
$args[] = $binding; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -83,4 +129,26 @@ class App |
|
|
|
|
|
|
|
return $args; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param class-string $className |
|
|
|
*/ |
|
|
|
protected function instantiate(string $className): object |
|
|
|
{ |
|
|
|
$reflection = new ReflectionClass($className); |
|
|
|
|
|
|
|
if (!$reflection->isInstantiable()) { |
|
|
|
throw new Exception("Cannot instantiate {$className}: class is not instantiable."); |
|
|
|
} |
|
|
|
|
|
|
|
$constructor = $reflection->getConstructor(); |
|
|
|
|
|
|
|
if ($constructor === null) { |
|
|
|
return new $className(); |
|
|
|
} |
|
|
|
|
|
|
|
$args = $this->resolveArgs($constructor, []); |
|
|
|
|
|
|
|
return $reflection->newInstanceArgs($args); |
|
|
|
} |
|
|
|
} |