[Laravel] 客製化你的Laravel: macro

2024/03/04閱讀時間約 6 分鐘
此文章同步刊登於我的部落格


前言

有的時候,會希望在Laravel原生的class新增功能的時候,大多我們都會寫一個新的class並繼承,但是其實Laravel提供了一個不同的方式,讓我們可以在常用的class上,直接新增想要的function,那就是macro。


一、使用

我們可以在Provider的boot()裡面使用macro來添加自訂的function,這邊以Collection為例子:

Collection::macro('remove', function (string $filterValue, ?string $filterKey = null) {
foreach ($this as $key => $item) {
// 根據是否有$filterKey決定如何取值
$value = is_null($filterKey) ? $item : data_get($item, $filterKey);
// 如果值與$filterValue相同就移除該item
if ($value == $filterValue) {
$this->forget($key);
}
}

return $this;
});

現在Collection就被註冊了一個名為remove的function了,可以直接透過value移除指定的元素:

$collection = collect([
'標題1', '標題2', '標題3', '標題4'
]);

$collection->remove('標題3');

或是像data_get一樣取得巢狀物件或陣列的方式,移除指定的元素,例如:

$collection = collect([
[
'title' => '標題1',
'content' => '內容1',
'writer' => [
'name' => '作者1',
'gender' => 'man',
],
],
[
'title' => '標題2',
'content' => '內容2',
'writer' => [
'name' => '作者2',
'gender' => 'woman',
],
],
[
'title' => '標題3',
'content' => '內容3',
'writer' => [
'name' => '作者3',
'gender' => 'man',
],
],
]);

$collection->remove('作者3', 'writer.name');


二、實現方式

在Laravel中只要是有使用Illuminate\Support\Traits\Macroable這個trait的class,就可以使用macro,而Laravel是如何實現這個功能的呢?其實也很簡單,就是利用魔術方法中的call function,讓我們看一下原始碼寫了一些甚麼吧。

public static function macro($name, $macro)
{
static::$macros[$name] = $macro;
}

macro做的事情非常單純,就是把我們放進來的function name跟Closure儲存下來,而等到我們使用自訂function的時候就會觸發call function的機制:

public function __call($method, $parameters)
{
if (! static::hasMacro($method)) {
throw new BadMethodCallException(sprintf(
'Method %s::%s does not exist.', static::class, $method
));
}

$macro = static::$macros[$method];

if ($macro instanceof Closure) {
$macro = $macro->bindTo($this, static::class);
}

return $macro(...$parameters);
}

這樣我們的自訂functin就註冊給了這個class,也就可以像內建的function來使用了。

在Laravel中,有使用Macroable的class非常的多,包括但不限於以下:


  • Response
  • Request
  • Collection
  • HTML
  • Form
  • Str
  • Arr
  • Translator
  • File
  • Lang

但凡只要有引用Macroable的calss都可以使用carce來註冊自己的function,筆者這邊在Laravel 8內搜尋了一下就發現有51個class有引用Macroable,這還不包含這些class的子class,可以說非常的廣泛,大家不妨可以自己試試看。

參考資料


7會員
21內容數
你可以在這裡看到後端工程師的技術文章 也可以看到一些投資相關的心得分享 歡迎交流~
留言0
查看全部
發表第一個留言支持創作者!
從 Google News 追蹤更多 vocus 的最新精選內容