wyycc

上次说了provider,那么这次来说说facade

首先是启动的源头,从laravel的kernel类中的$bootstrappers 数组,我们可以看到它的一些系统引导方法,其中的RegisterFacades便是用来注册facade门面类的了。

    protected $bootstrappers = [
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
        \Illuminate\Foundation\Bootstrap\BootProviders::class,
    ];

 

 同样是有一个register类,通过这个类进行别名等注册操作

namespace Illuminate\Foundation\Bootstrap;

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

class RegisterFacades
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        //清除facade所有已绑定实例
        Facade::clearResolvedInstances();
        //将app存入对象
        Facade::setFacadeApplication($app);
        //将这些别名数组通过构造函数存入对象中
        AliasLoader::getInstance(array_merge(
            //通过Illuminate\Config\Repository获取config/app.php中的aliases数组
            $app->make(\'config\')->get(\'app.aliases\', []),
            //还记得最开始的博文中提到的那个包清单吗,这里也从中获取了它的aliases
            $app->make(PackageManifest::class)->aliases()
        //通过spl_autoload_register函数注册另一种自动加载函数
        ))->register();
    }
}
    public static function getInstance(array $aliases = [])
    {
        //注册时的实例是空的,会通过构造方法把刚刚传入的别名数组存入对象
        if (is_null(static::$instance)) {
            return static::$instance = new static($aliases);
        }

        $aliases = array_merge(static::$instance->getAliases(), $aliases);

        static::$instance->setAliases($aliases);

        return static::$instance;
    }

    private function __construct($aliases)
    {
        $this->aliases = $aliases;
    }
    public function register()
    {
        if (! $this->registered) {
            $this->prependToLoaderStack();

            $this->registered = true;
        }
    }

    /**
     * Prepend the load method to the auto-loader stack.
     *
     * @return void
     */
    protected function prependToLoaderStack()
    {
        //最后通过自动加载函数将本对象中的load方法放入自动加载队列的前端,在我们通过类名调用方法时,会触发自动加载函数队列,会优先触发这个函数,查找到对应文件的路径然后加载相应文件
        spl_autoload_register([$this, \'load\'], true, true);
    }
    public function load($alias)
    {
        //若传入的命名空间不为当前facade数组内才会通过这个方法加载
        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);
        }
    }

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

    /**
     * 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;
    }

 由于laravel中composer的执行过程过于繁琐,这里就不做深究了。原理是一样的,通过别名找到命名空间的类名,再由composer的类名与文件路径映射关系,自动加载函数找到相应文件加载进来。

 

那么我们来自定义一个门面类试一下

1、新建一个facade类,这里返回的test是上一篇博客中定义的对象

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class Test extends Facade
{
    protected static function getFacadeAccessor()
    {
        return \'App\Contracts\Test\';
    }
}

2、将它添加到config/app.php的aliases别名数组中

\'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,
        //刚刚新建的facades
        \'Test\' => \App\Facades\Test::class,
    ],

3、在路由文件中调用它

Route::any(\'/index\', function (){
    Test::doing();
});

我们会发现,即使我们没有通过app对象进行make也没有任何命名空间的引入,它就这样被调用了。

如果是在类中调用,那么就要麻烦一些了,需要ues这个别名,注意这一点

namespace App\Http\Controllers;

use Illuminate\Http\Request;
//use App\Contracts\Test;
//注意这里只引入了别名,由于命名空间冲突,所以我注释了其他部分
use Test;

class IndexController extends Controller
{
//    public function __construct(Test $test)
//    {
//        $this->test = $test;
//    }

    public function index(Test $test)
    {
        Test::doing();
//        app()->make(\'App\Contracts\Test\')->doing();
//        echo \'<br>\';
//
//        //只有通过构造方法进行自动加载依赖的方式才能触发契约的when绑定
//        $this->test->doing();
//
//        echo \'<br>\';
//        //因为laravel中的上下文绑定只能具体到类,所以这里的$test实例依然为普通绑定
//        $test->doing();

    }
}

 通过这个demo的实践,facade还是比较简单的。

分类:

技术点:

相关文章:

  • 2021-10-18
  • 2021-12-19
  • 2021-10-18
  • 2021-10-18
  • 2021-07-10
  • 2021-11-15
  • 2021-10-06
猜你喜欢
  • 2021-10-18
  • 2021-10-18
  • 2021-12-29
  • 2021-12-03
  • 2021-11-23
  • 2021-12-28
  • 2021-10-18
相关资源
相似解决方案