vchagin/superclosure

序列化闭包,包括它们的上下文

dev-master 2019-05-29 11:06 UTC

This package is auto-updated.

Last update: 2024-09-29 05:08:57 UTC


README

Latest Stable Version Total Downloads Build Status GitTip

你见过这种情况吗?

未捕获异常 '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 安装

注意事项

  1. 对于任何通过引用使用的变量(例如,function () use (&$vars, &$like, &$these) {…}),在序列化/反序列化后引用不会被保留。唯一例外是(仅限 PHP 5.4+)使用的变量是正在序列化的 SerializableClosure 对象的引用,这是递归函数的情况。由于某种原因——实际上我不太理解——这可以工作。
  2. 如果你在一行中定义了两个闭包(你根本不应该这样做),你将无法序列化任何一个,因为不清楚应该解析哪个闭包的代码。
  3. 由于获取闭包代码和上下文的技术需要反射和完整的 AST 风格解析,因此序列化闭包的性能可能不是很好。
  4. 警告:反序列化闭包需要 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。