From d3df4c399d3a56f0235afb1ef560656881812565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Tue, 12 Jun 2018 00:23:07 +0100 Subject: [PATCH] Make DeepCopy API final and immutable Closes #68 --- src/DeepCopy/DeepCopy.php | 52 ++++++++++++----------- src/DeepCopy/Exception/CloneException.php | 9 ++++ src/DeepCopy/deep_copy.php | 20 ++++++--- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/DeepCopy/DeepCopy.php b/src/DeepCopy/DeepCopy.php index b9c2075..a3ea9fc 100644 --- a/src/DeepCopy/DeepCopy.php +++ b/src/DeepCopy/DeepCopy.php @@ -44,31 +44,38 @@ final class DeepCopy private $useCloneMethod; /** - * @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will be used - * instead of the regular deep cloning. + * @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will + * be used instead of the regular deep cloning. + * @param bool $skipUncloneable If enabled, will not throw an exception when coming across an uncloneable + * property. + * @param Array List of filter-matcher pairs + * @param Array List of type filter-matcher pairs */ - public function __construct(bool $useCloneMethod = false) - { + public function __construct( + bool $useCloneMethod = false, + bool $skipUncloneable = true, + array $filters = [], + array $typeFilters = [] + ) { $this->useCloneMethod = $useCloneMethod; - $this->addTypeFilter( + $filters[] = [ new DateIntervalFilter(), new TypeMatcher(DateInterval::class) - ); - $this->addTypeFilter( + ]; + + foreach ($filters as [$filter, $matcher]) { + $this->addFilter($filter, $matcher); + } + + $typeFilters[] = [ new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class) - ); - } + ]; - /** - * If enabled, will not throw an exception when coming across an uncloneable property. - */ - public function skipUncloneable(bool $skipUncloneable = true): self - { - $this->skipUncloneable = $skipUncloneable; - - return $this; + foreach ($typeFilters as [$filter, $matcher]) { + $this->addTypeFilter($filter, $matcher); + } } /** @@ -85,12 +92,12 @@ public function copy($value) return $this->recursiveCopy($value); } - public function addFilter(Filter $filter, Matcher $matcher): void + private function addFilter(Filter $filter, Matcher $matcher): void { $this->filters[] = [$matcher, $filter]; } - public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher): void + private function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher): void { $this->typeFilters[] = [$matcher, $filter]; } @@ -146,12 +153,7 @@ private function copyObject(object $object): object return $object; } - throw new CloneException( - sprintf( - 'The class "%s" is not cloneable.', - $reflectedObject->getName() - ) - ); + throw CloneException::unclonableClass($reflectedObject->getName()); } $newObject = clone $object; diff --git a/src/DeepCopy/Exception/CloneException.php b/src/DeepCopy/Exception/CloneException.php index d7a2a27..7d2c80c 100644 --- a/src/DeepCopy/Exception/CloneException.php +++ b/src/DeepCopy/Exception/CloneException.php @@ -6,4 +6,13 @@ class CloneException extends UnexpectedValueException { + final public static function unclonableClass(string $class): self + { + return new self( + sprintf( + 'The class "%s" is not cloneable.', + $class + ) + ); + } } diff --git a/src/DeepCopy/deep_copy.php b/src/DeepCopy/deep_copy.php index 030a54f..0f58d44 100644 --- a/src/DeepCopy/deep_copy.php +++ b/src/DeepCopy/deep_copy.php @@ -6,11 +6,19 @@ * Deep copies the given value. * * @param mixed $value - * @param bool $useCloneMethod - * - * @return mixed + * @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will + * be used instead of the regular deep cloning. + * @param bool $skipUncloneable If enabled, will not throw an exception when coming across an uncloneable + * property. + * @param Array List of filter-matcher pairs + * @param Array List of type filter-matcher pairs */ -function deep_copy($value, $useCloneMethod = false) -{ - return (new DeepCopy($useCloneMethod))->copy($value); +public function deep_copy( + $value, + bool $useCloneMethod = false, + bool $skipUncloneable = true, + array $filters = [], + array $typeFilters = [] +) { + return (new DeepCopy($useCloneMethod, $skipUncloneable, $filters, $typeFilters))->copy($value); }