[Laravel] ファサードの実行順序を追っかけてみた。

ITLaravel, PHP

Laravel で開発していると、「ファサード」という単語をよく耳にすると思いますが、実際どう動いているのか追ってみました。

今回は例として、Auth::user() にしました。

https://readouble.com/laravel/5.5/ja/authentication.html

ここで use している Auth クラスにクラスメソッド user があるのかと思っていたら、、、ありません。

/Illuminate/Support/Facades/Auth.php

make('router')->auth();
    }
}

継承元の Facade 抽象クラスにもなく、、、以前に

「Laravel のファサードは __callStatic を使っているから、XXX」

と、聞いたことがあったので、__callStatic を調べると

__callStatic() は、 アクセス不能メソッドを静的コンテキストで実行したときに起動します。

引用元:http://php.net/manual/ja/language.oop5.overloading.php#object.callstatic

アクセス不能メソッド(クラスメソッドが実行された時にそのメソッドがない時に)呼び出される

というちょっと敗戦処理的な感じのメソッドのようです。getFacadeRoot メソッドを実行してます。

Illuminate/Support/Facades/Facade.php

/**
 * Handle dynamic, static calls to the object.
 *
 * @param  string  $method
 * @param  array   $args
 * @return mixed
 *
 * @throws \RuntimeException
 */
public static function __callStatic($method, $args)
{
    $instance = static::getFacadeRoot();

    if (! $instance) {
        throw new RuntimeException('A facade root has not been set.');
    }

    return $instance->$method(...$args);
}

getFacadeRoot メソッドは例外しか書いてないで、また「あれ?」と思ったら

Illuminate/Support/Facades/Facade.php

/**
 * Get the root object behind the facade.
 *
 * @return mixed
 */
public static function getFacadeRoot()
{
    return static::resolveFacadeInstance(static::getFacadeAccessor());
}

/**
 * Get the registered name of the component.
 *
 * @return string
 *
 * @throws \RuntimeException
 */
protected static function getFacadeAccessor()
{
    throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}

Auth クラスでオーバーライドしていました。ややこしい。

Illuminate/Support/Facades/Auth.php

/**
 * Get the registered name of the component.
 *
 * @return string
 */
protected static function getFacadeAccessor()
{
    return 'auth';
}

resolveFacadeInstance メソッドで static::$app[$name] すなわち static::$app[‘auth’] を返してるので、サービスコンテナで auth を解決してるインスタンス を取得してますね。

ということは、Laravel の Facade って、クラスメソッドと見せかけて、サービスコンテナに登録されてるインスタンス使ってたんかい、というオチになりました。

/**
 * Resolve the facade root instance from the container.
 *
 * @param  string|object  $name
 * @return mixed
 */
protected static function resolveFacadeInstance($name)
{
    if (is_object($name)) {
        return $name;
    }

    if (isset(static::$resolvedInstance[$name])) {
        return static::$resolvedInstance[$name];
    }

    return static::$resolvedInstance[$name] = static::$app[$name];
}

ひとこと

なんでこんなまわりくどいことしてるのか、腑に落ちてない(クラスメソッドじゃだめなんですかね?)ので、引き続き勉強&調査を進めます。

スポンサーリンク

Posted by nobuhiro harada