[Laravel 5.4] 新功能: 實時 Facade

milkmeowo發表於2017-01-17

概述

Taylor Otwell 昨天發了一條推,Laravel 5.4估計很快就要來了

file

即將到來的Laravel5.4,讓我最激動的一個新功能應該是,實時Facades

file

如果你對 Laravel Facades 還不熟悉,點選這裡學習 Facades


例子

安裝laravel 5.4

使用laravel-installer,使用--dev引數拿到開發版

laravel new laravel54 --dev

新建一個類

我在App目錄下建立了Milkmeowo.php

namespace App;

class Milkmeowo
{

    public function meow()
    {
        return 'cat meow';
    }
}

讓 Facade 飛起來

php 版本小於7

use Facades\App\Milkmeowo;

php 版本 7 以上可以使用 Group use declarations

use Facades\ {
    App\Milkmeowo
};

在任何你需要用到的地方,這裡我在路由檔案

// pre php 7
//use Facades\App\Milkmeowo;

// php 7+
use Facades\ {
    App\Milkmeowo
};

Route::get('/meow', function () {
    return Milkmeowo::meow();
});

就可以看到

file

超級方便有木有

所以在laravel5.4中任何類都可以像Facede那樣飛起來了,但注意

千萬不要使用過渡


實時Facade實現原理

本文預設你已經熟悉Facade,本文主要講實時 Facade的實現原理,有關Facade的具體載入原理,不在本文討論範圍之內

相信大部分人都知道Facade是通過class_alias來是實現的,通過Illuminate/Foundation/AliasLoader.php進行載入

實時Facade 就是改進了load方法

    /**
     * The namespace for all real-time facades.
     *
     * @var string
     */
    protected static $facadeNamespace = 'Facades\\';

    /**
     * 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])) {
            return class_alias($this->aliases[$alias], $alias);
        }
    }

可以看到

        if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
            $this->loadFacade($alias);

            return true;
        }

實時Facade 判斷alias是否在static::$facadeNamespace名稱空間下,如果是那麼就呼叫loadFacade方法實時載入Facade

    /**
     * Load a real-time facade for the given alias.
     *
     * @param  string  $alias
     * @return bool
     */
    protected function loadFacade($alias)
    {
        tap($this->ensureFacadeExists($alias), function ($path) {
            require $path;
        });
    }

    /**
     * Ensure that the given alias has an existing real-time facade class.
     *
     * @param  string  $alias
     * @return string
     */
    protected function ensureFacadeExists($alias)
    {
        if (file_exists($path = storage_path('framework/cache/facade-'.sha1($alias).'.php'))) {
            return $path;
        }

        file_put_contents($path, $this->formatFacadeStub(
            $alias, file_get_contents(__DIR__.'/stubs/facade.stub')
        ));

        return $path;
    }

            /**
     * Format the facade stub with the proper namespace and class.
     *
     * @param  string  $alias
     * @param  string  $stub
     * @return string
     */
    protected function formatFacadeStub($alias, $stub)
    {
        $replacements = [
            str_replace('/', '\\', dirname(str_replace('\\', '/', $alias))),
            class_basename($alias),
            substr($alias, strlen(static::$facadeNamespace)),
        ];

        return str_replace(
            ['DummyNamespace', 'DummyClass', 'DummyTarget'], $replacements, $stub
        );
    }

loadFacade方法中,通過ensureFacadeExists去查詢動態生成的Facade快取檔案,如果存在則返回路徑

例如本例中Facades\App\Milkmeowo,sha1得到下面hash

>>> sha1('Facades\App\Milkmeowo')
=> "c84beaca684289727906d76c85df52fd1de7cdbe"

實時facade會在framework/cache目錄中生成了facade-c84beaca684289727906d76c85df52fd1de7cdbe.php檔案

<?php

namespace Facades\App;

use Illuminate\Support\Facades\Facade;

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

可以看到這個檔案是標準的Facede檔案

然後通過loadFacade require這個檔案

        tap($this->ensureFacadeExists($alias), function ($path) {
            require $path;
        });

以上就是實時Facade的實現過程,實際上就是一個動態去生成Facade模版的方法


總結

  • 要想實時Facade,只需要在你的類的名稱空間前面加上Facades\就好了

use Facades\你的類的名稱空間

  • 使用時會生成cache檔案

  • 千萬不要覺得方便了濫用,你試想一下你維護或者debug的時候

方便了超多有木有!

相關文章