Laravel 中的強大的tap你用過麼

在本文,咱們將討論 Laravel 中的 tap。咱們將詳細討論 tap 幫助函數和 collection 中的 tap 方法。php

Tap 幫助函數

舊的實現方式

Laravel提出了一個 tap 功能。這是一個很是奇怪的功能,受Ruby的啓發。這是 tap 助手功能的基本實現。laravel

function tap($value, $callback)
{
    $callback($value);

    return $value;
}

上面的代碼將接受一個參數,它將使用該參數調用一個匿名函數。在調用回調函數後,它將返回參數。 讓咱們看看咱們如何以有意義的方式使用它。例如:spring

<?php

$photo = App\Photo::find(1);

return tap($photo, function($photo) {
    $photo->validated = true;
    $photo->save();
});

在上面的例子中,咱們傳遞一個參數(照片模型)和一個回調函數,該函數簡單地將 validated 設置爲 true 並保存模型。這個函數而後將照片模型實例返回給調用者。數組

新的實現方式

在最新版本的Laravel 5.4和Laravel 5.5中,更高級的 tap 來了。它引入了更短的使用方式。這裏是 tap 函數的新實現。bash

function tap($value, $callback = null)
{
    if (is_null($callback)) {
        return new HigherOrderTapProxy($value);
    }

    $callback($value);

    return $value;
}

回調函數如今是可選的。你還能夠鏈式使用參數中的多個方法,這裏其實也就是照片Model中支持的方法。例如函數

<?php

$photo = App\Photo::find(1);

return tap($photo)->update([
    'validated' => 'true',
])

咱們可以將任何模型的方法經過 tap 鏈式調用。此更新方法一般返回 truefalse,可是這裏使用了 tap 函數。在這種狀況下,它將返回照片模型。tap 能夠幫助你返回做爲參數傳遞的對象。post

它是如何工做的

tap 是一個很是有用的功能,但有時它很難理解它是如何工做的。 這裏來解釋它是如何工做的。ui

若是沒有給出回調函數,由於它是可選的,Laravel將返回 HigherOrderTapProxy 的新實例。 在 HigherOrderTapProxy 類中定義了調用魔術方法。 調用魔術方法是由語言動態調用的(所謂的方法在類中沒有定義)。 由於除了調用魔術方法,HigherOrderTapProxy 類中沒有定義方法,因此每次使用 tap 函數任何方法調用時都會調用它。 在調用魔術方法中,咱們的更新方法或任何咱們調用的方法將被參數調用,而且它將返回咱們最初傳遞給 tap 函數的參數。this

這裏是 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中,也有相似的方法叫管道。 它們在某種意義上是類似的,由於它們都在集合管道中使用。 tappipe 之間有一個區別。 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

相關文章
相關標籤/搜索