ホームページ > バックエンド開発 > PHPチュートリアル > PHP Lazy オブジェクトを使用した PSR 互換の依存関係注入コンテナーの構築

PHP Lazy オブジェクトを使用した PSR 互換の依存関係注入コンテナーの構築

DDD
リリース: 2025-01-04 09:45:39
オリジナル
243 人が閲覧しました

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

PHP 8.4 での Lazy オブジェクトによる依存関係の注入の探索

最新の PHP の領域では、バージョン 8.4 のリリースで画期的な機能である Lazy Objects が導入されました。これらのオブジェクトにより、絶対に必要になるまで初期化を延期する新しい方法が可能になり、パフォーマンスが向上し、リソースの使用量が削減されます。この機能は、Lazy Objects の Lazy Initialization RFC で概要が説明されているように、ReflectionClass API の機能強化を通じて言語に深く統合されています。

RFC の例
Lazy Objects の可能性を説明するために、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 に触発されて、私は最適なパフォーマンスを実現するために Lazy Objects API を活用して、PSR-11 互換の依存関係注入コンテナーの構築に着手しました。

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 の追加の利点は、依存関係注入コンテナーの PHP 標準である PSR-11 との互換性です。これにより、仕様に準拠したライブラリやフレームワークとの相互運用性が保証され、軽量で汎用的なソリューションになります。

他のコンテナとの性能比較

コンテナのパフォーマンスを測定するために、制御された環境で 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 とその Lazy オブジェクトは、依存関係の注入を簡素化し、最適化する新しい可能性を開きました。私たちの ContainerLazyObject は、軽量、効率的、柔軟であることに加えて、PSR-11 に準拠しており、他のライブラリやフレームワークとの相互運用性を保証しています。

このアプローチを試して、次のプロジェクトで依存関係の管理がどのように簡素化されるかを確認してください。

以上がPHP Lazy オブジェクトを使用した PSR 互換の依存関係注入コンテナーの構築の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート