在本文,我們將討論 Laravel 中的 tap
。我們將詳細討論 tap
幫助函式和 collection
中的 tap
方法。
Tap 幫助函式
舊的實現方式
Laravel提出了一個 tap
功能。這是一個非常奇怪的功能,受Ruby的啟發。這是 tap
助手功能的基本實現。
function tap($value, $callback)
{
$callback($value);
return $value;
}
上面的程式碼將接受一個引數,它將使用該引數呼叫一個匿名函式。在呼叫回撥函式後,它將返回引數。
讓我們看看我們如何以有意義的方式使用它。例如:
<?php
$photo = AppPhoto::find(1);
return tap($photo, function($photo) {
$photo->validated = true;
$photo->save();
});
在上面的例子中,我們傳遞一個引數(照片模型)和一個回撥函式,該函式簡單地將 validated
設定為 true
並儲存模型。這個函式然後將照片模型例項返回給呼叫者。
新的實現方式
在最新版本的Laravel 5.4和Laravel 5.5中,更高階的 tap
來了。它引入了更短的使用方式。這裡是 tap
函式的新實現。
function tap($value, $callback = null)
{
if (is_null($callback)) {
return new HigherOrderTapProxy($value);
}
$callback($value);
return $value;
}
回撥函式現在是可選的。你還可以鏈式使用引數中的多個方法,這裡其實也就是照片Model中支援的方法。例如
<?php
$photo = AppPhoto::find(1);
return tap($photo)->update([
`validated` => `true`,
])
我們能夠將任何模型的方法通過 tap
鏈式呼叫。此更新方法通常返回 true
或 false
,但是這裡使用了 tap
函式。在這種情況下,它將返回照片模型。tap
可以幫助你返回作為引數傳遞的物件。
它是如何工作的
tap
是一個非常有用的功能,但有時它很難理解它是如何工作的。 這裡來解釋它是如何工作的。
如果沒有給出回撥函式,因為它是可選的,Laravel將返回 HigherOrderTapProxy
的新例項。 在 HigherOrderTapProxy
類中定義了呼叫魔術方法。 呼叫魔術方法是由語言動態呼叫的(所謂的方法在類中沒有定義)。 因為除了呼叫魔術方法,HigherOrderTapProxy
類中沒有定義方法,所以每次使用 tap
函式任何方法呼叫時都會呼叫它。 在呼叫魔術方法中,我們的更新方法或任何我們呼叫的方法將被引數呼叫,並且它將返回我們最初傳遞給 tap
函式的引數。
這裡是 HigherOrderTapProxy
類中呼叫魔術方法的實際內容。
// vendor/laravel/framework/src/Illuminate/Support/HigherOrderTapProxy.php
public function __call($method, $parameters)
{
$this->target->{$method}(...$parameters);
return $this->target;
}
在上面的程式碼中,target
屬性是我們在tap中傳遞的引數。
Laravel collection 中的 tap 方法
Laravel還在 collection
類中有一個 tap
方法,可讓你在特定的地方傳入引數到 tap中,並對這些結果進行處理。tap
不會影響主要 collection 的結果。 這對除錯程式碼和查詢在處理集合時出現錯誤的地方很有幫助。
我們用一個例子來解釋這個方法。 初始化以下陣列。
$photos = [
[`file_name` => `wallpaper`, `validated` => true, `extension` => `jpg`],
[`file_name` => `spring`, `validated` => true, `extension` => `png`],
[`file_name` => `flowers`, `validated` => false, `extension` => `jpg`],
[`file_name` => `mac`, `validated` => true, `extension` => `png`],
[`file_name` => `books`, `validated` => false, `extension` => `jpg`],
[`file_name` => `mobiles`, `validated` => false, `extension` => `jpg`],
[`file_name` => `glass`, `validated` => false, `extension` => `png`],
[`file_name` => `fruit`, `validated` => true, `extension` => `jpg`],
];
現在讓我們嘗試在這個陣列上使用 tap
方法。首先,我們必須將這個陣列轉換為一個集合,然後在特定點處 tap
這個集合。
return collect($photos)
->where(`validated`, true)
->tap(function ($validated) {
return var_dump($validated->pluck(`file_name`));
});
});
上面的程式碼將會輸出以下結果:
wallpaper
spring
mac
fruit
tap VS Pipe(管道)
在Laravel中,也有類似的方法叫管道。 它們在某種意義上是相似的,因為它們都在集合管道中使用。 tap
和 pipe
之間有一個區別。 tap
允許你使用資料,但不會修改原始返回值。 另一方面,pipe
根據返回值修改資料。
例如:
return collect($photos)
->where(`validated`, true)
->pipe(function ($validated) {
return $validated->where(`extension`, `jpg`)->pluck(`file_name`);
});
});
輸出結果為
wallpaper
fruit
另一方面,如果我們像這樣使用上面的程式碼:
return collect($photos)
->where(`validated`, true)
->tap(function ($validated) {
return $validated->where(`extension`, `jpg`)->pluck(`file_name`);
});
});
它將返回驗證設定為true的所有照片陣列。
結果為
0: {
file_name: "wallpaper",
validated: true,
extension: "jpg"
},
1: {
file_name: "spring",
validated: true,
extension: "png"
},
3: {
file_name: "mac",
validated: true,
extension: "png"
},
7: {
file_name: "fruit",
validated: true,
extension: "jpg"
}
更多PHP知識,請前往PHPCasts