PHPackages                             antto1/superclosure - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. antto1/superclosure

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

antto1/superclosure
===================

Serialize Closure objects, including their context and binding

v2.4.1(5y ago)01611MITPHPPHP &gt;=5.4

Since Apr 14Pushed 5y agoCompare

[ Source](https://github.com/antto1/superclosure)[ Packagist](https://packagist.org/packages/antto1/superclosure)[ RSS](/packages/antto1-superclosure/feed)WikiDiscussions master Synced 5d ago

READMEChangelog (1)Dependencies (3)Versions (23)Used By (1)

PHP SuperClosure
================

[](#php-superclosure)

A PHP Library for serializing closures and anonymous functions.

---

No Longer Maintained
--------------------

[](#no-longer-maintained)

This software is no longer maintained. Consider using [opis/closure](https://github.com/opis/closure) instead.

The rest of the README will remain intact as it was prior to the software being abandoned.

---

Introduction
------------

[](#introduction)

Once upon a time, I tried to serialize a PHP `Closure` object. As you can probably guess, it doesn't work at all. In fact, you get a very specific error message from the PHP Runtime:

> Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed'

Even though serializing closures is "not allowed" by PHP, the SuperClosure library makes it **possible**. Here's the way you use it:

```
use SuperClosure\Serializer;

$serializer = new Serializer();

$greeting = 'Hello';
$hello = function ($name = 'World') use ($greeting) {
    echo "{$greeting}, {$name}!\n";
};

$hello('Jeremy');
//> Hello, Jeremy!

$serialized = $serializer->serialize($hello);
// ...
$unserialized = $serializer->unserialize($serialized);

$unserialized('Jeremy');
//> Hello, Jeremy!
```

Yep, pretty cool, right?

### Features

[](#features)

SuperClosure comes with two different **Closure Analyzers**, which each support different features regarding the serialization of closures. The `TokenAnalyzer`is not as robust as the `AstAnalyzer`, but it is around 20-25 times faster. Using the table below, and keeping in mind what your closure's code looks like, you should *choose the fastest analyzer that supports the features you need*.

   Supported Features Via `AstAnalyzer` Via `TokenAnalyzer`      Regular closures (anonymous functions)
 `$fn = function (...) {...};`  Yes Yes    Closures with context
 `$fn = function () use ($a, $b, ...) {...};`  Yes Yes    Recursive closures
 `$fn = function () use (&$fn, ...) {...};`  Yes Yes    Closures bound to an object
 `$fn = function () {$this->something(); ...};`  Yes Yes    Closures scoped to an object
 `$fn = function () {self::something(); ...};`  Yes Yes    Static closures (i.e, preserves the `static`-ness)
 `$fn = static function () {...};`  Yes --    Closures with class name in params
 `$fn = function (Foo $foo) {...};`  Yes --    Closures with class name in body
 `$fn = function () {$foo = new Foo; ...};`  Yes --    Closures with magic constants
 `$fn = function () {$file = __FILE__; ...};`  Yes --   Performance *Slow* *Fast*  ### Caveats

[](#caveats)

1. For any variables used by reference (e.g., `function () use (&$vars, &$like,   &$these) {…}`), the references are not maintained after serialization. The only exception to this is recursive closure references.
2. If you have two closures defined on a single line (why would you do this anyway?), you will not be able to serialize either one since it is ambiguous which closure's code should be parsed (they are *anonymous* functions after all).
3. **Warning**: The `eval()` function is required to unserialize the closure. This function is considered dangerous by many, so you will have to evaluate what precautions you may need to take when using this library. You should only unserialize closures retrieved from a trusted source, otherwise you are opening yourself up to code injection attacks. It is a good idea sign serialized closures if you plan on storing or transporting them. Read the **Signing Closures** section below for details on how to do this.
4. Cannot serialize closures that are defined within `eval()`'d code. This includes re-serializing a closure that has been unserialized.

### Analyzers

[](#analyzers)

You can choose the analyzer you want to use when you instantiate the `Serializer`. If you do not specify one, the `AstAnalyzer` is used by default, since it has the most capabilities.

```
use SuperClosure\Serializer;
use SuperClosure\Analyzer\AstAnalyzer;
use SuperClosure\Analyzer\TokenAnalyzer;

// Use the default analyzer.
$serializer = new Serializer();

// Explicitly choose an analyzer.
$serializer = new Serializer(new AstAnalyzer());
// OR
$serializer = new Serializer(new TokenAnalyzer());
```

Analyzers are also useful on their own if you are just looking to do some introspection on a Closure object. Check out what is returned when using the `AstAnalyzer`:

```
use SuperClosure\Analyzer\AstAnalyzer;

class Calculator
{
    public function getAdder($operand)
    {
        return function ($number) use ($operand) {
            return $number + $operand;
        };
    }
}

$closure = (new Calculator)->getAdder(5);
$analyzer = new AstAnalyzer();

var_dump($analyzer->analyze($closure));
// array(10) {
//   'reflection' => class ReflectionFunction#5 (1) {...}
//   'code' => string(68) "function ($number) use($operand) {
//     return $number + $operand;
// };"
//   'hasThis' => bool(false)
//   'context' => array(1) {
//     'operand' => int(5)
//   }
//   'hasRefs' => bool(false)
//   'binding' => class Calculator#2 (0) {...}
//   'scope' => string(10) "Calculator"
//   'isStatic' => bool(false)
//   'ast' => class PhpParser\Node\Expr\Closure#13 (2) {...}
//   'location' => array(8) {
//     'class' => string(11) "\Calculator"
//     'directory' => string(47) "/Users/lindblom/Projects/{...}/SuperClosureTest"
//     'file' => string(58) "/Users/lindblom/Projects/{...}/SuperClosureTest/simple.php"
//     'function' => string(9) "{closure}"
//     'line' => int(11)
//     'method' => string(22) "\Calculator::{closure}"
//     'namespace' => NULL
//     'trait' => NULL
//   }
// }
```

### Signing Closures

[](#signing-closures)

Version 2.1+ of SuperClosure allows you to specify a signing key, when you instantiate the Serializer. Doing this will configure your Serializer to sign any closures you serialize and verify the signatures of any closures you unserialize. Doing this can help protect you from code injection attacks that could potentially happen if someone tampered with a serialized closure. *Remember to keep your signing key secret*.

```
$serializer1 = new SuperClosure\Serializer(null, $yourSecretSigningKey);
$data = $serializer1->serialize(function () {echo "Hello!\n";});
echo $data . "\n";
// %rv9zNtTArySx/1803fgk3rPS1RO4uOPPaoZfTRWp554=C:32:"SuperClosure\Serializa...

$serializer2 = new SuperClosure\Serializer(null, $incorrectKey);
try {
    $fn = $serializer2->unserialize($data);
} catch (SuperClosure\Exception\ClosureUnserializationException $e) {
    echo $e->getMessage() . "\n";
}
// The signature of the closure's data is invalid, which means the serialized
// closure has been modified and is unsafe to unserialize.
```

Installation
------------

[](#installation)

To install the Super Closure library in your project using Composer, simply require the project with Composer:

```
$ composer require antto1/superclosure
```

You may of course manually update your require block if you so choose:

```
{
    "require": {
        "antto1/superclosure": "^2.0"
    }
}
```

Please visit the [Composer homepage](http://getcomposer.org) for more information about how to use Composer.

Why would I need to serialize a closure?
----------------------------------------

[](#why-would-i-need-to-serialize-a-closure)

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 and IronMQ](http://vimeo.com/64703617) by [UserScape](http://www.userscape.com), 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.

Or... you might have a dependency injection container or router object that is built by writing closures. If you wanted to cache that, you would need to be able to serialize it.

In general, however, serializing closures should probably be avoided.

Tell me about how this project started
--------------------------------------

[](#tell-me-about-how-this-project-started)

It all started back in the beginning of 2010 when PHP 5.3 was starting to gain traction. I set out to prove that serializing a closure could be done, despite that PHP wouldn't let me do it. I wrote a blog post called [Extending PHP 5.3 Closures with Serialization and Reflection](http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/) on my former employers' blog, [HTMList](http://www.htmlist.com), showing how it could be done. I also released the code on GitHub.

Since then, I've made a few iterations on the code, and the most recent iterations have been more robust, thanks to the usage of the fabulous [nikic/php-parser](https://github.com/nikic/PHP-Parser) library.

Alternatives
------------

[](#alternatives)

This year the [Opis Closure](https://github.com/opis/closure) library has been introduced, that also provides the ability to serialize a closure. You should check it out as well and see which one suits your needs the best.

If you wish to export your closures as executable PHP code instead, you can check out the [brick/varexporter](https://github.com/brick/varexporter) library.

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community18

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 55% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~150 days

Recently: every ~456 days

Total

22

Last Release

1991d ago

Major Versions

0.9.2 → 1.0.02013-06-14

0.8.x-dev → 1.0.12013-10-09

1.0.1 → 2.0-alpha12014-01-14

1.0.x-dev → 2.0.0-beta.12015-01-19

PHP version history (3 changes)0.9.0PHP &gt;=5.3.2

0.9.1PHP &gt;=5.3.3

2.0.0-beta.1PHP &gt;=5.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/ab906c15ebe608890964a47d5eff83636a052d234abb472223a8304309ea1ef9?d=identicon)[antto](/maintainers/antto)

---

Top Contributors

[![jeremeamia](https://avatars.githubusercontent.com/u/107867?v=4)](https://github.com/jeremeamia "jeremeamia (94 commits)")[![GrahamCampbell](https://avatars.githubusercontent.com/u/2829600?v=4)](https://github.com/GrahamCampbell "GrahamCampbell (62 commits)")[![lstrojny](https://avatars.githubusercontent.com/u/79707?v=4)](https://github.com/lstrojny "lstrojny (2 commits)")[![nikic](https://avatars.githubusercontent.com/u/216080?v=4)](https://github.com/nikic "nikic (2 commits)")[![baytech-anson](https://avatars.githubusercontent.com/u/6721633?v=4)](https://github.com/baytech-anson "baytech-anson (2 commits)")[![jrbasso](https://avatars.githubusercontent.com/u/26548?v=4)](https://github.com/jrbasso "jrbasso (1 commits)")[![mnapoli](https://avatars.githubusercontent.com/u/720328?v=4)](https://github.com/mnapoli "mnapoli (1 commits)")[![ntzm](https://avatars.githubusercontent.com/u/3888578?v=4)](https://github.com/ntzm "ntzm (1 commits)")[![asgrim](https://avatars.githubusercontent.com/u/496145?v=4)](https://github.com/asgrim "asgrim (1 commits)")[![Remo](https://avatars.githubusercontent.com/u/129864?v=4)](https://github.com/Remo "Remo (1 commits)")[![BenMorel](https://avatars.githubusercontent.com/u/1952838?v=4)](https://github.com/BenMorel "BenMorel (1 commits)")[![dortort](https://avatars.githubusercontent.com/u/1169721?v=4)](https://github.com/dortort "dortort (1 commits)")[![drbyte](https://avatars.githubusercontent.com/u/404472?v=4)](https://github.com/drbyte "drbyte (1 commits)")[![florianv](https://avatars.githubusercontent.com/u/1586668?v=4)](https://github.com/florianv "florianv (1 commits)")

---

Tags

parserserializeserializableclosurefunctiontokenizerlambda

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/antto1-superclosure/health.svg)

```
[![Health](https://phpackages.com/badges/antto1-superclosure/health.svg)](https://phpackages.com/packages/antto1-superclosure)
```

###  Alternatives

[opis/closure

A library that can be used to serialize closures (anonymous functions) and arbitrary data.

2.6k230.0M284](/packages/opis-closure)[jeremeamia/functionparser

Function parser for PHP functions, methods, and closures

48169.7k6](/packages/jeremeamia-functionparser)[nicoswd/php-rule-parser

Rule Engine - Rule Parser &amp; Evaluator

13078.6k7](/packages/nicoswd-php-rule-parser)[composer-unused/symbol-parser

Toolkit to parse symbols from a composer package

145.7M2](/packages/composer-unused-symbol-parser)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
