首頁 > 後端開發 > php教程 > 使用 PHP 惰性物件建立 PSR 相容的依賴注入容器

使用 PHP 惰性物件建立 PSR 相容的依賴注入容器

DDD
發布: 2025-01-04 09:45:39
原創
188 人瀏覽過

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中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板