Lumen 5創建Facade類

Laravel的Facade,實際上是對service container中的service provider的一層包裝,使用魔術方法__callStatic調用service provider類的方法。拿Log Facade來探究一下。

<?php

namespace Illuminate\Support\Facades;

/**
 * @see \Illuminate\Log\Writer
 */
class Log extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'log';
    }
}

Facade類只需要重寫父類中的getFacadeAccessor方法,返回一個字符串即可。
返回的log代表什麼,有什麼用?

到框架的service container裏看個究竟

<?php

namespace Laravel\Lumen;

use Monolog\Logger;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Composer;
use Monolog\Handler\StreamHandler;
use Illuminate\Container\Container;
use Monolog\Formatter\LineFormatter;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Facade;
use Illuminate\Support\ServiceProvider;
use Zend\Diactoros\Response as PsrResponse;
use Illuminate\Config\Repository as ConfigRepository;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;

class Application extends Container
{
    /**
     * Register the core container aliases.
     *
     * @return void
     */
    protected function registerContainerAliases()
    {
        $this->aliases = [
            'Illuminate\Contracts\Foundation\Application' => 'app',
            'Illuminate\Contracts\Auth\Factory' => 'auth',
            'Illuminate\Contracts\Auth\Guard' => 'auth.driver',
            'Illuminate\Contracts\Cache\Factory' => 'cache',
            'Illuminate\Contracts\Cache\Repository' => 'cache.store',
            'Illuminate\Contracts\Config\Repository' => 'config',
            'Illuminate\Container\Container' => 'app',
            'Illuminate\Contracts\Container\Container' => 'app',
            'Illuminate\Database\ConnectionResolverInterface' => 'db',
            'Illuminate\Database\DatabaseManager' => 'db',
            'Illuminate\Contracts\Encryption\Encrypter' => 'encrypter',
            'Illuminate\Contracts\Events\Dispatcher' => 'events',
            'Illuminate\Contracts\Hashing\Hasher' => 'hash',
            'log' => 'Psr\Log\LoggerInterface',    // 重點在這裏
            'Illuminate\Contracts\Queue\Factory' => 'queue',
            'Illuminate\Contracts\Queue\Queue' => 'queue.connection',
            'request' => 'Illuminate\Http\Request',
            'Laravel\Lumen\Routing\UrlGenerator' => 'url',
            'Illuminate\Contracts\View\Factory' => 'view',
        ];
    }

    /**
     * Register container bindings for the application.
     *
     * @return void
     */
    protected function registerLogBindings()
    {
        $this->singleton('Psr\Log\LoggerInterface', function () {
            if ($this->monologConfigurator) {
                return call_user_func($this->monologConfigurator, new Logger('lumen'));
            } else {
                return new Logger('lumen', [$this->getMonologHandler()]);
            }
        });
    }
}

當我們調用Log::info時,實際上調用的是Psr\Log\LoggerInterface的info方法,Psr\Log\LoggerInterface可以看做Log的代理,Log有需要時,轉發給代理,由代理決定具體的執行。有了Facade,代碼可讀性更高,不需要解具體的內部實現。

進一步說

Log::info()
// 等同於
app('log')->info()  // app('log')創建了什麼?請看Application::registerLogBindings

開始創建一個Facade

第一步,實現一個service provider

代碼大致如下

<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Http\Request;
use App\Logger;

/**
 * Class LogServiceProvider
 * @package App\Providers
 */
class LogServiceProvider extends ServiceProvider
{

    public function register()
    {
        // TODO: Implement register() method.
        $this->app->singleton('mylog', function($app) {
            return new Logger();
        });
    }

}

第二步,註冊service provider

在bootstrap/app.php文件添加代碼

$app->register(App\Providers\LogServiceProvider::class);

第三步,創建Facade類

<?php
namespace App\Library\Facade;

use Illuminate\Support\Facades\Facade;

class Mylog extends Facade
{
    public static function getFacadeAccessor()
    {
        return 'mylog';
    }
}

就是這麼簡單。

容易看出,Facade類帶來了好處,也帶來了壞處,比如:PHPStorm的代碼跟蹤就拿Facade無能爲力了。

關於Laravel 5 Service container與service provider,可以參考
Laravel5 container & service provider

發佈了52 篇原創文章 · 獲贊 12 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章