PHP服务容器与依赖管理进阶
PHP服务容器与依赖管理进阶服务容器是现代PHP框架的核心。除了基本的依赖解析容器还需要处理别名、标记、延迟加载等高级功能。今天实现一个功能更完整的容器。先看看容器的自动解析能力。反射机制让容器能够分析类的构造函数递归地创建所有依赖。phpclass ServiceContainer{private array $bindings [];private array $instances [];private array $aliases [];private array $tags [];private array $extenders [];public function bind(string $abstract, callable|string|null $concrete null, bool $shared false): void{if ($concrete null) {$concrete $abstract;}if (!$concrete instanceof Closure) {$concrete $this-getClosure($abstract, $concrete);}$this-bindings[$abstract] compact(concrete, shared);}public function singleton(string $abstract, callable|string|null $concrete null): void{$this-bind($abstract, $concrete, true);}public function instance(string $abstract, mixed $instance): void{$this-instances[$abstract] $instance;}public function alias(string $abstract, string $alias): void{$this-aliases[$alias] $abstract;}public function tag(array $abstracts, string $tag): void{foreach ($abstracts as $abstract) {$this-tags[$tag][] $abstract;}}public function tagged(string $tag): array{$results [];foreach ($this-tags[$tag] ?? [] as $abstract) {$results[] $this-make($abstract);}return $results;}public function extend(string $abstract, callable $extender): void{if (isset($this-instances[$abstract])) {$this-instances[$abstract] $extender($this-instances[$abstract], $this);} else {$this-extenders[$abstract][] $extender;}}public function make(string $abstract): mixed{$abstract $this-getAlias($abstract);if (isset($this-instances[$abstract])) {return $this-instances[$abstract];}if (!isset($this-bindings[$abstract])) {return $this-autoResolve($abstract);}$binding $this-bindings[$abstract];$object $binding[concrete]($this);if (!empty($this-extenders[$abstract])) {foreach ($this-extenders[$abstract] as $extender) {$object $extender($object, $this);}}if ($binding[shared]) {$this-instances[$abstract] $object;}return $object;}public function has(string $abstract): bool{$abstract $this-getAlias($abstract);return isset($this-bindings[$abstract])|| isset($this-instances[$abstract])|| class_exists($abstract);}public function call(callable|array $callable, array $parameters []): mixed{if (is_array($callable)) {$reflector new ReflectionMethod($callable[0], $callable[1]);} else {$reflector new ReflectionFunction($callable);}$dependencies [];foreach ($reflector-getParameters() as $param) {$name $param-getName();if (isset($parameters[$name])) {$dependencies[] $parameters[$name];} elseif ($param-getType() !$param-getType()-isBuiltin()) {$dependencies[] $this-make($param-getType()-getName());} elseif ($param-isDefaultValueAvailable()) {$dependencies[] $param-getDefaultValue();} else {throw new RuntimeException(无法解析参数: $name);}}return $reflector-invokeArgs($dependencies);}private function getClosure(string $abstract, string $concrete): Closure{return function (ServiceContainer $container) use ($abstract, $concrete) {if ($concrete $abstract || !class_exists($concrete)) {return $container-autoResolve($concrete);}return $container-autoResolve($concrete);};}private function autoResolve(string $class): object{if (!class_exists($class)) {throw new RuntimeException(无法解析: $class);}$ref new ReflectionClass($class);$ctor $ref-getConstructor();if ($ctor null) {return $ref-newInstance();}$params [];foreach ($ctor-getParameters() as $param) {$type $param-getType();if ($type null) {if ($param-isDefaultValueAvailable()) {$params[] $param-getDefaultValue();} else {throw new RuntimeException(无法解析参数: {$param-getName()});}} elseif ($type-isBuiltin()) {if ($param-isDefaultValueAvailable()) {$params[] $param-getDefaultValue();} else {throw new RuntimeException(无法解析内置类型: {$param-getName()});}} else {$params[] $this-make($type-getName());}}return $ref-newInstanceArgs($params);}private function getAlias(string $abstract): string{return $this-aliases[$abstract] ?? $abstract;}}?// 使用示例interface LoggerInterface{public function log(string $message): void;}class FileLogger implements LoggerInterface{public function log(string $message): void{error_log(date(Y-m-d H:i:s) . $message);}}class DatabaseLogger implements LoggerInterface{public function log(string $message): void{// 写入数据库...}}class UserService{public function __construct(private LoggerInterface $logger,private array $config []) {}public function register(string $name): void{$this-logger-log(用户注册: $name);}}$container new ServiceContainer();$container-bind(LoggerInterface::class, FileLogger::class);$container-alias(logger, LoggerInterface::class);$container-singleton(db, function () {return new PDO(mysql:hostlocalhost;dbnametest, root, );});$service $container-make(UserService::class);$service-register(张三);echo 容器工作正常\n;?服务提供者模式把相关的服务注册和引导逻辑组织在一起。容器在项目中的核心作用就是管理依赖让代码更模块化、更易测试。理解了容器的原理不管用什么框架都能快速上手。