本文參照轉譯:
http://derekmd.com/2017/02/laravel-tap/?ut...
https://murze.be/2017/02/laravels-tap-help...
Laravel 5.3 中增加了一個新的全域性幫助函式 tap()
,改進了框架的宣告能力。這個微妙的語法是從 Ruby
和 Lodash
借鑑而來,允許你去 tap
成鏈。
先看看 tap()
幫助函式的程式碼,只有短短的幾行:
function tap($value, $callback)
{
$callback($value);
return $value;
}
你需要傳一個值和一個回撥到方法中,值作為回撥的引數,回撥將執行,最後值被返回。
執行中間操作
從一個簡單的例子開始,提取 Laravel
的 AuthenticateSession@handle()
的一些程式碼,一些 PHP 開發者非常熟悉的解決方案:
$response = $next($request);
$this->storePasswordHashInSession($request);
return $response;
使用 tap()
幫助函式:
return tap($next($request), function () use ($request) {
$this->storePasswordHashInSession($request);
});
另外的一個簡單的例子,讓我們看看 Illuminate\Cache\Repository
下的 pull
方法,此函式將從指定鍵的快取中獲取值,並將其刪除。pull
方法的實現:
public function pull($key, $default = null)
{
$value = $this->get($key, $default);
$this->forget($key) // returns a boolean;
return $value;
}
上面的例子中,$this-> forget()
返回一個布林值,所以要使我們的函式返回原始值,需要將其儲存到臨時變數 $value
中。以下是 tap()
的實現,不再需要臨時變數:
public function pull($key, $default = null)
{
return tap($this->get($key, $default), function ($value) use ($key) {
$this->forget($key);
});
}
恢復狀態
Eloquent 的 create
和 update
方法支援 ['timestamps' => false]
選項。如果這被實現成鏈式方法,結果的可讀性會更好。
// Method defined in App\Model that App\Message extends.
public function keepingTimestamps(callable $callback)
{
try {
$timestamps = $this->timestamps;
$this->timestamps = false;
return tap($this, $callback);
} finally {
$this->timestamps = $timestamps;
}
}
現在 Message
模型可以鏈式使用以上的方法:
request()->user()->latestMessage->keepingTimestamps(function ($message) {
$message->markRead(); // updates a 'read_at' timestamp instead
}); // returns the latestMessage
如果你寫的程式碼有 DB::transaction()
相同的模式,你可以在 Laravel 5.4 使用 tap()
幫助函式重寫。
Collection
Laravel 5.4 中也可以在 Collection
類中使用 tap()
方法。你可以在任何地方使用,而不需要破壞鏈式。對於 Laravel 5.3 及更早的版本,你只需要複製貼上五行程式碼的方法作為 Collection macro
到你專案的 AppServiceProvider@boot()
即可。
這裡有一個例子,用於 Laravel 網站支援英語和法語。取代月份的語言翻譯檔案,使用 Carbon
列出一年每個月份的 <option>
。因此這個模型的修飾方法:
public function monthOptions()
{
return collect(range(1, 12))
->keyByValue() // custom Collection macro
->tap(function () {
if (App::getLocale() === 'fr') {
setlocale(LC_TIME, 'fr_CA');
}
})
->map(function ($month) {
return sprintf('%02d - %s', $month,
Carbon::now()->month($month)->formatLocalized('%B'));
})
->tap(function () {
if (App::getLocale() === 'fr') {
setlocale(LC_TIME, '');
}
});
}
對於更多的語言支援,設定/恢復狀態將提取到其他方法,使其更加可讀。
使用 Collection tap()
處理控制檯命令進度條
這是在集合中最典型的用例。你甚至可以在 handle()
處理過程中保持其方法鏈。
public function handle()
{
Club::findOrFail($this->option('club'))
->members()
->subscribed()
->get()
->tap(function ($members) {
$this->output->progressStart($members->count());
})
->each(function ($member) {
Mail::to($member)->queue(new Newsletter($member, $this->matchReport());
$this->output->progressAdvance();
})
->tap(function () {
$this->output->progressFinish();
});
}
public function matchReport()
{
return once(function () {
return MatchReport::ofRound($this->option('round'))->firstOrFail();
});
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結
Nothing is impossible. —— @Jiajian Chan