vchagin / superclosure
序列化闭包,包括它们的上下文
Requires
- php: >=5.3.3
- nikic/php-parser: ~1.0
Requires (Dev)
- phpunit/phpunit: ~4.0
This package is auto-updated.
Last update: 2024-09-29 05:08:57 UTC
README
你见过这种情况吗?
未捕获异常 'Exception',消息为 '序列化 'Closure' 不允许'
是真的!如果你尝试序列化一个 Closure
,PHP 将抛出异常,并告诉你不允许。尽管 PHP 不允许,但 Super Closure 库(在 Packagist 上的 jeremeamia/superclosure)使这成为可能。
我没有开玩笑,你真的可以序列化 PHP 闭包!
require 'vendor/autoload.php'; use SuperClosure\SerializableClosure; $greeting = 'Hello'; $helloWorld = new SerializableClosure(function ($name = 'World') use ($greeting) { echo "{$greeting}, {$name}!\n"; }); $helloWorld(); //> Hello, World! $helloWorld('Jeremy'); //> Hello, Jeremy! $serialized = serialize($helloWorld); $unserialized = unserialize($serialized); $unserialized(); //> Hello, World! $unserialized('Jeremy'); //> Hello, Jeremy!
是的,很酷,对吧?
告诉我更多!
这一切始于 2010 年初,当时 PHP 5.3 开始流行。我在前雇主博客 HTMList 上发表了一篇名为 使用序列化和反射扩展 PHP 5.3 闭包 的博客文章,展示了如何实现。从那时起,我对代码进行了一些迭代,最近的一次迭代带来了一个更稳健的解决方案,利用了出色的 nikic/php-parser 库。
功能
- 允许序列化闭包
- 处理使用/继承/导入变量的闭包
- 处理使用其他闭包的闭包
- 处理引用参数或体中的类名的闭包
- 处理递归闭包(仅限 PHP 5.4+)
- 允许您获取闭包的代码
- 允许您获取闭包使用的变量名称和值
- 允许您获取表示闭包代码的抽象语法树(AST)
- 将魔术常量替换为其预期值,以便在反序列化后闭包按预期行为
- 通过 nikic/php-parser 库使用精确的上下文无关语法解析方法
- PSR-0 兼容,可通过 Composer 安装
注意事项
- 对于任何通过引用使用的变量(例如,
function () use (&$vars, &$like, &$these) {…}
),在序列化/反序列化后引用不会被保留。唯一例外是(仅限 PHP 5.4+)使用的变量是正在序列化的SerializableClosure
对象的引用,这是递归函数的情况。由于某种原因——实际上我不太理解——这可以工作。 - 如果你在一行中定义了两个闭包(你根本不应该这样做),你将无法序列化任何一个,因为不清楚应该解析哪个闭包的代码。
- 由于获取闭包代码和上下文的技术需要反射和完整的 AST 风格解析,因此序列化闭包的性能可能不是很好。
- 警告:反序列化闭包需要
eval()
和extract()
。这些函数被认为很危险,所以你必须评估你是否真的想使用这个库,如果这些函数让你担忧。这些函数 必须 被使用才能使这项技术工作。
安装
要使用 Composer 在项目中安装 Super Closure 库,首先将以下内容添加到你的 composer.json
配置文件中。
{ "require": { "jeremeamia/superclosure": "~1.0" } }
然后运行 Composer 的安装或更新命令以完成安装。请访问 Composer 主页 获取有关如何使用 Composer 的更多信息。
我为什么需要序列化闭包?
嗯,既然你在这里查看这个README,你可能已经有了使用场景。尽管这个概念最初是一个实验,但在野外也有一些用例出现。
例如,在UserScape(http://www.userscape.com)关于Laravel 4和IronMQ的视频(http://vimeo.com/64703617)中,大约7分50秒的时候,他们展示了如何将一个闭包推送到队列作为一个作业,以便由工作进程执行。这很好,因为你不需要为可能非常简单的作业创建一个完整的类。闭包序列化是通过Laravel 4框架中的一个类来完成的,该类基于我较旧版本的SuperClosure。
本质上,这个库允许你在一个进程中创建闭包并在另一个进程中使用它们。甚至可以通过API提供闭包(或算法)作为服务。
谁在使用Super Closure?
- Laravel 4 - 将闭包序列化以推送到作业队列。
- PHP的HTTP Mock - 将闭包序列化以在测试工作流程中发送到远程服务器。
- Jumper - 将闭包序列化以通过SSH在远程主机上运行。
- nicmart/Benchmark - 使用
ClosureParser
来显示基准测试的闭包代码。 - 请告诉我你的项目是否以及如何使用Super Closure。