最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Laravel Facade加载以及原理

    正文概述 转载于:掘金(Rocket)   2021-06-09   449

    Hello,我是Rocket

    这是我参与更文挑战的第4天,活动详情查看:更文挑战

    • 知识是自己的,不要畏惧去看源码,因为它比你想象的更简单
    • 今天带着大家来揭开Laravel Facade神秘的面纱,从他启动注册,到解析加载一点点
    • 学完估计你会想我曹原来这么简单,其实是你想复杂了
    • 动态facede感觉有点多余,有那功夫写个命令生成Facade

    1、Facade 是什么

    LaravelFacade 是典型的静态代理模式,他可以让你以静态的方式来调用存放在容器中任何对象的任何方法

    2、Facade 启动和注册

    Facade 的启动引导是在 Illuminate\Foundation\Bootstrap\RegisterFacades 中注册的

     public function bootstrap(Application $app)
     {
            Facade::clearResolvedInstances();
    
            Facade::setFacadeApplication($app);
    
            AliasLoader::getInstance(array_merge(
                $app->make('config')->get('app.aliases', []),
                $app->make(PackageManifest::class)->aliases()
            ))->register();
    }
    

    默认的别名配置是从 app 配置文件下的 aliases 读取的,PackageManifest 是 laravel 5.5 新增的 包自动发现 规则,这里我们暂时不考虑 PackageManifest 包提供的别名。

    public function register()
        {
            if (! $this->registered) {
                $this->prependToLoaderStack();
    
                $this->registered = true;
            }
        }
        
    protected function prependToLoaderStack()
        {
            spl_autoload_register([$this, 'load'], true, true);
        }
    

    通过Illuminate\Foundation\AliasLoader把所有的facade注册进自动加载,基于phpspl_autoload_register 注册完成后,后续所有 use 的类都将通过 load 函数来完成类的自动加载。并且优先走load方法

    3、如何定义Facade

    需要继承Illuminate\Support\Facades\Facade类,并实现getFacadeAccessor静态方法

    use Illuminate\Support\Facades\Facade;
    
    class Cache extends Facade
    {
        /**
         * 获取组件注册名称
         *
         * @return string
         */
        protected static function getFacadeAccessor() { 
            return 'cache'; 
        }
    }
    

    4、Facade 是如何实现的

    我们平时调用facade总会发现这个类其实是没有对应的方法的,那么facade是怎么找到具体的实现类

    <?php
    
    use Illuminate\Support\Facades\Config;
    
    class Test
    {
        public function index()
        {
            Config::get('app.name');
        }
    }
    
    
    

    所有的Facade都是基于Illuminate\Support\Facades\Facade类,在该基类中定义了一个 __callStatic 方法,已至于我们能够轻松地使用 Facade(不用实列化)。

    abstract class Facade
    {
        public static function getFacadeRoot()
        {
            
            return static::resolveFacadeInstance(static::getFacadeAccessor());
        }
        
        //static::getFacadeAccessor() 被子类重写
        protected static function getFacadeAccessor()
        {
            throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
        }
    
        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];
        }
        //php的魔术方法
        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);
        }
    }
    

    static::$app[$name] 大家可能好奇怎么能把对象当数组取值呢?实际上app继承了Illuminate\Container\ContainerIOC容器,同时容器还实现了PHP的ArrayAccessstatic::$app[$name]这种方式等同于app->make($name)

    5、动态Facade实现的原理

    public function load($alias)
        {
            //检测到命名空间包含 Facades\\
            if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
                //这块是实现动态Facade的关键
                $this->loadFacade($alias);
    
                return true;
            }
    
            if (isset($this->aliases[$alias])) {
                //注册类别名
                return class_alias($this->aliases[$alias], $alias);
            }
        }
    
    protected function loadFacade($alias)
        {
            require $this->ensureFacadeExists($alias);
        }
        
    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;
        }
    

    6、结尾

    与诸君共勉之,希望对您有所帮助
    

    起源地下载网 » Laravel Facade加载以及原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元