PHP 依赖注入容器自动解析

wen PHP项目 7

本文目录导读:

PHP 依赖注入容器自动解析

  1. 基础依赖注入容器实现
  2. 增强版容器(支持更多特性)
  3. 实际使用示例
  4. 专业级完整实现
  5. 使用第三方容器(推荐)
  6. 性能优化和最佳实践

我来详细讲解PHP依赖注入容器(DIC)的自动解析机制,包括完整实现和最佳实践。

基础依赖注入容器实现

基础容器类

<?php
namespace App\Container;
class Container
{
    /**
     * 已注册的服务实例
     */
    private array $instances = [];
    /**
     * 已注册的服务定义(闭包)
     */
    private array $definitions = [];
    /**
     * 别名映射
     */
    private array $aliases = [];
    /**
     * 实例化中的类(用于检测循环依赖)
     */
    private array $resolving = [];
    /**
     * 绑定接口到实现
     */
    public function bind(string $abstract, $concrete = null): void
    {
        if ($concrete === null) {
            $concrete = $abstract;
        }
        if ($concrete instanceof \Closure) {
            $this->definitions[$abstract] = $concrete;
        } else {
            // 存储类名,延迟实例化
            $this->definitions[$abstract] = function () use ($concrete) {
                return $this->build($concrete);
            };
        }
    }
    /**
     * 绑定单例
     */
    public function singleton(string $abstract, $concrete = null): void
    {
        $this->bind($abstract, $concrete);
        // 标记为单例
        $this->definitions[$abstract] = function () use ($abstract) {
            if (!isset($this->instances[$abstract])) {
                $this->instances[$abstract] = call_user_func($this->definitions[$abstract], $this);
            }
            return $this->instances[$abstract];
        };
    }
    /**
     * 设置实例
     */
    public function instance(string $abstract, $instance): void
    {
        $this->instances[$abstract] = $instance;
    }
    /**
     * 添加别名
     */
    public function alias(string $abstract, string $alias): void
    {
        $this->aliases[$alias] = $abstract;
    }
    /**
     * 从容器中解析服务
     */
    public function make(string $abstract)
    {
        // 解析别名
        $abstract = $this->getAlias($abstract);
        // 如果已有实例,直接返回
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }
        // 检测循环依赖
        if (isset($this->resolving[$abstract])) {
            throw new \RuntimeException("Circular dependency detected: {$abstract}");
        }
        $this->resolving[$abstract] = true;
        try {
            // 如果有定义,使用定义创建
            if (isset($this->definitions[$abstract])) {
                $object = call_user_func($this->definitions[$abstract], $this);
            } else {
                // 否则自动解析
                $object = $this->build($abstract);
            }
        } finally {
            unset($this->resolving[$abstract]);
        }
        return $object;
    }
    /**
     * 自动构建类
     */
    public function build(string $class)
    {
        // 通过反射获取类信息
        $reflector = new \ReflectionClass($class);
        // 检查类是否可实例化
        if (!$reflector->isInstantiable()) {
            throw new \Exception("Class {$class} is not instantiable");
        }
        // 获取构造函数
        $constructor = $reflector->getConstructor();
        // 没有构造函数,直接实例化
        if (is_null($constructor)) {
            return new $class();
        }
        // 获取构造函数的参数
        $dependencies = $this->resolveDependencies($constructor->getParameters());
        // 创建类实例
        return $reflector->newInstanceArgs($dependencies);
    }
    /**
     * 解析构造函数依赖
     */
    private function resolveDependencies(array $parameters): array
    {
        $dependencies = [];
        foreach ($parameters as $parameter) {
            $dependency = $this->resolveParameter($parameter);
            if ($dependency !== null) {
                $dependencies[] = $dependency;
            }
        }
        return $dependencies;
    }
    /**
     * 解析单个参数
     */
    private function resolveParameter(\ReflectionParameter $parameter)
    {
        // 获取参数类型
        $type = $parameter->getType();
        if ($type && !$type->isBuiltin()) {
            // 类型是类,从容器中解析
            $typeName = $type->getName();
            return $this->make($typeName);
        }
        // 参数有默认值
        if ($parameter->isDefaultValueAvailable()) {
            return $parameter->getDefaultValue();
        }
        // 尝试使用参数名查找配置
        if (isset($this->config[$parameter->getName()])) {
            return $this->config[$parameter->getName()];
        }
        throw new \Exception("Unable to resolve parameter: {$parameter->getName()}");
    }
    /**
     * 解析别名
     */
    private function getAlias(string $abstract): string
    {
        return $this->aliases[$abstract] ?? $abstract;
    }
}

