[PHP]Slim3では、なぜget()メソッドの中で$thisでDIコンテナが取得できるか?

カテゴリ: SlimFramework

PHPのSlim3 Frameworkでは、以下のようなコードでgetリクエストが走った時のコールバック処理内で、DIコンテナへアクセスすることができます。

$app = new \Slim\App();

// myServiceをDIコンテナを取得
$container = $app->getContainer();
$container['myService'] = function ($container) {
    $myService = new MyService();
    return $myService;
};

$app->get('/foo', function ($req, $res, $args) {
    // DIコンテナからオブジェクトを取得
    //   (下記のコードは、$this->myService;とも書ける)
    $myService = $this->get('myService');        // なぜか、$thisでDIコンテナが取得できる!?
    ...
});

この中で不思議なのは、コールバック関数内で$thisでDIコンテナが取得できることです。

このコードで$thisがDIコンテナであることは、下記のコードで確認できます。

$app->get('/foo', function ($req, $res, $args) {
    echo get_class($this);  // "Slim\Container" が出力される
    ...
});

$thisがDIコンテナになる仕組み

仕組みは、get()メソッドの中身を追っていくとわかります。

実際にget()メソッドの中身を見ると、そのままmap()メソッドに処理を委譲しています。

# vendor\slim\slim\Slim\App.php
namespace Slim;
...

class App
{
    ...

    public function get($pattern, $callable)
    {
        return $this->map(['GET'], $pattern, $callable);
    }

で、map()メソッドを見ると以下のような実装になっています。

    public function map(array $methods, $pattern, $callable)
    {
        if ($callable instanceof Closure) {
            $callable = $callable->bindTo($this->container);
        }

        $route = $this->container->get('router')->map($methods, $pattern, $callable);
        if (is_callable([$route, 'setContainer'])) {
            $route->setContainer($this->container);
        }

        if (is_callable([$route, 'setOutputBuffering'])) {
            $route->setOutputBuffering($this->container->get('settings')['outputBuffering']);
        }

        return $route;
    }

この中で注目すべきは、下記の行です。

$callable = $callable->bindTo($this->container);

PHPでは無名関数は、Closureクラスのインスタンスとして実装されています。ClosureクラスにはbindTo()メソッドが用意されており、bindTo()のパラメータで渡されたオブジェクトを$thisオブジェクトとみなすことができるという仕組みなっています。

Slim3 FrameworkではこのbindTo()メソッドの仕組みを利用して、$thisがDIコンテナであるかのように見なしているわけです。

こちらもおススメ

コメントを残す

メールアドレスが公開されることはありません。