Facades 原理 (程式碼執行流程分析)

mjczz發表於2019-01-05

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)

相關文章