Skip to content

Commit 2901b2a

Browse files
committed
chore: Use PHP 8.2 readonly class feature and add toNative() and equals() method
1 parent f3327f2 commit 2901b2a

19 files changed

+506
-198
lines changed

README.md

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# PHP ^8.1 Value Objects Redux
22

3-
Opinionated PHP immutable value object example with deep nesting, `\JsonSerializable`, `\IteratorAggregate`, `snake_case` and `camelCase`. Please see source and tests for more details.
3+
Opinionated PHP immutable value object example with deep nesting, `\JsonSerializable`, `\IteratorAggregate`, `snake_case` and `camelCase`. Please see `example-php`, source and tests for more details.
44

55
- simple and short immutable value objects
6-
- plain value objects have 2 methods `fromNative(...)` and `jsonSerialize()`
6+
- plain value objects have 4 methods `fromNative(...)`, `toNative()`, `equals(...)` and `jsonSerialize()`
77
- records have additional 2 methods `with(iterable|self $data)` and `getIterator()`
88
- records are traversable, you can iterate over the properties
99
- union types for creating value objects from scalar or same value object type
@@ -14,9 +14,11 @@ Opinionated PHP immutable value object example with deep nesting, `\JsonSerializ
1414
**Example for a String value object:**
1515

1616
```php
17-
final class FirstName implements Immutable, \Stringable
17+
final readonly class FirstName implements Immutable, \Stringable
1818
{
19-
private function __construct(public readonly string $val)
19+
use FuncTrait;
20+
21+
private function __construct(public readonly string $v)
2022
{
2123
}
2224

@@ -25,49 +27,61 @@ final class FirstName implements Immutable, \Stringable
2527
return $firstName instanceof self ? $firstName : new self($firstName);
2628
}
2729

30+
public function toNative(): string
31+
{
32+
return $this->jsonSerialize();
33+
}
34+
2835
public function jsonSerialize(): string
2936
{
30-
return $this->val;
37+
return $this->v;
3138
}
3239

3340
public function __toString(): string
3441
{
35-
return $this->val;
42+
return $this->v;
3643
}
3744
}
3845
```
3946

4047
**Example for a date value object:**
4148

4249
```php
43-
final class LastLogin implements \Stringable, Immutable
50+
final readonly class LastLogin implements \Stringable, Immutable
4451
{
52+
use FuncTrait;
53+
4554
private const OUTPUT_FORMAT = 'Y-m-d\TH:i:sP';
4655

47-
public static function fromNative(string|int|DateTimeImmutable|self $val): self
56+
public static function fromNative(string|int|DateTimeImmutable|self $v): self
4857
{
49-
switch (\gettype($val)) {
58+
switch (\gettype($v)) {
5059
case 'integer':
51-
$datetime = (new DateTimeImmutable())->setTimestamp($val);
60+
$datetime = (new DateTimeImmutable())->setTimestamp($v);
5261

5362
break;
5463
case 'string':
55-
$datetime = new DateTimeImmutable($val);
64+
$datetime = new DateTimeImmutable($v);
5665

5766
break;
5867
default:
59-
if ($val instanceof self) {
60-
return $val;
68+
if ($v instanceof self) {
69+
return $v;
6170
}
62-
$datetime = $val;
71+
$datetime = $v;
6372

6473
break;
6574
}
6675

6776
return new self(self::ensureUtc($datetime));
6877
}
6978

70-
private function __construct(public readonly DateTimeImmutable $val)
79+
public function toNative(): string
80+
{
81+
return $this->jsonSerialize();
82+
}
83+
84+
private function __construct(public readonly DateTimeImmutable $v)
7185
{
7286
}
7387

@@ -87,7 +101,7 @@ final class LastLogin implements \Stringable, Immutable
87101

88102
public function jsonSerialize(): string
89103
{
90-
return $this->val->format(self::OUTPUT_FORMAT);
104+
return $this->v->format(self::OUTPUT_FORMAT);
91105
}
92106
}
93107
```
@@ -97,6 +111,8 @@ final class LastLogin implements \Stringable, Immutable
97111
```php
98112
final class Account implements ImmutableRecord
99113
{
114+
use FuncTrait;
115+
100116
private static array $__objectKeys;
101117

102118
private function __construct(
@@ -108,11 +124,19 @@ final class Account implements ImmutableRecord
108124
) {
109125
}
110126

127+
/**
128+
* @param iterable{firstName : string, lastName : string, age : int|null, address : array} $data
129+
*/
111130
public static function fromNative(iterable|self $data): static
112131
{
113132
return $data instanceof self ? $data : new self(...self::convertFromNative($data));
114133
}
115134

135+
public function toNative(): array
136+
{
137+
return $this->jsonSerialize();
138+
}
139+
116140
public function with(iterable|self $data): static
117141
{
118142
return new self(...self::convertFromNative([...\get_object_vars($this), ...$data]));
@@ -121,18 +145,20 @@ final class Account implements ImmutableRecord
121145
public function getIterator(): Traversable
122146
{
123147
yield 'firstName' => $this->firstName;
148+
yield 'lastName' => $this->lastName;
124149
yield 'age' => $this->age;
125150
yield 'address' => $this->address->getIterator();
151+
yield 'active' => $this->active;
126152
}
127153

128154
public function jsonSerialize(): array
129155
{
130156
return [
131-
'firstName' => $this->firstName->val,
132-
'lastName' => $this->lastName->val,
133-
'age' => $this->age?->val,
157+
'firstName' => $this->firstName->v,
158+
'lastName' => $this->lastName->v,
159+
'age' => $this->age?->v,
134160
'address' => $this->address->jsonSerialize(),
135-
'active' => $this->active->val,
161+
'active' => $this->active->v,
136162
];
137163
}
138164

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
"name": "Sandro Keil"
1818
}
1919
],
20+
"require": {
21+
"php": "^8.2"
22+
},
2023
"require-dev": {
2124
"vimeo/psalm": "^5.7.4",
2225
"phpunit/phpunit": "^10.0.11",

0 commit comments

Comments
 (0)