PHPackages                             rcalicdan/serializer - 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. rcalicdan/serializer

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

rcalicdan/serializer
====================

code serializer for ipc and parallel execution libraries built on top of opis/closure

1.0.0(4mo ago)0786MITPHPPHP ^8.3CI passing

Since Dec 30Pushed 4mo agoCompare

[ Source](https://github.com/rcalicdan/serializer)[ Packagist](https://packagist.org/packages/rcalicdan/serializer)[ GitHub Sponsors](https://github.com/rcalicdan)[ RSS](/packages/rcalicdan-serializer/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (4)Versions (2)Used By (0)

Callback Serializer
===================

[](#callback-serializer)

A PHP library for serializing and unserializing various types of callbacks, including closures, static methods, instance methods, and more. This library is primarily designed for parallel execution and inter-process communication (IPC) serialization, automatically detecting callback types and using the appropriate serialization strategy.

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

[](#installation)

```
composer require rcalicdan/serializer
```

Requirements
------------

[](#requirements)

- PHP 8.3 or higher
- opis/closure library (automatically installed as dependency)

Overview
--------

[](#overview)

The Callback Serializer library provides a robust solution for serializing PHP callbacks, particularly useful for:

- **Parallel execution libraries** that need to pass callbacks between processes
- **Inter-process communication (IPC)** where callbacks must be serialized and transmitted
- Queue systems that need to serialize job callbacks
- Event systems that persist event listeners
- Workflow engines that save state

The library **automatically detects the callback type** and uses the appropriate serialization strategy, removing the need for manual callback type checking.

Basic Usage
-----------

[](#basic-usage)

### Static API (Recommended)

[](#static-api-recommended)

The static `CallbackSerializer` class provides a convenient singleton-based API:

```
use Rcalicdan\Serializer\CallbackSerializer;

// Serialize a closure
$closure = function ($x) {
    return $x * 2;
};
$serialized = CallbackSerializer::serialize($closure);

// Unserialize and execute
$callback = CallbackSerializer::unserialize($serialized);
$result = $callback(5); // Returns: 10

// Check if callback can be serialized
if (CallbackSerializer::canSerialize($closure)) {
    $serialized = CallbackSerializer::serialize($closure);
}
```

### Non-Static API

[](#non-static-api)

For applications requiring multiple independent serializer instances or more control, use the `CallbackSerializationManager` directly:

```
use Rcalicdan\Serializer\CallbackSerializationManager;

// Create a manager instance
$manager = new CallbackSerializationManager();

// Serialize a callback
$closure = function ($x) {
    return $x * 2;
};
$serialized = $manager->serializeCallback($closure);

// Unserialize a callback
$callback = $manager->unserializeCallback($serialized);
$result = $callback(5); // Returns: 10

// Check if callback can be serialized
if ($manager->canSerializeCallback($closure)) {
    $serialized = $manager->serializeCallback($closure);
}

// Get serializer information
$info = $manager->getSerializerInfo();
```

### When to Use Non-Static API

[](#when-to-use-non-static-api)

Use `CallbackSerializationManager` directly when you need:

- Multiple independent serializer configurations in the same application
- Different custom serializers for different contexts
- More explicit dependency injection
- Easier unit testing without singleton state

```
use Rcalicdan\Serializer\CallbackSerializationManager;

class ParallelExecutor
{
    private CallbackSerializationManager $serializer;

    public function __construct(?CallbackSerializationManager $serializer = null)
    {
        $this->serializer = $serializer ?? new CallbackSerializationManager();
    }

    public function executeInParallel(callable $callback, array $data): void
    {
        $serialized = $this->serializer->serializeCallback($callback);

        // Send to child process via IPC
        $this->sendToChildProcess($serialized, $data);
    }

    private function sendToChildProcess(string $serialized, array $data): void
    {
        // IPC implementation
    }
}
```

Supported Callback Types
------------------------

[](#supported-callback-types)

The library automatically detects and handles these callback types:

### 1. String Functions

[](#1-string-functions)

Native PHP functions passed as strings.

```
$callback = 'strtoupper';
$serialized = CallbackSerializer::serialize($callback);
$callback = CallbackSerializer::unserialize($serialized);

echo $callback('hello'); // Outputs: HELLO
```

**Priority:** 100 (highest)

### 2. Static Methods

[](#2-static-methods)

Class static methods as array `[ClassName::class, 'methodName']`.

```
class Calculator
{
    public static function add($a, $b)
    {
        return $a + $b;
    }
}

$callback = [Calculator::class, 'add'];
$serialized = CallbackSerializer::serialize($callback);
$callback = CallbackSerializer::unserialize($serialized);

echo $callback(5, 3); // Outputs: 8
```

**Priority:** 90

### 3. Closures

[](#3-closures)

Anonymous functions with variable binding support.

```
$multiplier = 10;
$closure = function ($x) use ($multiplier) {
    return $x * $multiplier;
};

$serialized = CallbackSerializer::serialize($closure);
$callback = CallbackSerializer::unserialize($serialized);

echo $callback(5); // Outputs: 50
```

**Priority:** 80

### 4. Instance Methods

[](#4-instance-methods)

Object instance methods as array `[$object, 'methodName']`.

```
class Greeter
{
    private $greeting = 'Hello';

    public function greet($name)
    {
        return "{$this->greeting}, {$name}!";
    }
}

$greeter = new Greeter();
$callback = [$greeter, 'greet'];

$serialized = CallbackSerializer::serialize($callback);
$callback = CallbackSerializer::unserialize($serialized);

echo $callback('World'); // Outputs: Hello, World!
```

**Priority:** 70

### 5. Anonymous Classes

[](#5-anonymous-classes)

Anonymous class instances with `__invoke` method.

```
$callback = new class {
    public function __invoke($x)
    {
        return $x * 2;
    }
};

$serialized = CallbackSerializer::serialize($callback);
$callback = CallbackSerializer::unserialize($serialized);

echo $callback(5); // Outputs: 10
```

**Priority:** 70

### 6. Invokable Objects

[](#6-invokable-objects)

Regular class instances with `__invoke` method.

```
class Doubler
{
    public function __invoke($x)
    {
        return $x * 2;
    }
}

$callback = new Doubler();
$serialized = CallbackSerializer::serialize($callback);
$callback = CallbackSerializer::unserialize($serialized);

echo $callback(5); // Outputs: 10
```

**Priority:** 60

Context Serialization
---------------------

[](#context-serialization)

Serialize and unserialize context data (arrays) alongside callbacks, useful for passing state in parallel execution scenarios.

### Static API

[](#static-api)

```
use Rcalicdan\Serializer\CallbackSerializer;

$context = [
    'user_id' => 123,
    'settings' => ['theme' => 'dark'],
    'callback' => function ($x) {
        return $x * 2;
    },
];

// Serialize context
$serialized = CallbackSerializer::serializeContext($context);

// Unserialize context
$restored = CallbackSerializer::unserializeContext($serialized);

// Context is fully restored including nested callbacks
echo $restored['callback'](5); // Outputs: 10

// Check if context can be serialized
if (CallbackSerializer::canSerializeContext($context)) {
    $serialized = CallbackSerializer::serializeContext($context);
}
```

### Non-Static API

[](#non-static-api-1)

```
use Rcalicdan\Serializer\CallbackSerializationManager;

$manager = new CallbackSerializationManager();

$context = [
    'user_id' => 123,
    'settings' => ['theme' => 'dark'],
];

// Serialize context
$serialized = $manager->serializeContext($context);

// Unserialize context
$restored = $manager->unserializeContext($serialized);

// Check if context can be serialized
if ($manager->canSerializeContext($context)) {
    $serialized = $manager->serializeContext($context);
}
```

Use Case: Parallel Execution
----------------------------

[](#use-case-parallel-execution)

Example of using the library for parallel execution with IPC:

```
use Rcalicdan\Serializer\CallbackSerializer;

// Parent process
$task = function ($data) {
    // Heavy computation
    return array_sum($data) * 2;
};

$serializedTask = CallbackSerializer::serialize($task);
$serializedContext = CallbackSerializer::serializeContext(['data' => [1, 2, 3, 4, 5]]);

// Send to child process via socket/pipe/shared memory
socket_write($socket, $serializedTask);
socket_write($socket, $serializedContext);

// Child process
$serializedTask = socket_read($socket, 8192);
$serializedContext = socket_read($socket, 8192);

$task = CallbackSerializer::unserialize($serializedTask);
$context = CallbackSerializer::unserializeContext($serializedContext);

$result = $task($context['data']);
// Send result back to parent
```

Advanced Usage
--------------

[](#advanced-usage)

### Custom Serializers (Static API)

[](#custom-serializers-static-api)

Create custom serializers for specific callback types by implementing the `CallbackSerializerInterface`.

```
use Rcalicdan\Serializer\Interfaces\CallbackSerializerInterface;
use Rcalicdan\Serializer\Exceptions\SerializationException;
use Rcalicdan\Serializer\CallbackSerializer;

class CustomSerializer implements CallbackSerializerInterface
{
    public function canSerialize(mixed $callback): bool
    {
        // Check if this serializer can handle the callback
        return $callback instanceof MyCustomCallable;
    }

    public function serialize(mixed $callback): string
    {
        // Serialize the callback
        if (!$this->canSerialize($callback)) {
            throw new SerializationException('Cannot serialize this callback');
        }

        return json_encode(['custom' => $callback->getData()]);
    }

    public function unserialize(string $serialized): mixed
    {
        // Unserialize the callback
        $data = json_decode($serialized, true);
        return new MyCustomCallable($data['custom']);
    }

    public function getPriority(): int
    {
        // Higher priority = checked first (100 = highest)
        return 95;
    }
}

// Register custom serializer
$customSerializer = new CustomSerializer();
CallbackSerializer::addSerializer($customSerializer);

// Now your custom serializer will be used automatically
$callback = new MyCustomCallable();
$serialized = CallbackSerializer::serialize($callback);
```

### Custom Serializers (Non-Static API)

[](#custom-serializers-non-static-api)

```
use Rcalicdan\Serializer\CallbackSerializationManager;

$manager = new CallbackSerializationManager();

// Add custom serializer
$customSerializer = new CustomSerializer();
$manager->addSerializer($customSerializer);

// Use the manager with custom serializer
$callback = new MyCustomCallable();
$serialized = $manager->serializeCallback($callback);
```

### Get Serializer Information

[](#get-serializer-information)

#### Static API

[](#static-api-1)

```
$info = CallbackSerializer::getSerializerInfo();

foreach ($info as $serializer) {
    echo "Class: {$serializer['class']}\n";
    echo "Name: {$serializer['name']}\n";
    echo "Priority: {$serializer['priority']}\n\n";
}
```

#### Non-Static API

[](#non-static-api-2)

```
$manager = new CallbackSerializationManager();
$info = $manager->getSerializerInfo();

foreach ($info as $serializer) {
    echo "Class: {$serializer['class']}\n";
    echo "Name: {$serializer['name']}\n";
    echo "Priority: {$serializer['priority']}\n\n";
}
```

Output:

```
Class: Rcalicdan\Serializer\Serializers\StringFunctionSerializer
Name: StringFunctionSerializer
Priority: 100

Class: Rcalicdan\Serializer\Serializers\StaticMethodSerializer
Name: StaticMethodSerializer
Priority: 90

Class: Rcalicdan\Serializer\Serializers\ClosureSerializer
Name: ClosureSerializer
Priority: 80

...

```

### Reset Singleton (Testing)

[](#reset-singleton-testing)

Useful for resetting the serializer state in unit tests when using the static API.

```
use Rcalicdan\Serializer\CallbackSerializer;

// Reset the singleton instance
CallbackSerializer::reset();

// Fresh instance with default serializers
$callback = function () {};
$serialized = CallbackSerializer::serialize($callback);
```

Exception Handling
------------------

[](#exception-handling)

The library throws `SerializationException` when serialization or unserialization fails.

```
use Rcalicdan\Serializer\CallbackSerializer;
use Rcalicdan\Serializer\Exceptions\SerializationException;

try {
    $callback = /* some callback */;
    $serialized = CallbackSerializer::serialize($callback);
} catch (SerializationException $e) {
    echo "Serialization failed: " . $e->getMessage();
}

try {
    $callback = CallbackSerializer::unserialize($serialized);
} catch (SerializationException $e) {
    echo "Unserialization failed: " . $e->getMessage();
}
```

Architecture
------------

[](#architecture)

### Automatic Callback Type Detection

[](#automatic-callback-type-detection)

The library uses a priority-based system to automatically detect and handle different callback types. When you call `serialize()`, the library:

1. Iterates through registered serializers in priority order (highest first)
2. Checks if each serializer can handle the callback using `canSerialize()`
3. Uses the first matching serializer to perform the serialization
4. Throws `SerializationException` if no serializer matches

This automatic detection means you never need to manually determine the callback type.

### Serializer Priority System

[](#serializer-priority-system)

Serializers are checked in order of priority (highest first):

1. **StringFunctionSerializer (100)** - Fastest, no complex serialization needed
2. **StaticMethodSerializer (90)** - Simple string serialization
3. **ClosureSerializer (80)** - Uses opis/closure for complex serialization
4. **InstanceMethodSerializer (70)** - Serializes object instances
5. **AnonymousClassSerializer (70)** - Handles anonymous classes
6. **InvokableObjectSerializer (60)** - Catches remaining invokable objects

### Singleton Pattern (Static API)

[](#singleton-pattern-static-api)

The static `CallbackSerializer` class uses a singleton pattern to maintain a single instance of `CallbackSerializationManager`, ensuring consistent serializer registration across your application.

### Direct Instantiation (Non-Static API)

[](#direct-instantiation-non-static-api)

The `CallbackSerializationManager` can be instantiated directly for scenarios requiring multiple independent configurations or better testability.

Testing
-------

[](#testing)

### Testing with Static API

[](#testing-with-static-api)

```
use PHPUnit\Framework\TestCase;
use Rcalicdan\Serializer\CallbackSerializer;

class CallbackSerializerTest extends TestCase
{
    protected function setUp(): void
    {
        // Reset singleton between tests
        CallbackSerializer::reset();
    }

    public function test_can_serialize_closure(): void
    {
        $closure = function ($x) {
            return $x * 2;
        };

        $this->assertTrue(CallbackSerializer::canSerialize($closure));

        $serialized = CallbackSerializer::serialize($closure);
        $unserialized = CallbackSerializer::unserialize($serialized);

        $this->assertEquals(10, $unserialized(5));
    }
}
```

### Testing with Non-Static API

[](#testing-with-non-static-api)

```
use PHPUnit\Framework\TestCase;
use Rcalicdan\Serializer\CallbackSerializationManager;

class CallbackSerializationManagerTest extends TestCase
{
    private CallbackSerializationManager $manager;

    protected function setUp(): void
    {
        // Create fresh instance for each test
        $this->manager = new CallbackSerializationManager();
    }

    public function test_can_serialize_closure(): void
    {
        $closure = function ($x) {
            return $x * 2;
        };

        $this->assertTrue($this->manager->canSerializeCallback($closure));

        $serialized = $this->manager->serializeCallback($closure);
        $unserialized = $this->manager->unserializeCallback($serialized);

        $this->assertEquals(10, $unserialized(5));
    }
}
```

Limitations
-----------

[](#limitations)

- Closures with resources (file handles, database connections) cannot be serialized
- Some objects with internal state may not serialize correctly
- Callbacks referencing unavailable classes will fail on unserialization
- Serialized callbacks may break if the referenced code changes between serialization and unserialization

License
-------

[](#license)

MIT License

Contributing
------------

[](#contributing)

Contributions are welcome! Please submit pull requests or open issues on GitHub.

Credits
-------

[](#credits)

This library uses [opis/closure](https://github.com/opis/closure) for closure serialization.

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance74

Regular maintenance activity

Popularity20

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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

Unknown

Total

1

Last Release

139d ago

### Community

Maintainers

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

---

Top Contributors

[![rcalicdan](https://avatars.githubusercontent.com/u/163510169?v=4)](https://github.com/rcalicdan "rcalicdan (3 commits)")

---

Tags

ipcserialization-library

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/rcalicdan-serializer/health.svg)

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

###  Alternatives

[masterminds/html5

An HTML5 parser and serializer.

1.8k242.8M229](/packages/masterminds-html5)[sabberworm/php-css-parser

Parser for CSS Files written in PHP

1.8k191.2M65](/packages/sabberworm-php-css-parser)[jms/metadata

Class/method/property metadata management in PHP

1.8k152.8M88](/packages/jms-metadata)[jms/serializer-bundle

Allows you to easily serialize, and deserialize data of any complexity

1.8k89.3M627](/packages/jms-serializer-bundle)[hassankhan/config

Lightweight configuration file loader that supports PHP, INI, XML, JSON, and YAML files

97513.5M170](/packages/hassankhan-config)[meyfa/php-svg

Read, edit, write, and render SVG files with PHP

54613.9M42](/packages/meyfa-php-svg)

PHPackages © 2026

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