blogPHPでWEB+DBシステムの開発をやっています。特徴として良く挙げられるファサードクラスの仕組みをコードで見てみました。Input::get()やRoute::get()など、クラスメソッドでフレームワークの機能を利用する場面が多くあります。これは一見すると、InputやRouteクラスで提供されているクラスメソッドを実行しているだけに見えますが、これらのクラスにメソッドの実装があるわけではなく、実際はIoCコンテナに格納されているインスタンスのメソッドを実行しています。InputであればIlluminate\Http\Requestクラス、RouteであればIlluminate\Routing\Routerのインスタンスメソッドが実行されます。これらのインスタンスは、IoCコンテナにて管理されており、ファサードクラスのクラスメソッドが実行されると、IoCコンテナから定められたインスタンスを取得して、そのインスタンスメソッドを実行する仕組みになっています。ファサードクラスの利用により、コードの記述がシンプルになります(ここは意見が分かれるところですが)。ファサードクラスでのメソッド呼び出しでは、自身では処理を行わずに、IoCコンテナに格納されたインスタンスなどに委譲します。ファサードクラスが呼び出すインスタンスを差し替えることで実際に処理を行うクラスを変えることができます。ファサードクラスでは、shouldReceive()メソッドにて、テスト時に実行するインスタンスをモックオブジェクトと差し替える機能が標準で用意されています。ファサードクラス実行の流れではRoute::get()を例にして、ファサードクラスがどのように実行されるか見て行きましょう。ファサードクラスの解決まずRouteクラスの解決を行います。実は、Routeクラスは、フレームワークでは定義されていません。Routeクラスのクラスメソッドが実行できるのかというと、class_alias()関数にて、存在するクラスの別名として、Routeを定義するためです。この処理はIlluminate\Foundation\AliasLoaderにて行います。Routeクラスへのアクセスがあると、クラス定義を探すためにオートローダが起動します。オートローダには、Illuminate\Foundation\AliasLoaderとComposerのものが登録されているのですが、はじめにIlluminate\Foundation\AliasLoaderが実行されます。Illuminate\Foundation\AliasLoaderでオートロードを行う箇所が以下です。$this->aliasesに対象のクラス名(ここではRoute)があれば、class_alias()で、クラス別名を設定します。$alias);}}$this->aliasesは、app/config/app.phpで定義しているaliasesキーの内容がセットされています。Routeは、下記のように設定されているため、Illuminate\Support\Facades\Routeへの別名として設定されます。&#039;IlluminateSupportFacadesRoute&#039;,次にIlluminate\Support\Facades\Routeについて、オートロードによる読み込みが行われるので、RouteはIlluminate\Support\Facades\Routeの別名として利用できるようになります。次に、Routeクラスのget()メソッドを実行します。Routeクラス(Illuminate\Support\Facades\Route)を見ると、get()というメソッドは存在しません。Illuminate\Support\Facades\Routeの基底クラスであるIlluminate\Support\Facade\Facadeには、__callStatic()メソッドが定義されているため、このメソッドが呼ばれます。__callStatic()メソッドが下記です。コンテナから処理対象のインスタンスを取得します。static::getFacadeAccessor()を実行して、どのインスタンスを取得するかを決定します。このメソッドは各ファサードクラスで定義されており、Routeクラスの場合は下記のようになっています。ここでは、routerという文字列を返しています。このようにファサードクラスではgetFacadeAccessor()の戻り値で、実行するインスタンスを指定します。}このrouterを引数にresolveFacadeInstance()メソッドを実行して、インスタンスを取得します。resolveFacadeInstance()メソッドの実装は以下です。static::$app[$name];}引数で与えられた$name(ここではrouter)がオブジェクトであれば、そのまま返します。ファサードクラスで解決済ならそのインスタンスを返します。なければ、IoCコンテナからインスタンスを取得して返します。IoCコンテナからインスタンスを取得した場合は、Fasadeクラスのクラス定数$resolvedInstanceにキャッシュされる仕組みになっているので、常に同じインスタンスが利用されます。実行インスタンスを変えたい場合はswap()やclearResolvedInstance()を使うと良いでしょう。インスタンスメソッドの実行で取得したインスタンスについて、指定されたインスタンスメソッド(この場合get())を実行します。ファサードクラスの仕組みを見てきました。構築が良く手順に含まれていますが、実はファサードクラスを作る上ではこれは必須ではありません。利用することが多いだけです。ファサードクラスを自作する際もこうした動きを知っていると作りやすいですね。ファサードパターンとは異なり、IoCコンテナにあるインスタンスを透過的に呼び出す仕組みとなっており、便利なサービスロケータと言った方がイメージしやすいかもしれません。ファサードパターンは違うものだそうです。