zoukankan      html  css  js  c++  java
  • laravel5.5源码笔记(三、门面类facade)

    上次说了provider,那么这次来说说facade

    首先是启动的源头,从laravel的kernel类中的$bootstrappers 数组,我们可以看到它的一些系统引导方法,其中的RegisterFacades便是用来注册facade门面类的了。

        protected $bootstrappers = [
            IlluminateFoundationBootstrapLoadEnvironmentVariables::class,
            IlluminateFoundationBootstrapLoadConfiguration::class,
            IlluminateFoundationBootstrapHandleExceptions::class,
            IlluminateFoundationBootstrapRegisterFacades::class,
            IlluminateFoundationBootstrapRegisterProviders::class,
            IlluminateFoundationBootstrapBootProviders::class,
        ];

     同样是有一个register类,通过这个类进行别名等注册操作

    namespace IlluminateFoundationBootstrap;
    
    use IlluminateFoundationAliasLoader;
    use IlluminateSupportFacadesFacade;
    use IlluminateFoundationPackageManifest;
    use IlluminateContractsFoundationApplication;
    
    class RegisterFacades
    {
        /**
         * Bootstrap the given application.
         *
         * @param  IlluminateContractsFoundationApplication  $app
         * @return void
         */
        public function bootstrap(Application $app)
        {
            //清除facade所有已绑定实例
            Facade::clearResolvedInstances();
            //将app存入对象
            Facade::setFacadeApplication($app);
            //将这些别名数组通过构造函数存入对象中
            AliasLoader::getInstance(array_merge(
                //通过IlluminateConfigRepository获取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的类名与文件路径映射关系,自动加载函数找到相应文件加载进来。

    那么我们来自定义一个门面类试一下

    1、新建一个facade类,这里返回的test是上一篇博客中定义的对象

    namespace AppFacades;
    
    use IlluminateSupportFacadesFacade;
    
    class Test extends Facade
    {
        protected static function getFacadeAccessor()
        {
            return 'AppContractsTest';
        }
    }

    2、将它添加到config/app.php的aliases别名数组中

    'aliases' => [
    
            'App' => IlluminateSupportFacadesApp::class,
            'Artisan' => IlluminateSupportFacadesArtisan::class,
            'Auth' => IlluminateSupportFacadesAuth::class,
            'Blade' => IlluminateSupportFacadesBlade::class,
            'Broadcast' => IlluminateSupportFacadesBroadcast::class,
            'Bus' => IlluminateSupportFacadesBus::class,
            'Cache' => IlluminateSupportFacadesCache::class,
            'Config' => IlluminateSupportFacadesConfig::class,
            'Cookie' => IlluminateSupportFacadesCookie::class,
            'Crypt' => IlluminateSupportFacadesCrypt::class,
            'DB' => IlluminateSupportFacadesDB::class,
            'Eloquent' => IlluminateDatabaseEloquentModel::class,
            'Event' => IlluminateSupportFacadesEvent::class,
            'File' => IlluminateSupportFacadesFile::class,
            'Gate' => IlluminateSupportFacadesGate::class,
            'Hash' => IlluminateSupportFacadesHash::class,
            'Lang' => IlluminateSupportFacadesLang::class,
            'Log' => IlluminateSupportFacadesLog::class,
            'Mail' => IlluminateSupportFacadesMail::class,
            'Notification' => IlluminateSupportFacadesNotification::class,
            'Password' => IlluminateSupportFacadesPassword::class,
            'Queue' => IlluminateSupportFacadesQueue::class,
            'Redirect' => IlluminateSupportFacadesRedirect::class,
            'Redis' => IlluminateSupportFacadesRedis::class,
            'Request' => IlluminateSupportFacadesRequest::class,
            'Response' => IlluminateSupportFacadesResponse::class,
            'Route' => IlluminateSupportFacadesRoute::class,
            'Schema' => IlluminateSupportFacadesSchema::class,
            'Session' => IlluminateSupportFacadesSession::class,
            'Storage' => IlluminateSupportFacadesStorage::class,
            'URL' => IlluminateSupportFacadesURL::class,
            'Validator' => IlluminateSupportFacadesValidator::class,
            'View' => IlluminateSupportFacadesView::class,
            //刚刚新建的facades
            'Test' => AppFacadesTest::class,
        ],

    3、在路由文件中调用它

    Route::any('/index', function (){
        Test::doing();
    });

    我们会发现,即使我们没有通过app对象进行make也没有任何命名空间的引入,它就这样被调用了。

    如果是在类中调用,那么就要麻烦一些了,需要ues这个别名,注意这一点

    namespace AppHttpControllers;
    
    use IlluminateHttpRequest;
    //use AppContractsTest;
    //注意这里只引入了别名,由于命名空间冲突,所以我注释了其他部分
    use Test;
    
    class IndexController extends Controller
    {
    //    public function __construct(Test $test)
    //    {
    //        $this->test = $test;
    //    }
    
        public function index(Test $test)
        {
            Test::doing();
    //        app()->make('AppContractsTest')->doing();
    //        echo '<br>';
    //
    //        //只有通过构造方法进行自动加载依赖的方式才能触发契约的when绑定
    //        $this->test->doing();
    //
    //        echo '<br>';
    //        //因为laravel中的上下文绑定只能具体到类,所以这里的$test实例依然为普通绑定
    //        $test->doing();
    
        }
    }

     通过这个demo的实践,facade还是比较简单的。

  • 相关阅读:
    EasyMvc入门教程基本控件说明(6)进度条
    EasyMvc入门教程基本控件说明(3)时间线
    EasyMvc入门教程基本控件说明(4)折叠面板
    EasyMvc入门教程基本控件说明(11)菜单导航
    在一天的24小时之中,时钟的时针、分针和秒针完
    Maven Tutorial
    JXL操作Excel
    Beanutils的基本用法
    利用hibernate分析数据库中的表,属性以及对应的类的类名,字段
    beanutils的一个应用
  • 原文地址:https://www.cnblogs.com/wyycc/p/9888927.html
Copyright © 2011-2022 走看看