首页 >后端开发 >php教程 >使用 PHP 惰性对象构建 PSR 兼容的依赖注入容器

使用 PHP 惰性对象构建 PSR 兼容的依赖注入容器

DDD
DDD原创
2025-01-04 09:45:39193浏览

Building a PSR-Compatible Dependency Injection Container with PHP  Lazy Objects

在 PHP 8.4 中探索使用惰性对象的依赖注入

在现代 PHP 领域,8.4 版本的发布引入了一项突破性的功能:惰性对象。这些对象提供了一种将初始化推迟到绝对必要的新方法,从而提高性能并减少资源使用。通过增强 ReflectionClass API,此功能已深度集成到语言中,如延迟对象 RFC 的延迟初始化中所述。

RFC 中的示例
为了说明惰性对象的潜力,请直接考虑以下 RFC 示例:

class MyClass
{
    public function __construct(private int $foo)
    {
        // Heavy initialization logic here.
    }

    // ...
}

$initializer = static function (MyClass $ghost): void {
    $ghost->__construct(123);
};

$reflector = new ReflectionClass(MyClass::class);
$object = $reflector->newLazyGhost($initializer);

// At this point, $object is a lazy ghost object.

这种机制允许开发者精细地控制初始化过程,确保资源仅在访问时才加载。

受此 RFC 的启发,我开始构建一个 PSR-11 兼容的依赖注入容器,利用惰性对象 API 来实现最佳性能。

ContainerLazyObject 的基础

我们容器的核心在于 ContainerLazyObject 类。有了它,您可以注册依赖项并延迟初始化它们,这意味着它们仅在实际需要时才实例化。这是执行此任务的主要方法:

public function set(string $id, object|string $concrete): void
{
    $reflector = new ReflectionClass($id);
    $initializer = $concrete;

    if (is_string($concrete)) {
        $initializer = function(object $instance) use ($concrete): void {
            $this->instances[$instance::class] = $concrete($this);
        };
    }

    if (is_object($concrete) && !$concrete instanceof Closure) {
        $initializer = function(object $instance) use ($concrete): void {
            $this->instances[$instance::class] = $concrete;
        };
    }

    $this->instances[$id] = $reflector->newLazyGhost($initializer);
}

在容器中注册服务

我们的容器支持多种注册服务的方式,为开发人员提供了灵活性。以下是一些示例:

$container = new ContainerLazyObject();
$containerer->set(DatabaseService::class, fn() => new DatabaseService(new LoggerService()));
$container->set(LoggerService::class, fn() => new LoggerService());

// Alternative approach with class names
$container->set(DatabaseService::class, DatabaseService::class);
$containerr->set(LoggerService::class, LoggerService::class);

// Using already instantiated objects
$container->set(DatabaseService::class, new DatabaseService(new LoggerService()));
$container->set(LoggerService::class, new LoggerService());

这种灵活性使得 ContainerLazyObject 能够适应各种场景,无论是动态构建依赖项还是重用预配置的对象。

从容器中检索服务
一旦服务在容器中注册,您就可以在需要时检索它们。容器确保服务是延迟实例化的,因此在实际请求之前不会创建它们。以下是如何检索已注册服务的示例:

// Retrieving the services from the container
$loggerService = $container->get(LoggerService::class);
$databaseService = $container->get(DatabaseService::class);

ContainerLazyObject 的核心我们容器的核心在于 ContainerLazyObject 类。有了它,您可以注册依赖项并延迟初始化它们,这意味着它们仅在实际使用时创建。这是执行此任务的主要方法:

public function set(string $id, object|string $concrete): void
{
    $reflector = new ReflectionClass($id);
    $initializer = $concrete;

    if (is_string($concrete)) {
        $initializer = function(object $instance) use ($concrete): void {
            $this->instances[$instance::class] = $concrete($this);
        };
    }

    if (is_object($concrete) && !$concrete instanceof Closure) {
        $initializer = function(object $instance) use ($concrete): void {
            $this->instances[$instance::class] = $concrete;
        };
    }

    $this->instances[$id] = $reflector->newLazyGhost($initializer);
}

PSR-11 兼容性

ContainerLazyObject 的另一个优点是它与 PSR-11(依赖注入容器的 PHP 标准)兼容。这确保了与遵循规范的库和框架的互操作性,使其成为轻量级且通用的解决方案。

与其他容器的性能比较

为了测量容器的性能,我在受控环境中使用了 PhpBench,并将其与流行的替代方案进行了比较:Pimple、Illuminate 和 PHP-DI。结果令人鼓舞:

class MyClass
{
    public function __construct(private int $foo)
    {
        // Heavy initialization logic here.
    }

    // ...
}

$initializer = static function (MyClass $ghost): void {
    $ghost->__construct(123);
};

$reflector = new ReflectionClass(MyClass::class);
$object = $reflector->newLazyGhost($initializer);

// At this point, $object is a lazy ghost object.

我们的容器展示了出色的性能,在简单的依赖解析场景中比 Illuminate Container 和 PHP-DI 等更强大的替代方案要快得多。

完整课程

public function set(string $id, object|string $concrete): void
{
    $reflector = new ReflectionClass($id);
    $initializer = $concrete;

    if (is_string($concrete)) {
        $initializer = function(object $instance) use ($concrete): void {
            $this->instances[$instance::class] = $concrete($this);
        };
    }

    if (is_object($concrete) && !$concrete instanceof Closure) {
        $initializer = function(object $instance) use ($concrete): void {
            $this->instances[$instance::class] = $concrete;
        };
    }

    $this->instances[$id] = $reflector->newLazyGhost($initializer);
}

结论

PHP 8.4 及其惰性对象为简化和优化依赖注入开辟了新的可能性。我们的 ContainerLazyObject 除了轻量、高效和灵活之外,还符合 PSR-11 标准,确保与其他库和框架的互操作性。

尝试这种方法,看看它如何在您的下一个项目中简化依赖关系管理!

以上是使用 PHP 惰性对象构建 PSR 兼容的依赖注入容器的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn