【Laravel-海贼王系列】第十二章,Facade 模式解析

栏目: PHP · 发布时间: 5年前

内容简介:我们经常这样使用一些类先看对应的所以调用的时候实际容器会去解析

我们经常这样使用一些类

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Log;

class IndexController extends Controller
{
    public function index()
    {
        Log::info('hahaha~');
    }
}
复制代码

注册别名

先看对应的 Log 类在框架中注册的部分,在 app.php 文件中的别名数组

'aliases' => [
        'App' => Illuminate\Support\Facades\App::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
    ],
复制代码

所以调用的时候实际容器会去解析

lluminate\Support\Facades\Log::class 这个类

我们来看这个类

<?php

namespace Illuminate\Support\Facades;

/**
 * @method static void emergency(string $message, array $context = [])
 * @method static void alert(string $message, array $context = [])
 * @method static void critical(string $message, array $context = [])
 * @method static void error(string $message, array $context = [])
 * @method static void warning(string $message, array $context = [])
 * @method static void notice(string $message, array $context = [])
 * @method static void info(string $message, array $context = [])
 * @method static void debug(string $message, array $context = [])
 * @method static void log($level, string $message, array $context = [])
 * @method static mixed channel(string $channel = null)
 * @method static \Psr\Log\LoggerInterface stack(array $channels, string $channel = null)
 *
 * @see \Illuminate\Log\Logger
 */
class Log extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'log';
    }
}

复制代码

调用分析

最开始我们的调用方法是 Log::info 这里要追踪到父类 Facade 里面

方便阅读精简一些方法

<?php

namespace Illuminate\Support\Facades;

use Closure;
use Mockery;
use RuntimeException;
use Mockery\MockInterface;

abstract class Facade
{
    protected static $app;

    protected static $resolvedInstance;
    
    ...
    
    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);
    }
}

复制代码

这里的调用逻辑是通过 __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);
    }
复制代码

这里也就解释了为什么我们能以静态调用的方式调用对应的方法。

开始分析

$instance = static::getFacadeRoot();
复制代码

看样子是要解析一个实例出来,这里要注意的是

static 调用会指向调用的类,其次才是继承的类。

public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }
复制代码

所以这里的 static::getFacadeAccessor() 实际指向 Log

protected static function getFacadeAccessor()
    {
        return 'log';
    }
复制代码

原来是获取一个别名,那么推测后面就是通过别名从容器拿对象了

继续看看如何拿对象

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];
    }
复制代码

看到这里就知道最主要是 static::$app[$name] 来获取对象

拓展- $app 来自哪里?

但是疑问来了, $app 如果是 Application 对象的话又是在什么地方赋值?

回到内核 Kernel 来看看解答,如何启动请回顾 【Laravel-海贼王系列】第四章,Kernel 类解析handle 方法。

protected $bootstrappers = [
        ...
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
        ...
    ];
复制代码

直接上代码

<?php

namespace Illuminate\Foundation\Bootstrap;

use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Facade;
use Illuminate\Foundation\PackageManifest;
use Illuminate\Contracts\Foundation\Application;

class 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();
    }
}
复制代码

真香~, Facade::setFacadeApplication($app); 在这儿传入的 Application

这里又涉及到了一些问题,那我怎么知道 $app['log'] 里面的对象是谁呢?

拓展-容器的绑定和解析!

哈哈这里去看 【Laravel-海贼王系列】第三章,Container 类解析 ,里面的 bind() 方法就是在容器中绑定抽象和实现的功能,这里也是容器的知识。 这里的 logApplication 在启动的时候提前以及帮我们搞定了~

位于 Application__construct()

public function __construct($basePath = null)
    {
        ...
        $this->registerBaseServiceProviders();
        ...
    }
复制代码
protected function registerBaseServiceProviders()
    {
        ...
        $this->register(new LogServiceProvider($this));
        ...
    }
复制代码
<?php

namespace Illuminate\Log;

use Illuminate\Support\ServiceProvider;

class LogServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton('log', function () {
            return new LogManager($this->app);
        });
    }
}
复制代码

最后就看到了真正的对象 return new LogManager($this->app);


以上所述就是小编给大家介绍的《【Laravel-海贼王系列】第十二章,Facade 模式解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

超简单!一学就懂的互联网金融

超简单!一学就懂的互联网金融

视觉图文 / 人民邮电出版社 / 2015-2-1 / 45.00元

零基础、全图解,通过130多个精辟的知识点、220多张通俗易懂的逻辑图表,让您一书在手,即可彻底看懂、玩转互联网金融从菜鸟成为达人,从新手成为互联网金融高手! 本书主要特色:最简洁的版式+最直观的图解+最实用的内容。 本书细节特色:10章专题内容详解+80多个特别提醒奉献+130多个知识点讲解+220多张图片全程图解,深度剖析互联网金融的精华之处,帮助读者在最短的时间内掌握互联网金融知......一起来看看 《超简单!一学就懂的互联网金融》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具