LoginSignup
6

More than 3 years have passed since last update.

CakePHP4.1に導入されるかもしれないDIコンテナ「phpleague/container」を試す

Last updated at Posted at 2019-12-18

本記事は CakePHP Advent Calendar 2019 の19日目のエントリーになります。

はじめに

先日、待ちに待ったCakePHP4.0.0が 正式リリース されましたね :clap:

そして、気が早いのですが4.0系がリリースされたということは、次の大きなアップデートは4.1系のリリースということになります。(本当に気が早くてごめんなさい)

そんなこともあり早速 4.1のロードマップ をチラ見してみたのですが Application の欄に以下のような記述があり、何やら面白そうな変化が起きそうだなと感じました。

日本語に訳すと「PSR11準拠のDIコンテナを試験導入するかも。phpleague/containerというライブラリに可能性を感じてるやで。」といった感じでしょうか。

というわけで、本記事ではCake4.1に導入されるかもしれないDIコンテナライブラリである phpleague/container を試してみたいと思います。

免責事項

  • DIやDIコンテナそのものの説明は行いません。
    • インターネットや書籍に素晴らしい記事や文献があるのでそちらをご参照ください。

インストール

composerでサクッとインストール出来ます。ちなみに、2019年12月時点では3.3.0がインストールされます。

$ composer require league/container

クライアントとサービスクラスの作成

まずはクライアントクラス(オブジェクトが注入されるクラス)とサービスクラス(注入対象となるオブジェクトのクラス)を作成します。よくあるConstructor Injectionです。

basic.php
<?php declare(strict_types=1);

namespace Basic;

class Client
{
    /**
     * @var Service
     */
    public $service;

    /**
     * Constructor Injection
     *
     * @param Service $service
     */
    public function __construct(Service $service)
    {
        $this->service = $service;
    }
}

class Service
{
}

DIコンテナの作成

準備が整ったのでphpleague/containerを利用してDIコンテナを作成します。

basic.php
// DI Container
require 'vendor/autoload.php';

use League\Container\Container;

$container = new Container;

$container->add(Service::class);
$container->add('client_alias', Client::class)->addArgument(Service::class);

$client1 = $container->get('client_alias');
$client2 = $container->get('client_alias');

var_dump($client1 instanceof Client); // true
var_dump($client1->service instanceof Service); // true
var_dump($client1 === $client2); //false

add()メソッドを利用して登録を行い、get()メソッドを利用してインスタンスを取得します。エイリアス名の設定なども簡単に出来ます。

インターフェイスの利用

実際にDIコンテナを利用する時は、インターフェイスを利用して具象クラスを隠蔽することが多いと思いますので、そのパターンも簡単に書いてみたいと思います。

advance.php
<?php declare(strict_types=1);

namespace Advance;

class Client
{
    /**
     * @var ServiceInterface
     */
    public $service;

    /**
     * Constructor Injection
     *
     * @param ServiceInterface $service
     */
    public function __construct(ServiceInterface $service)
    {
        $this->service = $service;
    }
}

interface ServiceInterface
{
}

class CakeService implements ServiceInterface
{
}

class LaravelService implements ServiceInterface
{
}

// DI Container
require 'vendor/autoload.php';

use League\Container\Container;

$container = new Container;

$container->add(ServiceInterface::class, CakeService::class);
$container->add(Client::class)->addArgument(ServiceInterface::class);

$client = $container->get(Client::class);

var_dump($client instanceof Client); // true
var_dump($client->service instanceof ServiceInterface); // true
var_dump($client->service instanceof CakeService); // true
var_dump($client->service instanceof LaravelService); // false

インターフェイスを利用した場合でも同じようにサクッとDIコンテナを作成することが出来ます。

まとめ

数行の記述で簡単に1DIコンテナが実現出来ました。今回は本当に試してみたレベルですが、もう少し深堀りして、CakePHPでこのライブラリがどのように使われるのか想像するのも面白そうです。2ちなみに ドキュメンテーションサイト がかっこよくてテンションが上りました :relaxed:

というわけで、2020年もCakePHPの動向から目が離せません!


  1. 簡単と言いつつドキュメントに書いてあるままやっていたらAutoloadの設定にハマって、作者の方に質問するなどしていました。(即レスで対応してくれて神でした:pray:) 

  2. Issueを細かくWatchしていないので、もしかしたら既に議論されているかもしれません。 

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6