Last active
January 14, 2022 09:34
-
-
Save bwaidelich/3dfde3bec107546467dad231ab32c86b to your computer and use it in GitHub Desktop.
Example of a "constant" value object that can be compared
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
final class SomeIdentifier | |
{ | |
/** | |
* @var string | |
*/ | |
private $value; | |
/** | |
* @var self[] | |
*/ | |
private static $instances = []; | |
private function __construct(string $value) | |
{ | |
$this->value = $value; | |
} | |
private static function constant(string $value): self | |
{ | |
return self::$instances[$value] ?? self::$instances[$value] = new self($value); | |
} | |
public static function fromString(string $value): self | |
{ | |
return self::constant($value); | |
} | |
public function toString(): string | |
{ | |
return $this->value; | |
} | |
public function __toString(): string | |
{ | |
return $this->toString(); | |
} | |
/** | |
* Cloning of constant value objects is not supported | |
*/ | |
public function __clone() | |
{ | |
throw new \RuntimeException('Cloning not supported'); | |
} | |
/** | |
* Serialization of constant value objects is not supported | |
*/ | |
public function __sleep() | |
{ | |
throw new \RuntimeException('Serialization not supported'); | |
} | |
/** | |
* Deserialization of constant value objects is not supported | |
*/ | |
public function __wakeup() | |
{ | |
throw new \RuntimeException('Deserialization not supported'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
final class SomeIdentifiers implements \IteratorAggregate, \Serializable | |
{ | |
/** | |
* @var SomeIdentifier[] | |
*/ | |
private $identifiers; | |
private function __construct(array $identifiers) | |
{ | |
$this->identifiers = $identifiers; | |
} | |
/** | |
* @param SomeIdentifier[] $identifiers | |
* @return self | |
*/ | |
public static function fromArray(array $identifiers): self | |
{ | |
array_walk($identifiers, static function($identifier) { | |
if (!$identifier instanceof SomeIdentifier) { | |
throw new \InvalidArgumentException('blah blah'); | |
} | |
}); | |
return new static(array_values($identifiers)); | |
} | |
/** | |
* @return \Traversable|SomeIdentifier[] | |
*/ | |
public function getIterator(): \Traversable | |
{ | |
return new \ArrayIterator(array_values($this->identifiers)); | |
} | |
/** | |
* @inheritDoc | |
*/ | |
public function serialize(): string | |
{ | |
return implode(',', $this->identifiers); | |
} | |
/** | |
* @inheritDoc | |
*/ | |
public function unserialize($serialized): void | |
{ | |
$this->identifiers = array_map(static function($identifier) { | |
return AccountIdentifier::fromString($identifier); | |
}, explode(',', $serialized)); | |
} | |
} |
Author
bwaidelich
commented
Apr 3, 2020
I think you definitely want to prevent __clone as it will always create a new instance, the __clone method won't help as it cannot prevent the creation of a second instance. Additionally (un)serialize needs to be handled I guess, either also preventing it (might be problematic for session stuff and caches and such) or by handling the instances/deducplication there.
With the latest version (revision 4) it's no longer allowed to clone / serialize the value objects, but the container (SomeIdentifiers
in this case) can still be serialized:
$id1 = SomeIdentifier::fromString('some-id');
$ids = SomeIdentifiers::fromArray([$id1]);
iterator_to_array($ids)[0] === iterator_to_array(unserialize(serialize($ids)))[0]); // true
👍
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment