https://github.com/texthtml/vo-identity
https://github.com/texthtml/vo-identity
Last synced: 3 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/texthtml/vo-identity
- Owner: texthtml
- License: mit
- Created: 2024-09-19T12:25:14.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-02-06T10:41:44.000Z (4 months ago)
- Last Synced: 2026-02-06T18:25:29.925Z (4 months ago)
- Language: PHP
- Size: 35.2 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# VO Identity
Make comparing Value Objects for equality easier & safer.
# Installation
```bash
composer req texthtml/vo-identity
```
# Usage
```php
final readonly class UserID
{
use TH\VOIdentity\Identity;
private function __construct(private int $i) {}
}
$ua = UserID::of(42);
$ub = UserID::of(42);
$uc = UserID::of(24);
assert($ua === $ub); // $ua & $ub reference the same object so they can be compared with `===`
assert($ua !== $uc);
```
# How does it work?
The `Identity` trait implements a named constructor `::of()` that takes the same arguments as the Value Object
constructor. And return the same instance of the Value Object when an identical Value Object than a previous one would
have been created.
To identify identical Value Object, `$vo->identity()` is called and should return a valid array key. A weak reference to
the object will be kept in a cache using that key. The next time an object would be created, if a reference with that
ley exists it will be returned. The default implementation of `$vo->identity()` is using `serialize($vo)` to generate
the the ID. This is valid but can generate large string and be time consuming for large objects. For better performance,
it is recommended to override it with a specialized implementation. e.g.:
```php
final readonly class UserID
{
use TH\VOIdentity\Identity;
private function __construct(private int $id) {}
protected function identity(): int
{
return $this->id;
}
}
```
You can also opt-in to implemented `inputIdentity()` to compute the key from the constructor arguments, and thus avoid having to construct the Value Object if not needed. e.g.:
```php
final readonly class UserID
{
use TH\VOIdentity\Identity;
private function __construct(private int $id) {}
protected function inputIdentity(int $id): int
{
return $id;
}
}
```
## Garbage collection
By keeping only a weak reference to the first created instance, this let PHP able to garbage collect the Value Objects
when they are not referenced anywhere else and avoid memory leaks.
# Requirements
To work properly a few rules must be respected:
* The object must be immutable and final
* The constructor should be pure (calling it with the same argument should always produce the same result)
# Notes
## Cloning
It's not allowed to clone a Value Object using `Identity`. Doing so would defeat the purpose by creating a new instance
of a Value Object having the same inner value.
## Unserializing
PHP `__unserialize()` can't be implemented in a way that an already existing instance of an object is returned instead
of a new instance. Because of that it's not allowed to `unserialize()` a previously `serialize()`'d Value Objects. Of
course, serializing and unserializing them with other tools is possible (e.g. with the Symfony Serializer, or as a
custom Doctrine type.
## Exporting
It is possible to serialize a Value Object with `var_export()` and `eval()` the corresponding export to get a PHP
instance. If the object properties doesn't match the constructor `__set_state()` will need to be overriden.