Skip to content

Commit 66a912a

Browse files
authored
Tweaks & cosmetic changes (#83)
1 parent 1a89424 commit 66a912a

18 files changed

+136
-83
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"php": ">=5.4.0"
2424
},
2525
"require-dev": {
26-
"doctrine/collections": "1.*",
26+
"doctrine/collections": "^1.0",
2727
"phpunit/phpunit": "~4.1"
2828
},
2929

src/DeepCopy/DeepCopy.php

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,44 @@
22

33
namespace DeepCopy;
44

5+
use DateTimeInterface;
56
use DeepCopy\Exception\CloneException;
67
use DeepCopy\Filter\Filter;
78
use DeepCopy\Matcher\Matcher;
89
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedList;
910
use DeepCopy\TypeFilter\TypeFilter;
1011
use DeepCopy\TypeMatcher\TypeMatcher;
12+
use ReflectionObject;
1113
use ReflectionProperty;
1214
use DeepCopy\Reflection\ReflectionHelper;
1315

1416
/**
15-
* DeepCopy
16-
*
1717
* @final
1818
*/
1919
class DeepCopy
2020
{
2121
/**
22-
* @var array
22+
* @var object[] List of objects copied.
2323
*/
2424
private $hashMap = [];
2525

2626
/**
2727
* Filters to apply.
28-
* @var array
28+
*
29+
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
2930
*/
3031
private $filters = [];
3132

3233
/**
3334
* Type Filters to apply.
34-
* @var array
35+
*
36+
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
3537
*/
3638
private $typeFilters = [];
3739

40+
/**
41+
* @var bool
42+
*/
3843
private $skipUncloneable = false;
3944

4045
/**
@@ -50,23 +55,28 @@ public function __construct($useCloneMethod = false)
5055
{
5156
$this->useCloneMethod = $useCloneMethod;
5257

53-
$this->addTypeFilter(new SplDoublyLinkedList($this), new TypeMatcher('\SplDoublyLinkedList'));
58+
$this->addTypeFilter(new SplDoublyLinkedList($this), new TypeMatcher('SplDoublyLinkedList'));
5459
}
5560

5661
/**
57-
* Cloning uncloneable properties won't throw exception.
62+
* If enabled, will not throw an exception when coming across an uncloneable property.
63+
*
5864
* @param $skipUncloneable
65+
*
5966
* @return $this
6067
*/
6168
public function skipUncloneable($skipUncloneable = true)
6269
{
6370
$this->skipUncloneable = $skipUncloneable;
71+
6472
return $this;
6573
}
6674

6775
/**
68-
* Perform a deep copy of the object.
76+
* Deep copies the given object.
77+
*
6978
* @param mixed $object
79+
*
7080
* @return mixed
7181
*/
7282
public function copy($object)
@@ -92,7 +102,6 @@ public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher)
92102
];
93103
}
94104

95-
96105
private function recursiveCopy($var)
97106
{
98107
// Matches Type Filter
@@ -104,14 +113,17 @@ private function recursiveCopy($var)
104113
if (is_resource($var)) {
105114
return $var;
106115
}
116+
107117
// Array
108118
if (is_array($var)) {
109119
return $this->copyArray($var);
110120
}
121+
111122
// Scalar
112123
if (! is_object($var)) {
113124
return $var;
114125
}
126+
115127
// Object
116128
return $this->copyObject($var);
117129
}
@@ -131,8 +143,12 @@ private function copyArray(array $array)
131143
}
132144

133145
/**
134-
* Copy an object
146+
* Copies an object.
147+
*
135148
* @param object $object
149+
*
150+
* @throws CloneException
151+
*
136152
* @return object
137153
*/
138154
private function copyObject($object)
@@ -143,29 +159,35 @@ private function copyObject($object)
143159
return $this->hashMap[$objectHash];
144160
}
145161

146-
$reflectedObject = new \ReflectionObject($object);
147-
148-
if (false === $isCloneable = $reflectedObject->isCloneable() and $this->skipUncloneable) {
149-
$this->hashMap[$objectHash] = $object;
150-
return $object;
151-
}
162+
$reflectedObject = new ReflectionObject($object);
163+
$isCloneable = $reflectedObject->isCloneable();
152164

153165
if (false === $isCloneable) {
154-
throw new CloneException(sprintf(
155-
'Class "%s" is not cloneable.',
156-
$reflectedObject->getName()
157-
));
166+
if ($this->skipUncloneable) {
167+
$this->hashMap[$objectHash] = $object;
168+
169+
return $object;
170+
}
171+
172+
throw new CloneException(
173+
sprintf(
174+
'Class "%s" is not cloneable.',
175+
$reflectedObject->getName()
176+
)
177+
);
158178
}
159179

160180
$newObject = clone $object;
161181
$this->hashMap[$objectHash] = $newObject;
182+
162183
if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) {
163184
return $object;
164185
}
165186

166-
if ($newObject instanceof \DateTimeInterface) {
187+
if ($newObject instanceof DateTimeInterface) {
167188
return $newObject;
168189
}
190+
169191
foreach (ReflectionHelper::getProperties($reflectedObject) as $property) {
170192
$this->copyObjectProperty($newObject, $property);
171193
}
@@ -195,11 +217,13 @@ function ($object) {
195217
return $this->recursiveCopy($object);
196218
}
197219
);
220+
198221
// If a filter matches, we stop processing this property
199222
return;
200223
}
201224
}
202225

226+
// No filter has been applied: simply copy the value
203227
$property->setAccessible(true);
204228
$propertyValue = $property->getValue($object);
205229