增强版容器(支持更多特性)

<?php
namespace App\Container;
use ReflectionClass;
use ReflectionMethod;
use ReflectionParameter;
class AdvancedContainer extends Container
{
    /**
     * 已解析的服务标记
     */
    private array $shared = [];
    /**
     * 参数默认值配置
     */
    private array $parameterOverrides = [];
    /**
     * 服务修饰器
     */
    private array $decorators = [];
    /**
     * 方法调用注入
     */
    public function call($callable, array $parameters = [])
    {
        if (is_string($callable) && strpos($callable, '@') !== false) {
            [$class, $method] = explode('@', $callable);
            $instance = $this->make($class);
            $callable = [$instance, $method];
        }
        if (is_array($callable)) {
            $reflection = new ReflectionMethod($callable[0], $callable[1]);
        } elseif (is_object($callable) && !$callable instanceof \Closure) {
            $reflection = new ReflectionMethod($callable, '__invoke');
        } else {
            $reflection = new \ReflectionFunction($callable);
        }
        return $reflection->invokeArgs($this->resolveDependenciesForMethod($reflection, $parameters));
    }
    /**
     * 解析方法依赖
     */
    private function resolveDependenciesForMethod($reflection, array $parameters = []): array
    {
        $dependencies = [];
        foreach ($reflection->getParameters() as $parameter) {
            // 优先使用传入的参数
            if (array_key_exists($parameter->getName(), $parameters)) {
                $dependencies[] = $parameters[$parameter->getName()];
                continue;
            }
            // 解析类型依赖
            $dependency = $this->resolveParameter($parameter);
            if ($dependency !== null) {
                $dependencies[] = $dependency;
            }
        }
        return $dependencies;
    }
    /**
     * 添加服务修饰器
     */
    public function extend(string $abstract, callable $decorator): void
    {
        $this->decorators[$abstract][] = $decorator;
    }
    /**
     * 重写make方法以支持修饰器
     */
    public function make(string $abstract)
    {
        $instance = parent::make($abstract);
        if (isset($this->decorators[$abstract])) {
            foreach ($this->decorators[$abstract] as $decorator) {
                $instance = $decorator($instance, $this);
            }
        }
        return $instance;
    }
    /**
     * 设置参数覆盖
     */
    public function when(string $class): ParameterOverrider
    {
        return new ParameterOverrider($class, $this);
    }
    /**
     * 自动解析类并调用方法
     */
    public function resolveAndCall(string $class, string $method, array $parameters = [])
    {
        $instance = $this->make($class);
        $reflection = new ReflectionMethod($instance, $method);
        return $reflection->invokeArgs(
            $this->resolveDependencies($reflection->getParameters(), $parameters)
        );
    }
    /**
     * 获取所有已注册的服务
     */
    public function getRegisteredServices(): array
    {
        return array_keys($this->definitions);
    }
}
/**
 * 参数覆盖器辅助类
 */
