laravel5.5 Facade

本文详细解析了Facade模式在Laravel框架中的实现原理,重点介绍了View::make()方法的内部工作流程,包括如何通过别名找到对应的Facade类,以及如何通过容器获取实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Facade原理 以View::make()为例

1.调用View::make()时,会先去config/app.php中的aliases数组中找到实际调用的Facade类。

    'aliases' => [
        //....
        'View' => Illuminate\Support\Facades\View::class,

    ],

2.在Illuminate\Support\Facades\View类中的getFacadeAccessor()方法会返回实际调用的对象的类或者别名。(注:可以返回带有完整命名空间的类名)
此处返回的是绑定在容器中的\Illuminate\View\Factory类的别名:

//in ViewServiceProvider.php
public function register()
{
    $this->registerFactory();

    $this->registerViewFinder();

    $this->registerEngineResolver();
}

/**
 * Register the view environment.
 *
 * @return void
 */
public function registerFactory()
{
    $this->app->singleton('view', function ($app) {
        //...
        return $factory;// \Illuminate\View\Factory
    });
}

3.根据返回的别名,在Facade父类中会去调用容器获取该类的实例(如果还没有实例化的话)。

    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]; //这里application继承的Container类实现了ArrayAccess接口,实际调用的是其中的offsetGet()方法
    }

4.容器得到$name后,由resolve方法获取实例

protected function resolve($abstract, $parameters = [])
    {
        $abstract = $this->getAlias($abstract);//寻找别名,没有返回原值,有的话会根据别名来获取绑定在容器中类的实例。

        $needsContextualBuild = ! empty($parameters) || ! is_null(
            $this->getContextualConcrete($abstract)
        );

        // If an instance of the type is currently being managed as a singleton we'll
        // just return an existing instance instead of instantiating new instances
        // so the developer can keep using the same objects instance every time.
        if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
            return $this->instances[$abstract];
        }

        $this->with[] = $parameters;

        $concrete = $this->getConcrete($abstract);

        // We're ready to instantiate an instance of the concrete type registered for
        // the binding. This will instantiate the types, as well as resolve any of
        // its "nested" dependencies recursively until all have gotten resolved.
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($concrete);
        } else {
            $object = $this->make($concrete);
        }

        // If we defined any extenders for this type, we'll need to spin through them
        // and apply them to the object being built. This allows for the extension
        // of services, such as changing configuration or decorating the object.
        foreach ($this->getExtenders($abstract) as $extender) {
            $object = $extender($object, $this);
        }

        // If the requested type is registered as a singleton we'll want to cache off
        // the instances in "memory" so we can return it later without creating an
        // entirely new instance of an object on each subsequent request for it.
        if ($this->isShared($abstract) && ! $needsContextualBuild) {
            $this->instances[$abstract] = $object;
        }

        $this->fireResolvingCallbacks($abstract, $object);

        // Before returning, we will also set the resolved flag to "true" and pop off
        // the parameter overrides for this build. After those two things are done
        // we will be ready to return back the fully constructed class instance.
        $this->resolved[$abstract] = true;

        array_pop($this->with);

        return $object;
    }

别名(aliases, 通过application的registerCoreContainerAliases()方法设置),
没有绑定该别名则直接根据第三步中的$name实例化。

//注意,别名数组中的值是$class_name(aliases)=>$key的形式
public function registerCoreContainerAliases()
    {
        foreach ([
            //...
            'view'                 => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
        ] as $key => $aliases) {
            foreach ($aliases as $alias) {
                $this->alias($key, $alias);
            }
        }
    }

注意点

  1. 使用时要注意命名空间的问题。
    在config.php中的aliase数组以key=>value的方式记录了Facade的别名和实际调用的Facade类的对应关系。
    如果不是在全局命名空间下使用Facade,需要在别名前加上’\’。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值