@@ -208,10 +232,12 @@ function ($object) {
208232
}
209233

210234
/**
211-
* Returns first filter that matches variable, NULL if no such filter found.
235+
* Returns first filter that matches variable, `null` if no such filter found.
236+
*
212237
* @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and
213238
* 'matcher' with value of type {@see TypeMatcher}
214239
* @param mixed $var
240+
*
215241
* @return TypeFilter|null
216242
*/
217243
private function getFirstMatchedTypeFilter(array $filterRecords, $var)
@@ -230,10 +256,13 @@ function (array $record) use ($var) {
230256
}
231257

232258
/**
233-
* Returns first element that matches predicate, NULL if no such element found.
234-
* @param array $elements
259+
* Returns first element that matches predicate, `null` if no such element found.
260+
*
261+
* @param array $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
235262
* @param callable $predicate Predicate arguments are: element.
236-
* @return mixed|null
263+
*
264+
* @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher'
265+
* with value of type {@see TypeMatcher} or `null`.
237266
*/
238267
private function first(array $elements, callable $predicate)
239268
{
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<?php
2+
23
namespace DeepCopy\Exception;
34

4-
class CloneException extends \UnexpectedValueException
5+
use UnexpectedValueException;
6+
7+
class CloneException extends UnexpectedValueException
58
{
69
}

src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use ReflectionProperty;
77

88
/**
9-
* Set a null value for a property
9+
* Sets a null value for a property.
1010
*
1111
* @final
1212
*/

src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,23 @@
44

55
use DeepCopy\Filter\Filter;
66
use Doctrine\Common\Collections\ArrayCollection;
7+
use ReflectionProperty;
78

89
/**
910
* @final
1011
*/
1112
class DoctrineEmptyCollectionFilter implements Filter
1213
{
1314
/**
14-
* Apply the filter to the object.
15+
* Applies the filter to the object.
1516
*
1617
* @param object $object
1718
* @param string $property
1819
* @param callable $objectCopier
1920
*/
2021
public function apply($object, $property, $objectCopier)
2122
{
22-
$reflectionProperty = new \ReflectionProperty($object, $property);
23+
$reflectionProperty = new ReflectionProperty($object, $property);
2324
$reflectionProperty->setAccessible(true);
2425

2526
$reflectionProperty->setValue($object, new ArrayCollection());

src/DeepCopy/Filter/Filter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
interface Filter
99
{
1010
/**
11-
* Apply the filter to the object.
11+
* Applies the filter to the object.
12+
*
1213
* @param object $object
1314
* @param string $property
1415
* @param callable $objectCopier

src/DeepCopy/Filter/ReplaceFilter.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
namespace DeepCopy\Filter;
44

5+
use ReflectionProperty;
6+
57
/**
6-
* Replace the value of a property
8+
* Replaces the value of a property
79
*
810
* @final
911
*/
@@ -27,7 +29,7 @@ public function __construct(callable $callable)
2729
*/
2830
public function apply($object, $property, $objectCopier)
2931
{
30-
$reflectionProperty = new \ReflectionProperty($object, $property);
32+
$reflectionProperty = new ReflectionProperty($object, $property);
3133
$reflectionProperty->setAccessible(true);
3234

3335
$value = call_user_func($this->callback, $reflectionProperty->getValue($object));

src/DeepCopy/Filter/SetNullFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use ReflectionProperty;
66

77
/**
8-
* Set a null value for a property
8+
* Sets a null value for a property.
99
*
1010
* @final
1111
*/

src/DeepCopy/Matcher/Matcher.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
namespace DeepCopy\Matcher;
44

5-
/**
6-
* Matcher interface
7-
*/
85
interface Matcher
96
{
107
/**
118
* @param object $object
129
* @param string $property
10+
*
1311
* @return boolean
1412
*/
1513
public function matches($object, $property);

src/DeepCopy/Matcher/PropertyMatcher.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace DeepCopy\Matcher;
44

55
/**
6-
* Match a specific property of a specific class
6+
* Match a specific property of a specific class.
77
*
88
* @final
99
*/
@@ -34,6 +34,6 @@ public function __construct($class, $property)
3434
*/
3535
public function matches($object, $property)
3636
{
37-
return ($object instanceof $this->class) && ($property == $this->property);
37+
return ($object instanceof $this->class) && $property == $this->property;
3838
}
3939
}

src/DeepCopy/Matcher/PropertyNameMatcher.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace DeepCopy\Matcher;
44

55
/**
6-
* Match a property by its name
6+
* Matches a property by its name.
77
*
88
* @final
99
*/

src/DeepCopy/Matcher/PropertyTypeMatcher.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
namespace DeepCopy\Matcher;
44

5+
use ReflectionException;
56
use ReflectionProperty;
67

78
/**
8-
* Match a property by its type
9+
* Matches a property by its type.
910
*
1011
* It is recommended to use {@see DeepCopy\TypeFilter\TypeFilter} instead, as it applies on all occurrences
1112
* of given type in copied context (eg. array elements), not just on object properties.
@@ -32,7 +33,12 @@ public function __construct($propertyType)
3233
*/
3334
public function matches($object, $property)
3435
{
35-
$reflectionProperty = new ReflectionProperty($object, $property);
36+
try {
37+
$reflectionProperty = new ReflectionProperty($object, $property);
38+
} catch (ReflectionException $exception) {
39+
return false;
40+
}
41+
3642
$reflectionProperty->setAccessible(true);
3743

3844
return $reflectionProperty->getValue($object) instanceof $this->propertyType;

0 commit comments

Comments
 (0)