|
9 éve | |
---|---|---|
.. | ||
demo | 9 éve | |
src | 9 éve | |
tests | 9 éve | |
.gitignore | 9 éve | |
.travis.yml | 9 éve | |
LICENSE.md | 9 éve | |
README.md | 9 éve | |
composer.json | 9 éve | |
phpunit.xml.dist | 9 éve |
Have you ever seen this?
Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed'
It's true! If you try to serialize a Closure
, PHP will throw an exception and tell you that it is not allowed. But
even though it is not "allowed" by PHP, the Super Closure library (jeremeamia/superclosure on Packagist) makes it
possible.
I'm not joking, you really can serialize a PHP closure!
<?php
require 'vendor/autoload.php';
use Jeremeamia\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!
Yep, pretty cool huh?
It all started way back in the beginning of 2010 when PHP 5.3 was starting to gain traction. I wrote a blog post called Extending PHP 5.3 Closures with Serialization and Reflection on my former employers' blog, HTMList, showing how it can be done. Since then I've made a few iterations on the code, and this most recent iteration brings with it a generally more robust solution that takes advantage of the fabulous nikic/php-parser library.
function () use (&$vars, &$like, &$these) {…}
), the references are not
maintained after serialization/unserialization. The only exception is when (in PHP 5.4+ only) the used variable is a
reference to the SerializableClosure
object being serialized, which is the case with a recursive function. For some
reason — that I actually don't quite understand — this works.eval()
and extract()
are required to unserialize the closure. These functions are considered
dangerous by many, so you will have to evaluate whether or not you actual want to be using this library if these
functions concern you. These functions must be used to make this technique work.To install the Super Closure library in your project using Composer, first add the following to your composer.json
config file.
{
"require": {
"jeremeamia/superclosure": "~1.0"
}
}
Then run Composer's install or update commands to complete installation. Please visit the Composer homepage for more information about how to use Composer.
Well, since you are here looking at this README, you may already have a use case in mind. Even though this concept began as an experiment, there have been some use cases that have come up in the wild.
For example, in a video about Laravel 4 and IronMQ by UserScape, at about the 7:50 mark they show how you can push a closure onto a queue as a job so that it can be executed by a worker. This is nice because you do not have to create a whole class for a job that might be really simple. The closure serialization is done by a class in the Laravel 4 framework that is based on one of my older versions of SuperClosure.
Essentially this library let's you create closures in one process and use them in another. It would even be possible to provide closures (or algorithms) as a service through an API.
ClosureParser
to display a benchmarked
Closure's code.