现代 PHP 新特性系列(五) —— 闭包和匿名函数 | 新特性 | 现代 PHP 新特性与最佳实践


本站和网页 https://xueyuanjun.com/post/4341.html 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

现代 PHP 新特性系列(五) —— 闭包和匿名函数 | 新特性 | 现代 PHP 新特性与最佳实践
Laravel 学院
文档
Laravel 8.x 中文文档
Laravel 7.x 中文文档
Laravel 6.x 中文文档
Laravel 5.8 中文文档
Laravel 5.7 中文文档
Laravel 5.6 中文文档
Laravel 5.5 中文文档
Laravel 5.4 中文文档
Laravel 5.3 中文文档
Laravel 5.2 中文文档
Laravel 5.1 中文文档
Lumen 中文文档
全栈教程
PHP 全栈工程师指南
PHP 入门到实战
Laravel 入门到精通
Vue.js 入门到实战
玩转 PhpStorm 教程
Laravel 博客入门项目
Laravel 微信小程序项目
Laravel 前后端分离项目
Swoole 入门到实战
Eloquent 性能优化实战
Redis 高性能实战系列
Laravel 新版本特性
PHP 新特性与最佳实践
Golang
Go 入门教程
Go Web 编程
Gin 使用教程
微服务开发
内功修炼
数据结构与算法
网络协议
微服务从入门到实践
高性能 MySQL 实战
高性能 Redis 实战
Laravel 消息队列实战
Laravel 从学徒到工匠
PHP 设计模式系列
名企面试指南
资源库
Laravel 资源大全
Laravel 开源项目
Laravel 扩展包
Laravel 资源下载
更多
博客 & 新闻
问答 & 讨论
Leetcode 题解
学院君读书笔记系列
关于 Laravel 学院
Laravel 互助学习群
Golang 互助学习群
更多
Laravel 中文文档
Laravel 全栈教程
Laravel 学习路径
Go 入门教程
程序员内功修炼
博客
问答
搜索
注册
登录
Info
Content
章节导航
现代 PHP 新特性与最佳实践
目录索引
新特性
9篇文章
现代 PHP 新特性系列(一) —— 命名空间
现代 PHP 新特性系列(二) —— 善用接口
现代 PHP 新特性系列(三) —— Trait 概览
现代 PHP 新特性系列(四) —— 生成器的创建和使用
现代 PHP 新特性系列(五) —— 闭包和匿名函数
现代 PHP 新特性系列(六) —— Zend Opcache
现代 PHP 新特性系列(七) —— 内置的 HTTP 服务器
PHP 8 新特性系列 —— JIT 对 PHP 应用性能的影响
PHP 8 所有新特性一览和代码示例
最佳实践
11篇文章
漫谈 PHP 组件、框架、Composer 那些事
聊聊 PHP 私有组件以及如何创建自己的 PHP 组件
PHP 安全三板斧:过滤、验证和转义之过滤篇 & Laravel底层SQL注入规避
PHP 安全三板斧:过滤、验证和转义之验证篇 & Laravel底层字段验证实现
PHP 安全三板斧:过滤、验证和转义之转义篇 & Blade 模板引擎避免 XSS 攻击原理探究
PHP 开发者如何做好密码保护 & Laravel 底层密码存储和验证实现
PHP 日期、时间和时区处理 API 及组件
PHP 数据库统一处理 API —— PDO 扩展及其在 Laravel 底层的使用
PHP 多字节字符串处理函数及字符编码
PHP 统一资源处理 API —— 流(Stream)的概述与使用详解
深入探讨 PHP 错误异常处理机制及 Laravel 框架底层的相应实现
部署调优
4篇文章
PHP 服务器主机选择及初始化配置 —— 新增用户及密钥对认证
在服务器上对 PHP-FPM 和 Nginx 进行安装配置详解
php.ini 配置调优 —— 让 PHP 应用性能维持在更高水平
使用现代化工具 Capistrano 自动部署 PHP 应用代码到生产环境
番外篇
2篇文章
在 Windows 下安装部署 PHP 7.0 本地开发环境
PHP 7.0 与 PHP 5.6 下 Laravel 博客应用性能对比分析
图书
现代 PHP 新特性与最佳实践
新特性
现代 PHP 新特性系列(五) —— 闭包和匿名函数
现代 PHP 新特性系列(五) —— 闭包和匿名函数
由 学院君 创建于6年前, 最后更新于 2年前
版本号 #3
52109 views
54 likes
4 collects
1、概述
闭包和匿名函数在PHP 5.3.0中引入,这两个特性非常有用,每个PHP开发者都应该掌握。
闭包是指在创建时封装周围状态的函数,即使闭包所在的环境的不存在了,闭包中封装的状态依然存在。
匿名函数其实就是没有名称的函数,匿名函数可以赋值给变量,还能像其他任何PHP函数对象那样传递。不过匿名函数仍然是函数,因此可以调用,还可以传入参数,适合作为函数或方法的回调。
注:理论上讲闭包和匿名函数是不同的概念,不过PHP将其视作相同的概念(匿名函数在PHP中也叫作闭包函数),所以下面提到闭包时指的也是匿名函数;反之亦然。
2、创建闭包
创建闭包很简单:
<?php
$greet = function ($name) {
    return sprintf("Hello %s\r\n", $name);
};
echo $greet('LaravelAcademy.org');
结果打印:
Hello LaravelAcademy.org
闭包和普通的PHP函数很像:常用的句法相同,也接受参数,而且能返回值。不过闭包没有函数名。
注:我们之所以能调用$greet变量,是因为这个变量的值是一个闭包,而且闭包对象实现了__invoke()魔术方法,只要变量名后有(),PHP就会查找并调用__invoke方法。
我们通常把PHP闭包当做函数会方法的回调使用,事实上,很多PHP函数都会用到闭包,比如array_map和preg_replace_callback,这是使用PHP匿名函数的绝佳时机。记住,闭包和其他值一样,可以作为参数传入其他PHP函数:
<?php
$numberPlusOne = array_map(function ($number) {
    return $number += 1;
}, [1, 2, 3]);
print_r($numberPlusOne);
在闭包出现之前,要实现这样的功能,PHP开发者只能单独创建具名函数,然后使用名称引用这个函数:
<?php
function incrementNumber ($number) {
    return $number += 1;
$numberPlusOne = array_map(‘incrementNumber’,  [1, 2, 3]);
print_r($numberPlusOne);
这样做把回调的实现和使用场所隔离开了,而且使用闭包实现代码更加简洁。
3、从父作用域继承变量
在PHP中必须手动调用闭包对象的bindTo方法或使用use关键字把父作用域的变量及状态附加到PHP闭包中。而实际应用中,又以使用use关键字实现居多。
use关键字
实际上,Laravel框架中也大量使用了闭包,最常见的比如路由定义:
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
这里面的两个function都是闭包。而从父作用域继承变量的使用场景在Laravel底层源码中也是俯拾即是,比如Model.php(Illuminate\Database\Eloquent)的saveOrFail方法:
该方法的作用是使用事务将模型数据保存到数据库,这里面我们使用闭包返回保存状态,同时使用use关键字将父作用域的$options传递给该闭包以便其能够访问这个数据。
此外,还支持传递多个父作用域变量到闭包,比如还是在Model类中的forceFill方法:
多个变量以逗号分隔即可。
bindTo方法
我们在前面已经提到,闭包是一个对象,所以我们可以在闭包中使用$this关键字获取闭包的内部状态,闭包对象的默认状态没什么用,需要注意的是其中的__invoke魔术方法和bindTo方法。
__invoke的作用前面已经说过,当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
接下来我们来看看bindTo方法,通过该方法,我们可以把闭包的内部状态绑定到其他对象上。这里bindTo方法的第二个参数显得尤为重要,其作用是指定绑定闭包的那个对象所属的PHP类,这样,闭包就可以在其他地方访问邦定闭包的对象中受保护和私有的成员变量。
你会发现,PHP框架经常使用bindTo方法把路由URL映射到匿名回调函数上,框架会把匿名回调函数绑定到应用对象上,这样在匿名函数中就可以使用$this关键字引用重要的应用对象:
<?php
class App {
    protected $routes = [];
    protected $responseStatus = '200 OK';
    protected $responseContentType = 'text/html';
    protected $responseBody = 'Laravel学院';
    public function addRoute($routePath, $routeCallback) {
        $this->routes[$routePath] = $routeCallback->bindTo($this, __CLASS__);
    }
    public function dispatch($currentPath) {
        foreach ($this->routes as $routePath => $callback) {
            if( $routePath === $currentPath) {
                $callback();
            }
        }
        header('HTTP/1.1 ' . $this->responseStatus);
        header('Content-Type: ' . $this->responseContentType);
        header('Content-Length: ' . mb_strlen($this->responseBody));
        echo $this->responseBody;
    }
这里我们需要重点关注addRoute方法,这个方法的参数分别是一个路由路径和一个路由回调,dispatch方法的参数是当前HTTP请求的路径,它会调用匹配的路由回调。第9行是重点所在,我们将路由回调绑定到了当前的App实例上。这么做能够在回调函数中处理App实例的状态:
$app = new App();
$app->addRoute(‘user/nonfu’, function(){
    $this->responseContentType = ‘application/json;charset=utf8’;
    $this->responseBody = ‘{“name”:”LaravelAcademy"}';
});
$app->dispatch(‘user/nonfu');
在Larval底层也有用到bindTo方法,详见Illuminate\Support\Traits\Macroable的__call方法:
Laravel
路由
PHP
新特性
闭包
匿名函数
Closure
点赞
取消点赞
收藏
取消收藏
赞赏
分享到以下平台:
<< 上一篇:
现代 PHP 新特性系列(四) —— 生成器的创建和使用
>> 下一篇:
现代 PHP 新特性系列(六) —— Zend Opcache
12 条评论
#11
newbrash
评论于 3年前
正在删除评论...
你这是匿名函数啦
#12
撸sir
评论于 3年前
回复 #10
正在删除评论...
区分的点是在哪里,还是不清楚,求赐教阿
&lsaquo;
&rsaquo;
登录后即可添加评论
升级为学院君订阅用户(新年优惠🎁)
内容导航
1、概述
2、创建闭包
3、从父作用域继承变量
use关键字
bindTo方法
相关推荐
现代 PHP 新特性系列(三) —— Trait 概览
现代 PHP 新特性与最佳实践
新特性
现代 PHP 新特性系列(七) —— 内置的 HTTP 服务器
现代 PHP 新特性与最佳实践
新特性
laravel ---- 关联表 A 和 B 如何模糊查询 B 表中指定的字段
问答
目录索引
现代 PHP 新特性与最佳实践
关于 laravel 任务调度的问题
问答
回到顶部
2022 基于 Laravel 6 构建
关于学院
订阅服务
友情链接
站点地图
本站 CDN 加速服务由又拍云赞助