event-engine/php-data
Immutable PHP value objects and data containers for event-driven apps. Provides typed properties, casting, validation, and convenient hydration from arrays/JSON, plus serialization back to payloads—useful for messages, commands, events, and read models in Event Engine setups.
Installation
composer require event-engine/php-data:^2.1
Add to composer.json under require if not auto-loaded.
First Use Case Define an immutable event object with JSON serialization support:
use EventEngine\Data\Immutable;
class UserRegisteredEvent extends Immutable
{
public function __construct(
public string $userId,
public string $email,
public array $metadata = []
) {}
}
Usage:
$event = new UserRegisteredEvent('123', 'user@example.com', ['source' => 'web']);
// $event->userId = '456'; // Throws Error (immutable)
// Native JSON serialization now works
$json = json_encode($event);
$decoded = json_decode($json, true);
Key Files
src/Immutable.php (core class with JSON support)src/ImmutableCollection.php (for arrays)tests/ (usage examples with serialization tests)Event Modeling with JSON Support
// Domain events as immutable objects with native JSON serialization
class OrderPlacedEvent extends Immutable {
public function __construct(
public string $orderId,
public float $total,
public array $items
) {}
}
// Direct JSON conversion
$json = json_encode(new OrderPlacedEvent('123', 99.99, []));
$event = json_decode($json, false, 512, JSON_THROW_ON_ERROR);
Data Validation Leverage constructor type hints + runtime checks:
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException("Invalid email");
}
Collection Handling
use EventEngine\Data\ImmutableCollection;
$events = new ImmutableCollection([
new UserRegisteredEvent(...),
new UserRegisteredEvent(...),
]);
// Collections also support JSON serialization
$json = json_encode($events);
API Responses Return immutable objects directly from controllers:
return response()->json(new UserRegisteredEvent('123', 'user@example.com'));
event(new OrderPlacedEvent($orderId, $total, $items));
// Will serialize automatically when needed
$requestData = json_decode($request->getContent(), false, 512, JSON_THROW_ON_ERROR);
$event = new UserRegisteredEvent(...array_values($requestData));
$event = new UserRegisteredEvent(...);
$this->assertEquals(json_encode($event), '{"userId":"123","email":"user@example.com"}');
Deep Immutability
// ❌ Breaks immutability
$event = new UserRegisteredEvent('123', 'user@example.com', ['tags' => []]);
$event->metadata['tags'][] = 'premium'; // Mutates!
// ✅ Solution: Use ImmutableCollection for arrays
JSON Serialization Edge Cases
__serialize()/__unserialize():
class CustomEvent extends Immutable {
public function __construct(public DateTime $createdAt) {}
// Required for full JSON support
public function jsonSerialize(): array {
return ['created_at' => $this->createdAt->format('c')];
}
}
Performance
get_object_vars() to inspect properties:
print_r(get_object_vars($event));
if (!json_encode($event)) {
throw new \RuntimeException("Serialization failed");
}
Custom JSON Handling
Implement JsonSerializable interface for complex types:
class ComplexEvent extends Immutable implements JsonSerializable {
public function jsonSerialize(): array {
return [
'id' => $this->id,
'metadata' => $this->metadata->toArray()
];
}
}
Magic Methods
Add __toString() or __invoke() for domain-specific behavior:
public function __toString(): string {
return "Order #{$this->orderId} placed for {$this->total}";
}
Laravel Integration
Use HasFactory with immutable objects:
class UserRegisteredEventFactory {
public function create(): UserRegisteredEvent {
return new UserRegisteredEvent(
Str::uuid()->toString(),
'user@example.com'
);
}
}
// JSON serialization works with factories
$json = json_encode((new UserRegisteredEventFactory())->create());
Collection JSON Support
$collection = new ImmutableCollection([$event1, $event2]);
$json = json_encode($collection); // Works natively
How can I help you explore Laravel packages today?