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
相关文章
相关标签/搜索