Facades 原理 (代码执行流程分析)

Facades原理

Laravel IOC Container总是bind(singleton)进去类,make出类的实例对象

通过Facades可以解析出类的对象,并调用类的方法,其实质也是调用了make方法解析出类的对象

  • 通过这一行简单的代码,我们没有use Cache这个类,却可以使用Cache
    // 注意Cache前加\
    \Cache::set('czz','18',60);
    dd(\Cache::get('czz'));

代码执行流程解析

1 使用Cache类,实际是调用了config/app.php中 aliases数组中的Illuminate\Support\Facades\Cache;

 /**
     * Prepend the load method to the auto-loader stack.
     *
     * @return void
     */
    protected function prependToLoaderStack()
    {
        // 把AliasLoader::load()放入自动加载函数队列中,并置于队列头部
        // 调用\Cache,实际是执行了这个方法,为Illuminate\Support\Facades\Cache注册别名Cache
        spl_autoload_register([$this, 'load'], true, true);
    }
     /**
     * Load a class alias if it is registered.
     *
     * @param  string  $alias
     * @return bool|null
     */
    public function load($alias)
    {
        if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
            $this->loadFacade($alias);

            return true;
        }

        if (isset($this->aliases[$alias])) {
            // 为Illuminate\Support\Facades\Cache注册别名Cache
            return class_alias($this->aliases[$alias], $alias);
        }
    }
'Cache' => Illuminate\Support\Facades\Cache::class,

2 进入Illuminate\Support\Facades\Cache类,发现没有set方法和get方法,调用父类的魔术方法__callStatic,从容器中解析出类的实例对象;

  • 魔术方法__callStatic
  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);
    }
  • 解析
   /**
     * Get the root object behind the facade.
     *
     * @return mixed
     */
    public static function getFacadeRoot()
    {
        //  相当于执行的是return static::resolveFacadeInstance("cache);
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }
  • 从容器中解析出类的对象
   protected static function resolveFacadeInstance($name)
    {
        // $name = ‘cache’;
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        return static::$resolvedInstance[$name] = static::$app[$name];
    }
  • $app是容器对象,因为实现了ArrayAccess接口,所以,最终调用的还是容器的make方法
public function offsetGet($key)
{
    // $key = "cache";
    return $this->make($key);
}

3 执行对象的方法get或者set..

$instance->$method(...$args)
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1

$this->make($key); 这个在哪个文件调用的?

public function offsetGet($key)
{
    // $key = "cache";
    return $this->make($key);
}

找到了文件 laravel\vendor\laravel\framework\src\Illuminate\Container\Container.php

/**
     * Resolve the given type from the container.
     *
     * @param  string  $abstract
     * @param  array  $parameters
     * @return mixed
     */
    public function make($abstract, array $parameters = [])
    {
        return $this->resolve($abstract, $parameters);
    }

laravel\vendor\laravel\framework\src\Illuminate\Cache\CacheServiceProvider.php 这个文件定义了 cache

/**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('cache', function ($app) {
            return new CacheManager($app);
        });

        $this->app->singleton('cache.store', function ($app) {
            return $app['cache']->driver();
        });

        $this->app->singleton('memcached.connector', function () {
            return new MemcachedConnector;
        });
    }
5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!