[Laravel 5.4] 新功能: 实时 Facade
概述
Taylor Otwell 昨天发了一条推,Laravel 5.4估计很快就要来了
即将到来的Laravel5.4,让我最激动的一个新功能应该是,实时Facades
如果你对 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();
});
就可以看到
超级方便有木有
所以在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的时候
方便了超多有木有!
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: