[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 协议》,转载必须注明作者和本文链接
@Summer 专栏的markdown语法支持有问题?不能使用
#
进行标题标记?没法渲染出来呀...赞,学习了
@milkmeowo 单个
#
的话,直接对应于 H1。一般情况下一个页面只有一个 H1 哦,那就是这篇文章的标题。
H2 是才是用来做段落区分。
推荐看下这个:http://baike.baidu.com/view/5362315.htm
另外,很棒的文章分享,今早上还在想什么时候能出 5.4 :smile: :+1:
5.4会是LTS吗?:flushed:
@quericy 按照官方计划 5.5 才是LTS
参考阅读
Laravel 更新了发布周期计划
Laravel 的发布路线图
没想到有什么具体使用的场景,解决什么问题
@leo 我暂时想到的是解决依赖问题,方便使用,因为facade其实还是通过容器make出来,有时候想单纯使用某个方法,但又不想去解决依赖问题,可能就用得上了。
说实在我也没对应的上实际业务中有什么场景适合。不知道各位大大有什么见解
@milkmeowo 基本同意你的看法。我对于 Facade 的理解比较粗浅,就是当它为传统的静态工具类使用,以便于代码的重用。
@milkmeowo 感觉鸡肋,如果想要make一个类直接
app(CLASS::class)
即可,比这个facade快多了@leo 我也没找到实际场合,感觉我们都没法理解作者的意图
刚翻了一下,找到这句,但我表示理解不能,求解
@milkmeowo 我的理解是 Taylor 可能想
new App\User(new someDependency())
当User
又依赖于某些类时,想要更简单的语法,直接new User
。没有实时 Facade 时的做法可能是把 User 先绑定到容器里面,然后再从容器解析出来自动 resolve 依赖。有实时 Facade 后就能自动为 User 生成 Facade,并从容器中解决依赖。方便很多。@leo 我也感觉这种方法很比实时 Facade 来的直接
看起来尽量少用这个功能啊....影响OO设计