上次說了provider,那麼此次來講說facadephp
首先是啓動的源頭,從laravel的kernel類中的$bootstrappers 數組,咱們能夠看到它的一些系統引導方法,其中的RegisterFacades即是用來註冊facade門面類的了。前端
protected $bootstrappers = [ \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, \Illuminate\Foundation\Bootstrap\HandleExceptions::class, \Illuminate\Foundation\Bootstrap\RegisterFacades::class, \Illuminate\Foundation\Bootstrap\RegisterProviders::class, \Illuminate\Foundation\Bootstrap\BootProviders::class, ];
一樣是有一個register類,經過這個類進行別名等註冊操做laravel
namespace Illuminate\Foundation\Bootstrap; use Illuminate\Foundation\AliasLoader; use Illuminate\Support\Facades\Facade; use Illuminate\Foundation\PackageManifest; use Illuminate\Contracts\Foundation\Application; class RegisterFacades { /** * Bootstrap the given application. * * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function bootstrap(Application $app) { //清除facade全部已綁定實例 Facade::clearResolvedInstances(); //將app存入對象 Facade::setFacadeApplication($app); //將這些別名數組經過構造函數存入對象中 AliasLoader::getInstance(array_merge( //經過Illuminate\Config\Repository獲取config/app.php中的aliases數組 $app->make('config')->get('app.aliases', []), //還記得最開始的博文中提到的那個包清單嗎,這裏也從中獲取了它的aliases $app->make(PackageManifest::class)->aliases() //經過spl_autoload_register函數註冊另外一種自動加載函數 ))->register(); } }
public static function getInstance(array $aliases = []) { //註冊時的實例是空的,會經過構造方法把剛剛傳入的別名數組存入對象 if (is_null(static::$instance)) { return static::$instance = new static($aliases); } $aliases = array_merge(static::$instance->getAliases(), $aliases); static::$instance->setAliases($aliases); return static::$instance; } private function __construct($aliases) { $this->aliases = $aliases; }
public function register() { if (! $this->registered) { $this->prependToLoaderStack(); $this->registered = true; } } /** * Prepend the load method to the auto-loader stack. * * @return void */ protected function prependToLoaderStack() { //最後經過自動加載函數將本對象中的load方法放入自動加載隊列的前端,在咱們經過類名調用方法時,會觸發自動加載函數隊列,會優先觸發這個函數,查找到對應文件的路徑而後加載相應文件 spl_autoload_register([$this, 'load'], true, true); }
public function load($alias) { //若傳入的命名空間不爲當前facade數組內纔會經過這個方法加載 if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) { $this->loadFacade($alias); return true; } //不然直接返回其別名 if (isset($this->aliases[$alias])) { return class_alias($this->aliases[$alias], $alias); } } /** * Load a real-time facade for the given alias. * * @param string $alias * @return void */ protected function loadFacade($alias) { require $this->ensureFacadeExists($alias); } /** * Ensure that the given alias has an existing real-time facade class. * * @param string $alias * @return string */ protected function ensureFacadeExists($alias) { //從緩存中返回路徑 if (file_exists($path = storage_path('framework/cache/facade-'.sha1($alias).'.php'))) { return $path; } file_put_contents($path, $this->formatFacadeStub( $alias, file_get_contents(__DIR__.'/stubs/facade.stub') )); return $path; }
因爲laravel中composer的執行過程過於繁瑣,這裏就不作深究了。原理是同樣的,經過別名找到命名空間的類名,再由composer的類名與文件路徑映射關係,自動加載函數找到相應文件加載進來。bootstrap
那麼咱們來自定義一個門面類試一下數組
一、新建一個facade類,這裏返回的test是上一篇博客中定義的對象緩存
namespace App\Facades; use Illuminate\Support\Facades\Facade; class Test extends Facade { protected static function getFacadeAccessor() { return 'App\Contracts\Test'; } }
二、將它添加到config/app.php的aliases別名數組中app
'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, //剛剛新建的facades 'Test' => \App\Facades\Test::class, ],
三、在路由文件中調用它composer
Route::any('/index', function (){ Test::doing(); });
咱們會發現,即便咱們沒有經過app對象進行make也沒有任何命名空間的引入,它就這樣被調用了。ide
若是是在類中調用,那麼就要麻煩一些了,須要ues這個別名,注意這一點函數
namespace App\Http\Controllers; use Illuminate\Http\Request; //use App\Contracts\Test; //注意這裏只引入了別名,因爲命名空間衝突,因此我註釋了其餘部分 use Test; class IndexController extends Controller { // public function __construct(Test $test) // { // $this->test = $test; // } public function index(Test $test) { Test::doing(); // app()->make('App\Contracts\Test')->doing(); // echo '<br>'; // // //只有經過構造方法進行自動加載依賴的方式才能觸發契約的when綁定 // $this->test->doing(); // // echo '<br>'; // //由於laravel中的上下文綁定只能具體到類,因此這裏的$test實例依然爲普通綁定 // $test->doing(); } }
經過這個demo的實踐,facade仍是比較簡單的。