{"id":36988229,"url":"https://github.com/rcalicdan/serializer","last_synced_at":"2026-01-13T23:25:01.470Z","repository":{"id":331106579,"uuid":"1125102998","full_name":"rcalicdan/serializer","owner":"rcalicdan","description":"Serializer utility tool for serializing callable for IPC and parallel execution system built on top of opis/closure","archived":false,"fork":false,"pushed_at":"2025-12-30T15:30:12.000Z","size":28,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-03T06:26:44.642Z","etag":null,"topics":["ipc","serialization-library"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rcalicdan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["rcalicdan"]}},"created_at":"2025-12-30T06:34:31.000Z","updated_at":"2025-12-30T15:29:41.000Z","dependencies_parsed_at":"2026-01-03T17:08:10.193Z","dependency_job_id":null,"html_url":"https://github.com/rcalicdan/serializer","commit_stats":null,"previous_names":["rcalicdan/serializer"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/rcalicdan/serializer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcalicdan%2Fserializer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcalicdan%2Fserializer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcalicdan%2Fserializer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcalicdan%2Fserializer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rcalicdan","download_url":"https://codeload.github.com/rcalicdan/serializer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcalicdan%2Fserializer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28405132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ipc","serialization-library"],"created_at":"2026-01-13T23:25:00.659Z","updated_at":"2026-01-13T23:25:01.465Z","avatar_url":"https://github.com/rcalicdan.png","language":"PHP","funding_links":["https://github.com/sponsors/rcalicdan"],"categories":[],"sub_categories":[],"readme":"# Callback Serializer\n\nA 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.\n\n## Installation\n\n```bash\ncomposer require rcalicdan/serializer\n```\n\n## Requirements\n\n- PHP 8.3 or higher\n- opis/closure library (automatically installed as dependency)\n\n## Overview\n\nThe Callback Serializer library provides a robust solution for serializing PHP callbacks, particularly useful for:\n\n- **Parallel execution libraries** that need to pass callbacks between processes\n- **Inter-process communication (IPC)** where callbacks must be serialized and transmitted\n- Queue systems that need to serialize job callbacks\n- Event systems that persist event listeners\n- Workflow engines that save state\n\nThe library **automatically detects the callback type** and uses the appropriate serialization strategy, removing the need for manual callback type checking.\n\n## Basic Usage\n\n### Static API (Recommended)\n\nThe static `CallbackSerializer` class provides a convenient singleton-based API:\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializer;\n\n// Serialize a closure\n$closure = function ($x) {\n    return $x * 2;\n};\n$serialized = CallbackSerializer::serialize($closure);\n\n// Unserialize and execute\n$callback = CallbackSerializer::unserialize($serialized);\n$result = $callback(5); // Returns: 10\n\n// Check if callback can be serialized\nif (CallbackSerializer::canSerialize($closure)) {\n    $serialized = CallbackSerializer::serialize($closure);\n}\n```\n\n### Non-Static API\n\nFor applications requiring multiple independent serializer instances or more control, use the `CallbackSerializationManager` directly:\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializationManager;\n\n// Create a manager instance\n$manager = new CallbackSerializationManager();\n\n// Serialize a callback\n$closure = function ($x) {\n    return $x * 2;\n};\n$serialized = $manager-\u003eserializeCallback($closure);\n\n// Unserialize a callback\n$callback = $manager-\u003eunserializeCallback($serialized);\n$result = $callback(5); // Returns: 10\n\n// Check if callback can be serialized\nif ($manager-\u003ecanSerializeCallback($closure)) {\n    $serialized = $manager-\u003eserializeCallback($closure);\n}\n\n// Get serializer information\n$info = $manager-\u003egetSerializerInfo();\n```\n\n### When to Use Non-Static API\n\nUse `CallbackSerializationManager` directly when you need:\n\n- Multiple independent serializer configurations in the same application\n- Different custom serializers for different contexts\n- More explicit dependency injection\n- Easier unit testing without singleton state\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializationManager;\n\nclass ParallelExecutor\n{\n    private CallbackSerializationManager $serializer;\n\n    public function __construct(?CallbackSerializationManager $serializer = null)\n    {\n        $this-\u003eserializer = $serializer ?? new CallbackSerializationManager();\n    }\n\n    public function executeInParallel(callable $callback, array $data): void\n    {\n        $serialized = $this-\u003eserializer-\u003eserializeCallback($callback);\n        \n        // Send to child process via IPC\n        $this-\u003esendToChildProcess($serialized, $data);\n    }\n\n    private function sendToChildProcess(string $serialized, array $data): void\n    {\n        // IPC implementation\n    }\n}\n```\n\n## Supported Callback Types\n\nThe library automatically detects and handles these callback types:\n\n### 1. String Functions\n\nNative PHP functions passed as strings.\n\n```php\n$callback = 'strtoupper';\n$serialized = CallbackSerializer::serialize($callback);\n$callback = CallbackSerializer::unserialize($serialized);\n\necho $callback('hello'); // Outputs: HELLO\n```\n\n**Priority:** 100 (highest)\n\n### 2. Static Methods\n\nClass static methods as array `[ClassName::class, 'methodName']`.\n\n```php\nclass Calculator\n{\n    public static function add($a, $b)\n    {\n        return $a + $b;\n    }\n}\n\n$callback = [Calculator::class, 'add'];\n$serialized = CallbackSerializer::serialize($callback);\n$callback = CallbackSerializer::unserialize($serialized);\n\necho $callback(5, 3); // Outputs: 8\n```\n\n**Priority:** 90\n\n### 3. Closures\n\nAnonymous functions with variable binding support.\n\n```php\n$multiplier = 10;\n$closure = function ($x) use ($multiplier) {\n    return $x * $multiplier;\n};\n\n$serialized = CallbackSerializer::serialize($closure);\n$callback = CallbackSerializer::unserialize($serialized);\n\necho $callback(5); // Outputs: 50\n```\n\n**Priority:** 80\n\n### 4. Instance Methods\n\nObject instance methods as array `[$object, 'methodName']`.\n\n```php\nclass Greeter\n{\n    private $greeting = 'Hello';\n\n    public function greet($name)\n    {\n        return \"{$this-\u003egreeting}, {$name}!\";\n    }\n}\n\n$greeter = new Greeter();\n$callback = [$greeter, 'greet'];\n\n$serialized = CallbackSerializer::serialize($callback);\n$callback = CallbackSerializer::unserialize($serialized);\n\necho $callback('World'); // Outputs: Hello, World!\n```\n\n**Priority:** 70\n\n### 5. Anonymous Classes\n\nAnonymous class instances with `__invoke` method.\n\n```php\n$callback = new class {\n    public function __invoke($x)\n    {\n        return $x * 2;\n    }\n};\n\n$serialized = CallbackSerializer::serialize($callback);\n$callback = CallbackSerializer::unserialize($serialized);\n\necho $callback(5); // Outputs: 10\n```\n\n**Priority:** 70\n\n### 6. Invokable Objects\n\nRegular class instances with `__invoke` method.\n\n```php\nclass Doubler\n{\n    public function __invoke($x)\n    {\n        return $x * 2;\n    }\n}\n\n$callback = new Doubler();\n$serialized = CallbackSerializer::serialize($callback);\n$callback = CallbackSerializer::unserialize($serialized);\n\necho $callback(5); // Outputs: 10\n```\n\n**Priority:** 60\n\n## Context Serialization\n\nSerialize and unserialize context data (arrays) alongside callbacks, useful for passing state in parallel execution scenarios.\n\n### Static API\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializer;\n\n$context = [\n    'user_id' =\u003e 123,\n    'settings' =\u003e ['theme' =\u003e 'dark'],\n    'callback' =\u003e function ($x) {\n        return $x * 2;\n    },\n];\n\n// Serialize context\n$serialized = CallbackSerializer::serializeContext($context);\n\n// Unserialize context\n$restored = CallbackSerializer::unserializeContext($serialized);\n\n// Context is fully restored including nested callbacks\necho $restored['callback'](5); // Outputs: 10\n\n// Check if context can be serialized\nif (CallbackSerializer::canSerializeContext($context)) {\n    $serialized = CallbackSerializer::serializeContext($context);\n}\n```\n\n### Non-Static API\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializationManager;\n\n$manager = new CallbackSerializationManager();\n\n$context = [\n    'user_id' =\u003e 123,\n    'settings' =\u003e ['theme' =\u003e 'dark'],\n];\n\n// Serialize context\n$serialized = $manager-\u003eserializeContext($context);\n\n// Unserialize context\n$restored = $manager-\u003eunserializeContext($serialized);\n\n// Check if context can be serialized\nif ($manager-\u003ecanSerializeContext($context)) {\n    $serialized = $manager-\u003eserializeContext($context);\n}\n```\n\n## Use Case: Parallel Execution\n\nExample of using the library for parallel execution with IPC:\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializer;\n\n// Parent process\n$task = function ($data) {\n    // Heavy computation\n    return array_sum($data) * 2;\n};\n\n$serializedTask = CallbackSerializer::serialize($task);\n$serializedContext = CallbackSerializer::serializeContext(['data' =\u003e [1, 2, 3, 4, 5]]);\n\n// Send to child process via socket/pipe/shared memory\nsocket_write($socket, $serializedTask);\nsocket_write($socket, $serializedContext);\n\n// Child process\n$serializedTask = socket_read($socket, 8192);\n$serializedContext = socket_read($socket, 8192);\n\n$task = CallbackSerializer::unserialize($serializedTask);\n$context = CallbackSerializer::unserializeContext($serializedContext);\n\n$result = $task($context['data']);\n// Send result back to parent\n```\n\n## Advanced Usage\n\n### Custom Serializers (Static API)\n\nCreate custom serializers for specific callback types by implementing the `CallbackSerializerInterface`.\n\n```php\nuse Rcalicdan\\Serializer\\Interfaces\\CallbackSerializerInterface;\nuse Rcalicdan\\Serializer\\Exceptions\\SerializationException;\nuse Rcalicdan\\Serializer\\CallbackSerializer;\n\nclass CustomSerializer implements CallbackSerializerInterface\n{\n    public function canSerialize(mixed $callback): bool\n    {\n        // Check if this serializer can handle the callback\n        return $callback instanceof MyCustomCallable;\n    }\n\n    public function serialize(mixed $callback): string\n    {\n        // Serialize the callback\n        if (!$this-\u003ecanSerialize($callback)) {\n            throw new SerializationException('Cannot serialize this callback');\n        }\n        \n        return json_encode(['custom' =\u003e $callback-\u003egetData()]);\n    }\n\n    public function unserialize(string $serialized): mixed\n    {\n        // Unserialize the callback\n        $data = json_decode($serialized, true);\n        return new MyCustomCallable($data['custom']);\n    }\n\n    public function getPriority(): int\n    {\n        // Higher priority = checked first (100 = highest)\n        return 95;\n    }\n}\n\n// Register custom serializer\n$customSerializer = new CustomSerializer();\nCallbackSerializer::addSerializer($customSerializer);\n\n// Now your custom serializer will be used automatically\n$callback = new MyCustomCallable();\n$serialized = CallbackSerializer::serialize($callback);\n```\n\n### Custom Serializers (Non-Static API)\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializationManager;\n\n$manager = new CallbackSerializationManager();\n\n// Add custom serializer\n$customSerializer = new CustomSerializer();\n$manager-\u003eaddSerializer($customSerializer);\n\n// Use the manager with custom serializer\n$callback = new MyCustomCallable();\n$serialized = $manager-\u003eserializeCallback($callback);\n```\n\n### Get Serializer Information\n\n#### Static API\n\n```php\n$info = CallbackSerializer::getSerializerInfo();\n\nforeach ($info as $serializer) {\n    echo \"Class: {$serializer['class']}\\n\";\n    echo \"Name: {$serializer['name']}\\n\";\n    echo \"Priority: {$serializer['priority']}\\n\\n\";\n}\n```\n\n#### Non-Static API\n\n```php\n$manager = new CallbackSerializationManager();\n$info = $manager-\u003egetSerializerInfo();\n\nforeach ($info as $serializer) {\n    echo \"Class: {$serializer['class']}\\n\";\n    echo \"Name: {$serializer['name']}\\n\";\n    echo \"Priority: {$serializer['priority']}\\n\\n\";\n}\n```\n\nOutput:\n```\nClass: Rcalicdan\\Serializer\\Serializers\\StringFunctionSerializer\nName: StringFunctionSerializer\nPriority: 100\n\nClass: Rcalicdan\\Serializer\\Serializers\\StaticMethodSerializer\nName: StaticMethodSerializer\nPriority: 90\n\nClass: Rcalicdan\\Serializer\\Serializers\\ClosureSerializer\nName: ClosureSerializer\nPriority: 80\n\n...\n```\n\n### Reset Singleton (Testing)\n\nUseful for resetting the serializer state in unit tests when using the static API.\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializer;\n\n// Reset the singleton instance\nCallbackSerializer::reset();\n\n// Fresh instance with default serializers\n$callback = function () {};\n$serialized = CallbackSerializer::serialize($callback);\n```\n\n## Exception Handling\n\nThe library throws `SerializationException` when serialization or unserialization fails.\n\n```php\nuse Rcalicdan\\Serializer\\CallbackSerializer;\nuse Rcalicdan\\Serializer\\Exceptions\\SerializationException;\n\ntry {\n    $callback = /* some callback */;\n    $serialized = CallbackSerializer::serialize($callback);\n} catch (SerializationException $e) {\n    echo \"Serialization failed: \" . $e-\u003egetMessage();\n}\n\ntry {\n    $callback = CallbackSerializer::unserialize($serialized);\n} catch (SerializationException $e) {\n    echo \"Unserialization failed: \" . $e-\u003egetMessage();\n}\n```\n\n## Architecture\n\n### Automatic Callback Type Detection\n\nThe library uses a priority-based system to automatically detect and handle different callback types. When you call `serialize()`, the library:\n\n1. Iterates through registered serializers in priority order (highest first)\n2. Checks if each serializer can handle the callback using `canSerialize()`\n3. Uses the first matching serializer to perform the serialization\n4. Throws `SerializationException` if no serializer matches\n\nThis automatic detection means you never need to manually determine the callback type.\n\n### Serializer Priority System\n\nSerializers are checked in order of priority (highest first):\n\n1. **StringFunctionSerializer (100)** - Fastest, no complex serialization needed\n2. **StaticMethodSerializer (90)** - Simple string serialization\n3. **ClosureSerializer (80)** - Uses opis/closure for complex serialization\n4. **InstanceMethodSerializer (70)** - Serializes object instances\n5. **AnonymousClassSerializer (70)** - Handles anonymous classes\n6. **InvokableObjectSerializer (60)** - Catches remaining invokable objects\n\n### Singleton Pattern (Static API)\n\nThe static `CallbackSerializer` class uses a singleton pattern to maintain a single instance of `CallbackSerializationManager`, ensuring consistent serializer registration across your application.\n\n### Direct Instantiation (Non-Static API)\n\nThe `CallbackSerializationManager` can be instantiated directly for scenarios requiring multiple independent configurations or better testability.\n\n## Testing\n\n### Testing with Static API\n\n```php\nuse PHPUnit\\Framework\\TestCase;\nuse Rcalicdan\\Serializer\\CallbackSerializer;\n\nclass CallbackSerializerTest extends TestCase\n{\n    protected function setUp(): void\n    {\n        // Reset singleton between tests\n        CallbackSerializer::reset();\n    }\n\n    public function test_can_serialize_closure(): void\n    {\n        $closure = function ($x) {\n            return $x * 2;\n        };\n\n        $this-\u003eassertTrue(CallbackSerializer::canSerialize($closure));\n        \n        $serialized = CallbackSerializer::serialize($closure);\n        $unserialized = CallbackSerializer::unserialize($serialized);\n        \n        $this-\u003eassertEquals(10, $unserialized(5));\n    }\n}\n```\n\n### Testing with Non-Static API\n\n```php\nuse PHPUnit\\Framework\\TestCase;\nuse Rcalicdan\\Serializer\\CallbackSerializationManager;\n\nclass CallbackSerializationManagerTest extends TestCase\n{\n    private CallbackSerializationManager $manager;\n\n    protected function setUp(): void\n    {\n        // Create fresh instance for each test\n        $this-\u003emanager = new CallbackSerializationManager();\n    }\n\n    public function test_can_serialize_closure(): void\n    {\n        $closure = function ($x) {\n            return $x * 2;\n        };\n\n        $this-\u003eassertTrue($this-\u003emanager-\u003ecanSerializeCallback($closure));\n        \n        $serialized = $this-\u003emanager-\u003eserializeCallback($closure);\n        $unserialized = $this-\u003emanager-\u003eunserializeCallback($serialized);\n        \n        $this-\u003eassertEquals(10, $unserialized(5));\n    }\n}\n```\n\n## Limitations\n\n- Closures with resources (file handles, database connections) cannot be serialized\n- Some objects with internal state may not serialize correctly\n- Callbacks referencing unavailable classes will fail on unserialization\n- Serialized callbacks may break if the referenced code changes between serialization and unserialization\n\n## License\n\nMIT License\n\n## Contributing\n\nContributions are welcome! Please submit pull requests or open issues on GitHub.\n\n## Credits\n\nThis library uses [opis/closure](https://github.com/opis/closure) for closure serialization.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frcalicdan%2Fserializer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frcalicdan%2Fserializer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frcalicdan%2Fserializer/lists"}