闭包
闭包和匿名函数是从PHP 5.3.0开始出现的,这是我最喜欢也是用的最多的PHP功能。听到这些名称心里特别没底(至少我第一次听到时是这么认为的),但是事实上真的很好理解。它们是每个PHP开发者们的工具箱中必备的最有用的工具。
闭包作为一个函数,在创建时会封装外部的状态。即使最初创建闭包时的环境已经不存在了,封装的状态也会一直保存在闭包中。这是一个不太好掌握的概念,一旦你能够弄明白,感觉就像人生翻开了新的篇章。
匿名函数实际上就是没有名字的函数。匿名函数可以被赋值给变量,像所有其它的PHP对象一样在代码中传递。但是它终归还是函数,所以你可以调用它并且传递参数。匿名函数最大的用处是作为函数或者方法的回调。
闭包和匿名函数理论上是不同的概念。然而,PHP认为它们是一码事。所以,当我说闭包的时候也可能指的是匿名函数,反之亦然。
PHP的闭包和匿名函数在语法上和函数一样,但是别被它们弄混。他们实际上是伪装成函数的对象。如果你打印检查一个PHP闭包或者匿名函数的类型,你会发现它们都是Closure类的实例。Closure可以看作是同string和integer一样重要的数据类型。
创建
我们都知道PHP的闭包和函数看起来很像。当你像例子 2-19那样创建一个PHP闭包后,你就不会感到惊讶了。
例子 2-19 简单的闭包
<?php $closure = function ($name) { return sprintf('Hello %s', $name);};echo $closure("Josh");// 输出 --> "Hello Josh"
就这么简单。例子 2-19创建了一个Closure对象并将它赋值给变量$closure。它看起来像一个标准的PHP函数:它使用了相同的语法、接收参数并且有返回值。但是它没有名字。
我们可以调用$closure变量,因为$closure的是一个闭包,Closure闭包对象都实现了\_invoke()这个魔术方法。在变量名跟着一对()符号时PHP会自动查找并调用__invoke()方法。
我通常使用PHP的闭包对象作为函数和方法的回调。很多PHP的函数都会使用回调函数,例如array_map()和preg_replace_callback()。这就像为PHP匿名函数量身定做的功能!记住,就像其它任何值一样,闭包可以像参数一样被传递给其它PHP函数。在例子 2-10中我使用一个闭包对象作为array_map()函数的回调参数。
例子 2-20 array_map闭包
<?php $numbersPlusOne = array_map(function ($number) { return $number +1;}, [1,2,3]);print_r($numbersPlusOne);// 输出 --> [2,3,4]
看起来并不是那么让人印象深刻是吗?但是记住,在闭包功能出现之前要实现这样的功能,PHP开发者们并没有什么好的选择,他们只能创建一个具名函数并把函数名作为参数传递进去才行。这样做执行上会有些慢,最重要的是它分离了回调的实现和使用。老派的PHP开发者们使用下面的代码:
<?php // 具名回调的实现function incrementNumber ($number) { return $number + 1;}// 具名回调的使用$numberPlusOne = array_map('incrementNumber', [1,2,3]);print_r($numberPlusOne);
上面的代码固然可以正常执行,但是却没有例子 2-20中的简洁。我们并不需要一个单独以incrementNumber()命名的一次性函数作为回调。使用闭包作为回调可以创建出更简练、可读性更强的代码。
附着状态
目前为止我们演示了如何使用无名(也叫匿名)函数作为回调使用。下面让我们研究一下如何使用PHP闭包附着和封装状态。JavaScript开发者们可能会对PHP的闭包产生困惑,因为PHP的闭包不会像JavaScript一样自动将应用程序的状态封装给闭包。相反,你必须手动的调用闭包对象的bintTo()方法或者use关键词将状态附着给一个PHP闭包。
通常我们都是使用use关键词来附着闭包状态,所以让我们先以此为例(例子 2-21)。当你使用use关键词将一个变量附着给一个闭包时,被附着的变量值将一直保持为变量被附着给闭包的那一刻的值。
例子 2-21 使用use关键词附着一个闭包状态
<?phpfunction enclosePerson($name) { return function ($doCommand) use ($name) { return sprintf('%s, %s', $name, $doCommand); };}// 将字符串"Clay"封装进闭包$clay = enclosePerson('Clay');// 调用闭包echo $clay('get me sweet tea!');// 输出 --> "Clay, get me sweet tea!"
在例子 2-21中,具名函数enclosePerson()函数接收一个$name参数,返回一个封装了$name参数的闭包对象。即使闭包最终离开了enclosePerson()函数的作用域,但是返回的闭包对象$clay中仍然会保留$name参数被附着给闭包时的值。也就说,$name变量仍然存在在闭包中!
你可以使用use关键词给闭包传递多个参数。参数之间使用逗号分隔,就像你们平时使用PHP的函数或者方法的参数一样。
别忘了PHP闭包都是对象。每个闭包的实例都有其内部状态,我们可以像其他PHP对象那样使用$this关键词来获取这些状态。一个闭包对象的默认状态相当无趣,它包含了一个魔术方法__invoke()和一个bindTo()方法,仅此而已。
不过bindTo()方法却可以带领我们去发掘出一些有趣的实现。这个方法允许我们将闭包对象的内部状态绑定到另一个对象上。bindTo()方法的第二个参数相当关键,它可以指定闭包需要绑定到的对象的类。这样我们就可以在闭包中获取绑定后的对象中protected和private的成员变量了。
你会发现bindTo()方法经常被一些PHP框架用来将路由地址映射到匿名回调函数上。这些框架将一个匿名函数绑定到应用程序对象上。你可以在匿名函数中使用$this关键词来引用应用程序对象,就像例子 2-22中所示
例子 2-22 使用bindTo方法附着闭包状态
<?phpclass App{ protected $routes = array(); protected $responseStatus = '200 OK'; protected $responseContentType = 'text/html'; protected $responseBody = 'Hello world'; 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方法。它接收一个路由地址(例如 /users/josh)和一个路由的回调。dispatch()方法接收一个当前HTTP请求地址并调用对应的路由回调。神奇的地方在第11行,我们将路由的回调绑定给了当前App类的实例。这样我们就可以创造一个可以操作App实例状态的回调函数了:
<?php $app = new App();$app->addRoute('/users/josh', function () { $this->responseContentType = 'application/json;charset=utf8'; $this->responseBody = '{"name": "Josh"}';});$app->dispatch('/users/josh');

PHP在现代Web开发中仍然重要,尤其在内容管理和电子商务平台。1)PHP拥有丰富的生态系统和强大框架支持,如Laravel和Symfony。2)性能优化可通过OPcache和Nginx实现。3)PHP8.0引入JIT编译器,提升性能。4)云原生应用通过Docker和Kubernetes部署,提高灵活性和可扩展性。

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

