Laravelのソースを読む DB Facade編
環境は下記と同じ
vendor/laravel/framework/src/Illuminate/Support/Facades/DB.php
を読む
<?php
namespace Illuminate\Support\Facades;
class DB extends Facade
{
protected static function getFacadeAccessor()
{
return 'db';
}
}
定義されているメソッドは getFacadeAccessor
のみ。
ここでは db
という文字列を返している。
Facadeクラスを読んでみる。(コードは今回読むところ以外は削除)
<?php
namespace Illuminate\Support\Facades;
abstract class Facade
{
protected static $app;
protected static $resolvedInstance;
protected static $cached = true;
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
protected static function resolveFacadeInstance($name)
{
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
if (static::$app) {
if (static::$cached) {
return static::$resolvedInstance[$name] = static::$app[$name];
}
return static::$app[$name];
}
}
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);
}
}
なんかいろいろメソッドはあるけど、基本的には __callStatic
が呼ばれることになる。
<?php
\Illuminate\Support\Facades\DB::table('tableName')->get();
こんなコードの場合、DBクラスには table
メソッドは定義されていないので、 __callStatic
が呼ばれる。
__callStatic
の中で、 getFacadeRoot
からインスタンスを取得し、table
メソッドを実行している。
resolveFacadeInstance
でコンテナからインスタンスを取得しているっぽい。
getFacadeAccessor
はdb
を返すので、static::$app['db']
が getFacadeRoot
で得られるクラスのようだ。
static::$app
は \Illuminate\Contracts\Foundation\Application
であり、vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterFacades.php
でセットされれているみたい。
static::$app['db']
はvendor/laravel/framework/src/Illuminate/Database/DatabaseServiceProvider.php
でバインドされている。
$this->app->singleton('db', function ($app) {
return new DatabaseManager($app, $app['db.factory']);
});
DatabaseManagerクラスには table
メソッドは定義されていない。
table
メソッドはConnectionクラスに定義してあり、DatabaseManagerクラスの __call
メソッドでConnectionクラスのインスタンスを取得して実行している。
class DatabaseManager implements ConnectionResolverInterface
{
public function __call($method, $parameters)
{
// connection()でConnectionクラスのインスタンスを取得している。
return $this->connection()->$method(...$parameters);
}
}