class ParameterOverrider
{
    private string $class;
    private AdvancedContainer $container;
    private array $overrides = [];
    public function __construct(string $class, AdvancedContainer $container)
    {
        $this->class = $class;
        $this->container = $container;
    }
    public function needs(string $parameter): self
    {
        $this->overrides['current'] = $parameter;
        return $this;
    }
    public function give($value): void
    {
        // 实现参数覆盖逻辑
        $this->container->addParameterOverride(
            $this->class,
            $this->overrides['current'],
            $value
        );
    }
}

实际使用示例

<?php
// 定义接口和类
interface MailerInterface
{
    public function send(string $to, string $message): bool;
}
class SmtpMailer implements MailerInterface
{
    public function __construct(
        private string $host,
        private int $port = 587,
        private string $username = '',
        private string $password = ''
    ) {}
    public function send(string $to, string $message): bool
    {
        echo "Sending email to {$to} via SMTP\n";
        return true;
    }
}
class UserService
{
    public function __construct(
        protected UserRepository $userRepository,
        protected MailerInterface $mailer,
        protected LoggerInterface $logger
    ) {}
    public function registerUser(array $data): User
    {
        $user = $this->userRepository->create($data);
        $this->mailer->send($user->email, 'Welcome!');
        $this->logger->info("User {$user->id} registered");
        return $user;
    }
}
class UserRepository
{
    public function __construct(
        protected DatabaseConnection $db
    ) {}
    public function create(array $data): User
    {
        return new User($data['id'] ?? 1, $data['email']);
    }
}
class DatabaseConnection
{
    public function __construct(
        private string $dsn,
        private bool $persistent = true
    ) {}
}
class LoggerInterface {}
class FileLogger extends LoggerInterface {}
// 使用容器
$container = new AdvancedContainer();
// 配置基础服务
$container->bind('database.config', [
    'dsn' => 'mysql:host=localhost;dbname=app',
    'persistent' => true
]);
// 绑定具体类
$container->bind(DatabaseConnection::class, function ($c) {
    $config = $c->make('database.config');
    return new DatabaseConnection($config['dsn'], $config['persistent']);
});
$container->bind(LoggerInterface::class, FileLogger::class);
$container->singleton(MailerInterface::class, SmtpMailer::class);
// 自动解析(无需手动注册 UserService)
try {
    $userService = $container->make(UserService::class);
    $user = $userService->registerUser([
        'id' => 1,
        'email' => 'user@example.com'
    ]);
    echo "User created: {$user->email}\n";
} catch (Exception $e) {
    echo "Error: {$e->getMessage()}\n";
}
// 方法调用注入
$result = $container->call(function (UserRepository $repo, MailerInterface $mailer) {
    return $repo->findAll();
});
// 使用别名
$container->alias('user.service', UserService::class);
$service = $container->make('user.service');

专业级完整实现

