laravel5.5门面

Facades为应用程序的 服务容器 中可用的类提供了一个 静态接口

  • 最直观的好处

就是需记住必须手动注入或配置的长长的类名。因此有人也理解Facades就是一个“快捷别名”

怎么变得更快捷呢?

# 使用make 去访问注册日志对象的info方法
$container->make('log')->info('message')

# 使用arrayaccess的方式
$container["log"]->info('message')

# 使用Facade访问Logger对象的info方法, 不需要使用容器去获取一个对象。
Log::info('message');
  • 主要风险

会引起类作用范围的膨胀。因为 Facades 使用起来非常简单而且不需要注入,就会使得我们在不经意间在单个类中使用许多 Facades,从而导致类变的越来越大。
而使用依赖注入的时候,使用的类越多,构造方法就会越长,在视觉上就会引起注意,提醒你这个类有点庞大了。

  • 在laravel中有许多辅助函数的功能都有与之对应的 Facade。

例如,下面这个 Facade 的调用和辅助函数的作用是一样的:

return View::make('profile');

return view('profile');
  • Facades的工作原理

文件位于IlluminateSupportFacades目录下

我们分析Cache 类

<?php

namespace AppHttpControllers;

use IlluminateSupportFacadesCache;
use AppHttpControllersController;

class UserController extends Controller
{
    /**
     * 显示给定用户的信息。
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}

我们打开IlluminateSupportFacadesCache 这个类,你会发现类中根本没有 get 这个静态方法:

<?php

namespace IlluminateSupportFacades;

/**
 * @see IlluminateCacheCacheManager
 * @see IlluminateCacheRepository
 */
class Cache extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'cache';
    }
}

既然没有那么我们去他的父类看看,父类也没有get方法,但是有个魔术方法__callStatic(),当找到不method的时候自动调用这个方法,顺着这个方法继续探究

Facades.php 的核心代码分析

    /**
     * Get the root object behind the facade.
     *
     * @return mixed
     */
    public static function getFacadeRoot()
    {
        //2. 这里调用了getFacadeAccessor() 也就是Cache.php中的这个方法,返回了字符串‘cache’
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }

    /**
     * Get the registered name of the component.
     *
     * @return string
     *
     * @throws RuntimeException
     */
    protected static function getFacadeAccessor()
    {
        throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
    }

    /**
     * Resolve the facade root instance from the container.
     *
     * @param  string|object  $name
     * @return mixed
     */
    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }
        
        // 3. 调用了当前类的静态属性,其实最终获取的就是$app['cache'],那么这个属性是怎么初始化的呢,原来在laravel启动的时候调用了setFacadeApplication()
        
        return static::$resolvedInstance[$name] = static::$app[$name];
    }

    /**
     * Get the application instance behind the facade.
     *
     * @return IlluminateContractsFoundationApplication
     */
    public static function getFacadeApplication()
    {
        return static::$app;
    }

    /**
     * Set the application instance.
     *
     * @param  IlluminateContractsFoundationApplication  $app
     * @return void
     */
    public static function setFacadeApplication($app)
    {
        //
        static::$app = $app;
    }

    /**
     * Handle dynamic, static calls to the object.
     *
     * @param  string  $method
     * @param  array   $args
     * @return mixed
     *
     * @throws RuntimeException
     */
    public static function __callStatic($method, $args)
    {
        //1. 当找不到method的时候,调用__callStatic()
        $instance = static::getFacadeRoot();  
        
        //4. 通过分析返回的$instance就是容器中的$app['cache']实例
        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        //5。 调用上面实例的方法
        return $instance->$method(...$args);
    }

继续分析上面标注4得到的$app['cache'],我们找到IlluminateCacheCacheServiceProvider.php

    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;
        });
    }

会发现绑定了单例,返回了new CacheManager($app)对象,想进一步探究可以查看这个CacheManager类,再次不再继续探究。

通过以上我们其实已经明白了门面的套路。

原文地址:https://www.cnblogs.com/redirect/p/8658702.html