読者です 読者をやめる 読者になる 読者になる

Symfony2/SilexのControllerResolverを読む2

ところで、Silex\ControllerResolverにはこんなコードがあるんですがこれは何をやってるんでしょうねえ。

    protected function doGetArguments(Request $request, $controller, array $parameters)
    {
        foreach ($parameters as $param) {
            if ($param->getClass() && $param->getClass()->isInstance($this->app)) {
                $request->attributes->set($param->getName(), $this->app);

                break;
            }
        }

        return parent::doGetArguments($request, $controller, $parameters);
    }

引数の$requestは当然リクエスト、$controllerは通常Silexでは無名関数、$parametersはReflectionFunction#getParameters()の戻り値で、ReflectionParameterの配列です。

http://jp2.php.net/manual/ja/reflectionfunctionabstract.getparameters.php

$param->getClass()->isInstance($this->app)

の部分ですが、ReflectionParameter#getClass()はReflectionClassのインスタンスを返すので、ReflectionClass#isInstance()が呼ばれています。これはこう書き換えることができます。

is_a($this->app, $param->getClass()->getName())

つまり、コントローラの仮引数がApplicationクラスであれば、$request->attributesにセットしている。で、最後にparent::doGetArguments()を呼び出しているということはもしかして、、、
コントローラの仮引数に"Application $app"って書いておけば勝手に渡ってくるってこと!?

つまり実は前回のコードはこれでいいってことか。

<?php
require_once __DIR__.'/../vendor/.composer/autoload.php';

use Silex\Application;

class LeapYearController
{
    function indexAction(Application $app, $year) {
        //...
    }
}

$app = new Application();
$app->get('/is_leap_year/{year}', 'LeapYearController::indexAction');

return $app;

あーこれなら書いてみる気になりますね。よくできてるなーって関心しかけたけどいやいやいやいやちょっと待って。ってことは

$app->get('/hello/{name}', function($name) use($app) { 
    return 'Hello '.$app->escape($name); 
}); 

じゃなくて

$app->get('/hello/{name}', function(Application $app, $name) { 
    return 'Hello '.$app->escape($name); 
}); 

でも良かったってことじゃん!!

まだ続くかも。