Laravel 中的强大的tap你用过么

Stella981
• 阅读 849

在本文,我们将讨论 Laravel 中的 tap。我们将详细讨论 tap 帮助函数和 collection 中的 tap 方法。

Tap 帮助函数

旧的实现方式

Laravel提出了一个 tap 功能。这是一个非常奇怪的功能,受Ruby的启发。这是 tap 助手功能的基本实现。

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

    return $value;
}

上面的代码将接受一个参数,它将使用该参数调用一个匿名函数。在调用回调函数后,它将返回参数。 让我们看看我们如何以有意义的方式使用它。例如:

<?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 函数的新实现。

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 可以帮助你返回作为参数传递的对象。

它是如何工作的

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中,也有类似的方法叫管道。 它们在某种意义上是相似的,因为它们都在集合管道中使用。 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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
OpenVPN搭建中tap与tun的实际使用区别
tap俗称网桥模式,tun俗称路由模式,tap在二层,tun在三层,在实际应用中,其实以上这些知识概念,我是抄来的,具体的解释可以看以下参考链接。下面将介绍在实际使用中的区别:1、tap可以直接使用route这样的路由表命令,但不能用于手机设备。2、tun可以用于手机,但不能使用route这样的路由表命令,压根无法穿透。3、tap和tun的路
Stella981 Stella981
3年前
Linux Bridge 详解
LinuxBridge详解LinuxBridge(网桥)是用纯软件实现的虚拟交换机,有着和物理交换机相同的功能,例如二层交换,MAC地址学习等。因此我们可以把tun/tap,vethpair等设备绑定到网桥上,就像是把设备连接到物理交换机上一样。此外它和vethpair、tun/tap一样,也是一种虚拟网络设备,
Stella981 Stella981
3年前
Linux的虚拟网卡TUN和TAP
TUN/TAP提供了给用户空间程序的包的接收和传输,它可以看成是简单的点对点设备或是以太网设备。它不是从物理设备接收包,而是从用户空间程序接收包。它发送包不是通过物理设备来发送包,而是将这些包写入用户空间程序来发送。为了应用这个驱动,应用程序需要打开/dev/net/tun设备(字符设备),然后发出一个控制(ioctl)来注册一个
Stella981 Stella981
3年前
PEP8 Python 编码规范
PEP8Python编码规范一代码编排1缩进。4个空格的缩进(编辑器都可以完成此功能),不使用Tap,更不能混合使用Tap和空格。2每行最大长度79,换行可以使用反斜杠,最好使用圆括号。换行点要在操作符的后边敲回车。3类和toplevel函数定义之间空两行;类中的方法定义之间空一行;函数内逻辑无关段落之间空一行;其
Wesley13 Wesley13
3年前
IOS中键盘自动隐藏
前言很多时候当我们在一个文本框中输入信息后,按了确认或者返回键需要隐藏键盘,或者在其他空白区域点击屏幕后也需要隐藏屏幕。这时肯定就需要让相应的控件响应Tap事件(点击事件),这样我们才能处理。实现隐藏的两种方法在IOS中有一个概念叫FirstResponder,意指第一响应者,也就是当前屏幕上,处于焦点状态的控件,它是第一响
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Linux Bridge和Tap关系详解
Bridge(桥)是Linux上用来做TCP/IP二层协议交换的设备,与现实世界中的交换机功能相似。Bridge设备实例可以和Linux上其他网络设备实例连接,既attach一个从设备,类似于在现实世界中的交换机和一个用户终端之间连接一根网线。当有数据到达时,Bridge会根据报文中的MAC信息进行广播、转发、丢弃处理。