PHP Luminova: Anonymous Functions and Closure Serializer
Luminova Closure Serializer allows you to convert anonymous functions into a storable string format, so you can save them and restore them later when needed.
The Luminova Closure Serializer allows you to convert anonymous functions (closures) into a storable string format and restore them later into executable functions.
PHP does not natively support serializing closures. Once your application ends, any anonymous function is gone. Luminova solves this by extracting the closure’s source code, captured variables, scope information, and signature, then rebuilding it when needed.
This makes it possible to:
- Store closures in a database
- Cache dynamic logic
- Queue and background-task executable callbacks
- Share runtime-defined logic between processes
- Rehydrate previously defined closures in CLI or web contexts
In short, you can define logic now and execute it later, even across requests.
The serializer signs every serialized closure using sha256 combined with your application key. This ensures the payload has not been tampered with before it is restored.
Important Note
Luminova Closure Serializer is designed for practical, lightweight closure serialization. It signs serialized closures using
sha256together with your application key to ensure integrity.Internally, it evaluates restored closures using
eval, and it does not currently provide advanced handling for dynamically updated global variable references.For straightforward use cases where performance and simplicity are the priority, Luminova’s implementation is efficient and sufficient.
For more complex scenarios, especially where advanced security requirements or deeper global reference handling are critical. Using
Opis Closureis recommended, as it offers extended capabilities and avoids relying onevalduring restoration.
Examples
Below are practical examples showing how the Luminova closure serializer converts anonymous functions into a storable string and restores them back into working closures.
Serialize a Simple Closure
Convert any anonymous function into a string that can be stored in a database, cache, or file.
use Luminova\Utility\Serializer;
$fn = function(string $name): string {
return "Hello, {$name}!";
};
$serialized = Serializer::serialize($fn);
echo $serialized;
// Returns a string representation of the closure.Unserialize and Execute
Restore a previously serialized closure and execute it like a normal function.
use Luminova\Utility\Serializer;
$fn = fn(string $name): string => "Hello, {$name}!";
$serialized = Serializer::serialize($fn);
$closure = Serializer::unserialize($serialized);
echo $closure('World');
// Hello, World!Key point:The restored closure behaves exactly like the original. Parameters and return types are preserved.
Closures Updating Variables by Reference
This example shows how closures can update external variables by reference. When a closure captures a variable by reference (&$var), changes inside the closure persist outside.
use Luminova\Utility\Serializer;
$counter = 0;
$obj = new \stdClass();
$obj->value = 10;
// Capture $counter by reference and $obj by value (object behaves like reference)
$fn = function () use (&$counter, $obj) {
$counter++;
$obj->value++;
return [$counter, $obj->value];
};
$packed = Serializer::serialize($fn);
$restored = Serializer::unserialize($packed);
var_export($restored());
// array (0 => 1,1 => 11)
var_export($restored());
// array (0 => 2,1 => 12)
var_export($restored());
// array (0 => 3,1 => 13)Serialize and Restore Recursive Closure
To serialize a recursive closure. The serializing and then unserializing, closures can be stored or passed around and later executed with its recursion.
use Luminova\Utility\Serializer;
$fn = function (int $n) use (&$fn) {
return $n <= 1 ? 1 : $n * $fn($n - 1);
};
$packed = Serializer::serialize($fn);
$restored = Serializer::unserialize($packed);
// Call the restored closure
echo $restored(5); // Outputs: 120Closures with use Variables
Closures often depend on external variables. These values are captured and restored correctly.
use Luminova\Utility\Serializer;
$testUse = 'TestVar';
$fn = function(string $ctx) use ($testUse): string {
return "Hello {$ctx}, {$testUse}";
};
$packed = Serializer::serialize($fn);
$restored = Serializer::unserialize($packed);
echo $restored('Closure');
// Hello Closure, TestVarNote:
The
$testUsevariable is stored as part of the closure’s context, so the restored version still has access to it.
Capturing Objects
Closures that capture objects are also supported.
use Luminova\Utility\Serializer;
$obj = new stdClass();
$obj->name = 'ObjectName';
$fn = function() use ($obj) {
return "Name: {$obj->name}";
};
$packed = Serializer::serialize($fn);
$restored = Serializer::unserialize($packed);
echo $restored();
// Name: ObjectNameNote:The object state at the time of serialization is preserved.
Binding to $this Scope
Closures created inside objects keep their bound scope.
use Luminova\Utility\Serializer;
use Closure;
$obj = new class {
public string $prefix = 'Scope';
public function getClosure(): Closure {
return function(string $ctx) {
return "{$this->prefix}: {$ctx}";
};
}
};
$fn = $obj->getClosure();
$packed = Serializer::serialize($fn);
$restored = Serializer::unserialize($packed);
echo $restored('Hello');
// Scope: HelloImportant:
The closure remains bound to its original object context after restoration.
Nested Closures
Closures defined inside other closures are handled correctly.
use Luminova\Utility\Serializer;
$fn = function(string $ctx) {
$inner = function(string $name) use ($ctx) {
return "{$ctx} -> {$name}";
};
return $inner('Nested');
};
$packed = Serializer::serialize($fn);
$restored = Serializer::unserialize($packed);
echo $restored('Outer');
// Outer -> NestedMultiple Captured Variables
Closures can capture multiple scalar and array variables.
use Luminova\Utility\Serializer;
$a = 1;
$b = 2;
$c = [3, 4];
$fn = function() use ($a, $b, $c) {
return $a + $b + array_sum($c);
};
$packed = Serializer::serialize($fn);
$restored = Serializer::unserialize($packed);
echo $restored();
// 10Class Definition
- Full namespace:
\Luminova\Utility\Serializer - This class is a Final class
Methods
serialize
Serialize a closure to string.
This method converts a Closure into a string representation that captures its code,scope, and any variables it uses. It handles both regular and arrow functions, andsupports closures that capture variables from their surrounding scope.
public static serialize(\Closure $closure, bool $sign = false): stringParameters:
| Parameter | Type | Description |
|---|---|---|
$closure | \Closure | The closure to serialize. |
$sign | bool | Whether to sign and include a security signature for the serialized closure. |
Return Value:
string - Returns the serialized string representation of the closure.
Throws:
- \Luminova\Exceptions\RuntimeException - If the closure cannot be serialized due to unsupported variable types or other issues.
unserialize
Unserialize a closure from string.
This method takes a serialized string representation of a closure (produced by the serialize method)and reconstructs the original Closure object.
It evaluates the closure code in the correct scope and binds it to the appropriate object if necessary.
public static unserialize(string $serialized, array<string,mixed> $options = []): ?ClosureParameters:
| Parameter | Type | Description |
|---|---|---|
$serialized | string | The serialized string representation of the closure. |
$options | array<string,mixed> | Optional unserialize options or application key for verifying signature:key - Optional sign key of the serialized closure verification.allowed_classes - Weather to allow class (default: true). |
Return Value:
\Closure|null - Returns the unserialized Closure object, or null if the input is invalid or cannot be unserialized.
Throws:
- \Luminova\Exceptions\RuntimeException - If the closure cannot be unserialized due to invalid format, evaluation errors, or other issues.
isClosure
Check if a serialized string is a closure.
This method checks if the given serialized string is a valid closure representation producedby the serialize method.
public static isClosure(string $serialized): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$serialized | string | The serialized string to check. |
Return Value:
bool - Returns true if the string is a valid serialized closure, false otherwise.
isValid
Verify if serialized closure signature is valid.
This method checks if the given serialized string is a valid closure representation producedby the serialize method and verifies signature if is signed.
public static isValid(string $serialized, array<string,mixed> $options = []): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$serialized | string | The serialized closure string. |
$options | array<string,mixed> | Optional unserialize options or application key for verifying signature:key - Optional sign key of the serialized closure verification.allowed_classes - Weather to allow class (default: true). |
Return Value:
bool - Return true if is valid closure, otherwise false.
Throws:
- \Luminova\Exceptions\RuntimeException - If closure is signed and not key was provided and no env(app.key).