<?php
declare(strict_types=1);
namespace App\DI;
use Attribute;
use ReflectionParameter;
use ReflectionFunction;
use ReflectionException;
use ReflectionAttribute;
use ReflectionNamedArgument;
#[Attribute]
class Inject
{
public function __construct(
public string $className
) {}
}
class Container
{
private array $bindings = [];
public function bind(string $abstract, string $concrete): void
{
$this->bindings[$abstract] = $concrete;
}
public function make(string $abstract): object
{
if (isset($this->bindings[$abstract])) {
$abstract = $this->bindings[$abstract];
}
return $this->resolve($abstract);
}
private function resolve(string $concrete): object
{
// 尝试创建类的实例
try {
$reflectionClass = new ReflectionClass($concrete);
if (!$reflectionClass->isInstantiable()) {
throw new ReflectionException("类 {$concrete} 不可实例化");
}
$constructor = $reflectionClass->getConstructor();
if (is_null($constructor)) {
return new $concrete;
}
$parameters = $constructor->getParameters();
$dependencies = $this->getDependencies($parameters);
return $reflectionClass->newInstanceArgs($dependencies);
} catch (ReflectionException $e) {
// 处理异常
throw new Exception($e->getMessage());
}
}
private function getDependencies(array $parameters): array
{
$dependencies = [];
foreach ($parameters as $parameter) {
$dependency = $parameter->getType();
if ($dependency) {
$dependencyName = $dependency->getName();
if (class_exists($dependencyName)) {
$dependencies[] = $this->make($dependencyName);
continue;
}
}
$attributes = $parameter->getAttributes(Inject::class, ReflectionAttribute::IS_INSTANCEOF);
if ($attributes) {
/** @var ReflectionNamedArgument $argument */
$argument = $attributes[0]->getArguments()['className'];
评论已关闭