1: <?php declare(strict_types=1);
2:
3: namespace Salient\Core\Concern;
4:
5: use Salient\Contract\Core\Immutable;
6: use ReflectionProperty;
7:
8: /**
9: * @api
10: *
11: * @phpstan-require-implements Immutable
12: */
13: trait HasMutator
14: {
15: /**
16: * Get a copy of the object with a value assigned to a property if its
17: * current value differs, otherwise return the object
18: *
19: * @param mixed $value
20: * @return static
21: */
22: private function with(string $property, $value)
23: {
24: if ((
25: isset($this->$property)
26: || ($value === null && $this->propertyIsInitialized($property))
27: ) && $value === $this->$property) {
28: return $this;
29: }
30:
31: $clone = clone $this;
32: $clone->$property = $value;
33: return $clone;
34: }
35:
36: /**
37: * Get a copy of the object where a property is unset if it is currently
38: * set, otherwise return the object
39: *
40: * @return static
41: */
42: private function without(string $property)
43: {
44: if (
45: !isset($this->$property)
46: && !$this->propertyIsInitialized($property)
47: ) {
48: return $this;
49: }
50:
51: $clone = clone $this;
52: unset($clone->$property);
53: return $clone;
54: }
55:
56: private function propertyIsInitialized(string $property): bool
57: {
58: if (!property_exists($this, $property)) {
59: return false;
60: }
61:
62: $property = new ReflectionProperty($this, $property);
63: $property->setAccessible(true);
64:
65: return $property->isInitialized($this);
66: }
67: }
68: