小艾的自留地

Stay foolish, Stay hungry

在实际开发中,如果想扩展一个基础类,通常的做法是先继承该类,然后在此基础上进行扩展。

而本文要介绍的宏指令,是Laravel 根据PHP 的特性,编写了一套叫做 MacroableTraits,可以在不使用继承的情况下进行扩展。

如何使用

定义一个宏指令:

1
2
3
4
5
6
<?php
use Illuminate\Http\Request;

Request::macro("sayHi", function ($name) {
echo "Hi " . $name . "!";
});

使用它:

1
2
3
4
5
<?php
<?php
use Illuminate\Http\Request;

Request::sayHi("Boo"); // Hi Boo!

上面那个例子非常简单,再来看一个复杂一些的,将集合的数组全部转换为大写:

1
2
3
4
5
6
7
8
9
10
11
<?php
use Illuminate\Support\Collection;

Collection::macro('uppercase', function () {
// $this->items 就相当于是集合的所有元素 ["hello", "world"]
return collect($this->items)->map(function ($item) {
return strtoupper($item);
});
});

collect(["hello", "world"])->uppercase(); // ["HELLO", "WORLD"]

关于Macro 的$this

这里有必要说一下$this 的指向,在上面那个集合的示例中,$this 并不是指向当前类,而是指向当前集合。

这是因为在 Marcoable 的源代码中,是可以看到 static::$macros[$method]->bindTo($this, static::class) 这段代码。而 bindTo 是改变 $this 上下文指向的方法。

应该放在哪里

有两个地方可以用来存放有关宏指令的代码,分别是:

利用composer 自动加载

第一种是使用通过 Composer autoload 的简单 PHP 文件。

可以在app 目录下新建一个叫做macros.php 的文件,然后编辑 composer.json 添加一个 files属性(注意相对路径 app/macros.php):

1
2
3
4
5
6
7
8
9
10
11
12
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
],
"files": [
"app/macros.php"
]
}

最后运行 composer dump-autoloader

这样新添加的文件将在运行时加载和执行,整个应用都可以使用其中的宏指令。

利用服务提供者

创建一个 ServiceProvider,并注册在config/app.php 中,

比如创建一个集合的服务提供者,加入boot 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
namespace App\Providers;

use Collection;
use Illuminate\Support\ServiceProvider;

class CollectionMacroServiceProvider extends ServiceProvider {

public function boot()
{
Collection::macro('uppercase', function () {
return collect($this->items)->map(function ($item) {
return strtoupper($item);
});
});
}
}

这样,整个应用就都可以访问到了。

有哪些类可以使用Macro

任何使用 Macroable Laravel 框架中的Traits 的类都可以使用宏,比如:

  • Collection
  • Builder
  • Response
  • Rule
  • Request
  • Route
  • HTML
  • Form
  • Filesystem
  • Cache
  • Str
  • Arr
  • Translator

Macro 是Laravel 中又一强大而被忽视的存在,合理地使用Macro 以实现更好的表达和复用。

参考连接

评论