<?php
namespace App\Container;
use ReflectionClass;
use ReflectionParameter;
use Throwable;
interface ContainerInterface
{
    public function get(string $id);
    public function has(string $id): bool;
}
class AutoWireContainer implements ContainerInterface
{
    use HasParameterOverrides;
    use HasAliases;
    private array $bindings = [];
    private array $instances = [];
    private array $contextual = [];
    private array $resolving = [];
    private array $buildStack = [];
    /**
     * 自动解析并缓存结果
     */
    public function get(string $id)
    {
        $id = $this->resolveAlias($id);
        // 检测循环依赖
        if (isset($this->buildStack[$id])) {
            throw new CircularDependencyException(
                "Circular dependency detected: " . implode(' -> ', array_keys($this->buildStack))
            );
        }
        // 从实例缓存获取
        if (isset($this->instances[$id])) {
            return $this->instances[$id];
        }
        $this->buildStack[$id] = true;
        try {
            $instance = $this->resolve($id);
            // 单例缓存
            if ($this->isShared($id)) {
                $this->instances[$id] = $instance;
            }
            return $instance;
        } finally {
            unset($this->buildStack[$id]);
        }
    }
    /**
     * 核心解析逻辑
     */
    protected function resolve(string $concrete)
    {
        // 查找绑定
        if (isset($this->bindings[$concrete])) {
            $binding = $this->bindings[$concrete];
            if ($binding instanceof \Closure) {
                return $binding($this);
            }
            $concrete = $binding;
        }
        // 上下文绑定解析
        $contextualBindings = $this->getContextualBindings();
        if (isset($contextualBindings[$concrete])) {
            $concrete = $contextualBindings[$concrete];
        }
        return $this->buildClass($concrete);
    }
    /**
     * 通过反射构建类
     */
    protected function buildClass(string $class)
    {
        try {
            $reflector = new ReflectionClass($class);
        } catch (Throwable $e) {
            throw new BindingResolutionException("Target class [$class] does not exist", 0, $e);
        }
        if (!$reflector->isInstantiable()) {
            throw new BindingResolutionException(
                "Target [$class] is not instantiable"
            );
        }
        // 获取构造函数
        $constructor = $reflector->getConstructor();
        if (is_null($constructor)) {
            return new $class();
        }
        // 解析依赖参数
        $dependencies = $this->resolveDependencies(
            $constructor->getParameters()
        );
        // 创建实例并执行属性注入
        $instance = $reflector->newInstanceArgs($dependencies);
        return $this->performPropertyInjection($instance;
    }
    /**
     * 解析构造函数依赖
     */
    protected function resolveDependencies(array $parameters): array
    {
        $dependencies = [];
        foreach ($parameters as $parameter) {
            if ($this->hasParameterOverride($parameter)) {
                $dependencies[] = $this->resolveParameterOverride($parameter);
                continue;
            }
            $dependency = $this->resolveClassDependency($parameter);
            if ($dependency !== null) {
                $dependencies[] = $dependency;
            }
        }
        return $dependencies;
    }
    /**
     * 解析类类型依赖
     */
    protected function resolveClassDependency(ReflectionParameter $parameter)
    {
        $type = $parameter->getType();
        // 检查是否为类类型
        if ($type && !$type->isBuiltin()) {
            $typeName = $type->getName();
            // 检查是否实现接口
            if ($type->isInterface()) {
                return $this->resolveInterface($typeName);
            }
            return $this->get($typeName);
        }
        // 检查默认值
        if ($parameter->isDefaultValueAvailable()) {
            return $parameter->getDefaultValue();
        }
        // 检查是否可空
        if ($type && $type->allowsNull()) {
            return null;
        }
        throw new UnresolvableDependencyException(
            "Unable to resolve dependency [{$parameter->getName()}] for parameter"
        );
    }
    /**
     * 解析接口实现
     */
    protected function resolveInterface(string $interface): mixed
    {
        if (isset($this->bindings[$interface])) {
            return $this->get($interface);
        }
        // 尝试找到实现类
        $implementations = $this->findImplementations($interface);
        if (count($implementations) === 1) {
            return $this->get($implementations[0]);
        }
        if (count($implementations) > 1) {
            throw new AmbiguousBindingException(
                "Multiple implementations found for interface: {$interface}"
            );
        }
        throw new BindingResolutionException(
            "No concrete implementation found for interface: {$interface}"
        );
    }
    /**
     * 查找接口的类实现
     */
    protected function findImplementations(string $interface): array
    {
        // 这里可以搜索项目目录或使用已有的映射
        // 简单实现 - 从已注册的绑定中查找
        $implementations = [];
        foreach ($this->bindings as $key => $binding) {
            if (is_string($binding) && class_exists($binding)) {
                $reflection = new ReflectionClass($binding);
                if ($reflection->implementsInterface($interface)) {
                    $implementations[] = $binding;
                }
            }
        }
        return $implementations;
    }
    /**
     * 属性注入
     */
    protected function performPropertyInjection($instance)
    {
        $reflection = new ReflectionClass($instance);
        foreach ($reflection->getProperties() as $property) {
            // 检查属性的注入注解(这里简单演示)
            if ($property->getAttributes(Inject::class)) {
                $property->setAccessible(true);
                $type = $property->getType();
                if ($type && !$type->isBuiltin()) {
                    $property->setValue(
                        $instance,
                        $this->get($type->getName())
                    );
                }
            }
        }
        return $instance;
    }
    public function has(string $id): bool
    {
        return isset($this->bindings[$id]) || 
               isset($this->instances[$id]) || 
               class_exists($id);
    }
    /**
     * 清除容器缓存
     */
    public function flush(): void
    {
        $this->instances = [];
        $this->resolving = [];
    }
}
// 自定义异常类
class CircularDependencyException extends \RuntimeException {}
class BindingResolutionException extends \RuntimeException {}
class UnresolvableDependencyException extends \RuntimeException {}
class AmbiguousBindingException extends \RuntimeException {}

使用第三方容器(推荐)

Composer PHP-DI

<?php
use DI\ContainerBuilder;
$containerBuilder = new ContainerBuilder();
$containerBuilder->useAutowiring(true);
$containerBuilder->useAnnotations(true);
// 配置定义
$containerBuilder->addDefinitions([
    'database.host' => 'localhost',
    DatabaseConnection::class => function ($c) {
        return new DatabaseConnection(
            "mysql:host={$c->get('database.host')};dbname=app"
        );
    },
    MailerInterface::class => DI\autowire(SmtpMailer::class),
    UserService::class => DI\create()
        ->constructor(
            DI\get(UserRepository::class),
            DI\get(MailerInterface::class),
            DI\get(LoggerInterface::class)
        ),
]);
$container = $containerBuilder->build();
// 自动解析
$userService = $container->get(UserService::class);
// 使用注解注入
class OrderService
{
    /**
     * @Inject
     * @var PaymentGatewayInterface
     */
    private $paymentGateway;
    /**
     * @Inject
     * @var OrderRepository
     */
    private OrderRepository $repository;
    public function process(Order $order)
    {
        return $this->paymentGateway->charge($order->amount);
    }
}

Laravel容器的自动注入

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\UserService;
class UserController extends Controller
{
    public function register(
        Request $request,
        UserService $userService // 自动注入
    ) {
        // 使用自动注入的服务
        $user = $userService->register($request->all());
        return response()->json($user);
    }
}

性能优化和最佳实践

自动解析缓存

<?php
class CacheableContainer extends AdvancedContainer
{
    private $cache;
    public function __construct(CacheInterface $cache = null)
    {
        parent::__construct();
        $this->cache = $cache ?? new ArrayCache();
    }
    public function make(string $abstract)
    {
        $cacheKey = "container.{$abstract}";
        // 使用缓存
        if ($this->cache->has($cacheKey)) {
            return $this->cache->get($cacheKey);
        }
        $instance = parent::make($abstract);
        // 缓存结果
        if ($this->shouldCache($abstract)) {
            $this->cache->set($cacheKey, $instance);
        }
        return $instance;
    }
}
  1. 接口绑定优先:优先绑定接口到具体实现
  2. 延迟加载:不要立即实例化所有服务
  3. 合理使用单例:只对真正需要保持状态的服务使用单例
  4. 避免循环依赖:通过构造函数注入减少循环依赖
  5. 容器配置集中:将容器配置集中在一个文件中管理
  6. 性能优化:对不经常变化的服务使用缓存
// 典型应用配置
return [
    Registration::class => Registration::class,
    MailerInterface::class => create(SmtpMailer::class),
    'services.names' => [
        'PHP',
        'Laravel',
        'Node.js'
    ],
    'services.paths' => function ($container) {
        return $container->get('services.names');
    }
];

这样的自动解析机制让开发者能够专注于业务逻辑,而不用关心对象如何创建和依赖如何管理。

抱歉,评论功能暂时关闭!