Complete Phase 1: MVC, DB migrations, Auth, RBAC, Security, and Views
This commit is contained in:
116
app/Core/Container.php
Normal file
116
app/Core/Container.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Exception;
|
||||
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
private array $bindings = [];
|
||||
private array $instances = [];
|
||||
|
||||
/**
|
||||
* Bind a dependency to the container.
|
||||
*/
|
||||
public function bind(string $id, callable|string $concrete, bool $singleton = false): void
|
||||
{
|
||||
$this->bindings[$id] = [
|
||||
'concrete' => $concrete,
|
||||
'singleton' => $singleton
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a singleton dependency.
|
||||
*/
|
||||
public function singleton(string $id, callable|string $concrete): void
|
||||
{
|
||||
$this->bind($id, $concrete, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dependency from the container.
|
||||
*/
|
||||
public function get(string $id): mixed
|
||||
{
|
||||
if (isset($this->instances[$id])) {
|
||||
return $this->instances[$id];
|
||||
}
|
||||
|
||||
if (!$this->has($id)) {
|
||||
return $this->resolve($id);
|
||||
}
|
||||
|
||||
$binding = $this->bindings[$id];
|
||||
$concrete = $binding['concrete'];
|
||||
|
||||
$object = $this->resolve($concrete);
|
||||
|
||||
if ($binding['singleton']) {
|
||||
$this->instances[$id] = $object;
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a dependency is bound.
|
||||
*/
|
||||
public function has(string $id): bool
|
||||
{
|
||||
return isset($this->bindings[$id]) || isset($this->instances[$id]) || class_exists($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a concrete class or binding.
|
||||
*/
|
||||
private function resolve(mixed $concrete): mixed
|
||||
{
|
||||
if ($concrete instanceof \Closure || is_callable($concrete)) {
|
||||
return $concrete($this);
|
||||
}
|
||||
|
||||
if (is_string($concrete)) {
|
||||
if (!class_exists($concrete)) {
|
||||
return $concrete;
|
||||
}
|
||||
|
||||
$reflector = new \ReflectionClass($concrete);
|
||||
|
||||
if (!$reflector->isInstantiable()) {
|
||||
throw new Exception("Class {$concrete} is not instantiable.");
|
||||
}
|
||||
|
||||
$constructor = $reflector->getConstructor();
|
||||
|
||||
if (null === $constructor) {
|
||||
return new $concrete();
|
||||
}
|
||||
|
||||
$parameters = $constructor->getParameters();
|
||||
$dependencies = [];
|
||||
|
||||
foreach ($parameters as $parameter) {
|
||||
$type = $parameter->getType();
|
||||
|
||||
if (!$type) {
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
$dependencies[] = $parameter->getDefaultValue();
|
||||
} else {
|
||||
throw new Exception("Cannot resolve parameter {$parameter->getName()} in class {$concrete}");
|
||||
}
|
||||
} elseif ($type instanceof \ReflectionUnionType) {
|
||||
throw new Exception("Union types in constructor injection not supported for class {$concrete}");
|
||||
} else {
|
||||
$typeName = $type->getName();
|
||||
$dependencies[] = $this->get($typeName);
|
||||
}
|
||||
}
|
||||
|
||||
return $reflector->newInstanceArgs($dependencies);
|
||||
}
|
||||
|
||||
return $concrete;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user