PHP和Python各有优势,适合不同场景。1.PHP适用于web开发,提供内置web服务器和丰富函数库。2.Python适合数据科学和机器学习,语法简洁且有强大标准库。选择时应根据项目需求决定。

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP成为许多网站首选技术栈的原因包括其易用性、强大社区支持和广泛应用。1)易于学习和使用,适合初学者。2)拥有庞大的开发者社区,资源丰富。3)广泛应用于WordPress、Drupal等平台。4)与Web服务器紧密集成,简化开发部署。

PHP在现代编程中仍然是一个强大且广泛使用的工具,尤其在web开发领域。1)PHP易用且与数据库集成无缝,是许多开发者的首选。2)它支持动态内容生成和面向对象编程,适合快速创建和维护网站。3)PHP的性能可以通过缓存和优化数据库查询来提升,其广泛的社区和丰富生态系统使其在当今技术栈中仍具重要地位。

在PHP中,弱引用是通过WeakReference类实现的,不会阻止垃圾回收器回收对象。弱引用适用于缓存系统和事件监听器等场景,需注意其不能保证对象存活,且垃圾回收可能延迟。

\_\_invoke方法允许对象像函数一样被调用。1.定义\_\_invoke方法使对象可被调用。2.使用$obj(...)语法时,PHP会执行\_\_invoke方法。3.适用于日志记录和计算器等场景,提高代码灵活性和可读性。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

WebStorm Mac版
好用的JavaScript开发工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。