在現代 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 類別。有了它,您可以註冊依賴項並延遲初始化它們,這意味著它們僅在實際需要時才實例化。這是執行此任務的主要方法:
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); }
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中文網其他相關文章!