You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- How do you create **deep** copies of your objects (i.e. copying also all the objects referenced in the properties)?
61
63
62
-
You use [`__clone()`](http://www.php.net/manual/en/language.oop5.cloning.php#object.clone) and implement the behavior yourself.
64
+
You use [`__clone()`](http://www.php.net/manual/en/language.oop5.cloning.php#object.clone) and implement the behavior
65
+
yourself.
63
66
64
67
- But how do you handle **cycles** in the association graph?
65
68
@@ -85,14 +88,49 @@ Now you're in for a big mess :(
85
88
86
89
## How it works
87
90
88
-
DeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it keeps a hash map of all instances and thus preserves the object graph.
91
+
DeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it
92
+
keeps a hash map of all instances and thus preserves the object graph.
93
+
94
+
To use it:
95
+
96
+
```php
97
+
use function DeepCopy\deep_copy;
98
+
99
+
$copy = deep_copy($var);
100
+
```
101
+
102
+
Alternatively, you can create your own `DeepCopy` instance to configure it differently for example:
103
+
104
+
```php
105
+
use DeepCopy\DeepCopy;
106
+
107
+
$copier = new DeepCopy(true);
108
+
109
+
$copy = $copier->copy($var);
110
+
```
111
+
112
+
It is however recommended to use a difference instance of `DeepCopy` between each object copy as it relies on
113
+
`spl_object_hash` internally. As such you may want to roll your own deep copy function:
114
+
115
+
```php
116
+
namespace Acme;
117
+
118
+
use DeepCopy\DeepCopy;
119
+
120
+
function deep_copy($var)
121
+
{
122
+
$copier = new DeepCopy(true);
123
+
124
+
return $copier->copy($var);
125
+
}
126
+
```
89
127
90
128
91
129
## Going further
92
130
93
131
You can add filters to customize the copy process.
94
132
95
-
The method to add a filter is `$deepCopy->addFilter($filter, $matcher)`,
133
+
The method to add a filter is `DeepCopy\DeepCopy::addFilter($filter, $matcher)`,
96
134
with `$filter` implementing `DeepCopy\Filter\Filter`
97
135
and `$matcher` implementing `DeepCopy\Matcher\Matcher`.
98
136
@@ -112,8 +150,8 @@ The `PropertyNameMatcher` will match a property by its name:
112
150
```php
113
151
use DeepCopy\Matcher\PropertyNameMatcher;
114
152
153
+
// Will apply a filter to any property of any objects named "id"
115
154
$matcher = new PropertyNameMatcher('id');
116
-
// will apply a filter to any property of any objects named "id"
117
155
```
118
156
119
157
@@ -124,46 +162,49 @@ The `PropertyMatcher` will match a specific property of a specific class:
124
162
```php
125
163
use DeepCopy\Matcher\PropertyMatcher;
126
164
165
+
// Will apply a filter to the property "id" of any objects of the class "MyClass"
127
166
$matcher = new PropertyMatcher('MyClass', 'id');
128
-
// will apply a filter to the property "id" of any objects of the class "MyClass"
129
167
```
130
168
131
169
132
170
#### Type
133
171
134
-
The `TypeMatcher` will match any element by its type (instance of a class or any value that could be parameter of [gettype()](http://php.net/manual/en/function.gettype.php) function):
172
+
The `TypeMatcher` will match any element by its type (instance of a class or any value that could be parameter of
If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a
222
266
Doctrine proxy class (...\\\_\_CG\_\_\Proxy).
223
267
You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class.
224
-
**Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded before other filters are applied!**
268
+
**Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded
269
+
before other filters are applied!**
225
270
226
271
```php
227
272
use DeepCopy\DeepCopy;
228
273
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
229
274
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
230
275
231
-
$deepCopy = new DeepCopy();
232
-
$deepCopy->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher());
233
-
$myCopy = $deepCopy->copy($myObject);
276
+
$copier = new DeepCopy();
277
+
$copier->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher());
278
+
279
+
$copy = $copier->copy($object);
234
280
235
-
// $myCopy should now contain a clone of all entities, including those that were not yet fully loaded.
281
+
// $copy should now contain a clone of all entities, including those that were not yet fully loaded.
236
282
```
237
283
238
284
239
285
#### `ReplaceFilter` (type filter)
240
286
241
-
1. If you want to replace the value of a property:
287
+
1. If you want to replace the value of a property:
288
+
289
+
```php
290
+
use DeepCopy\DeepCopy;
291
+
use DeepCopy\Filter\ReplaceFilter;
292
+
use DeepCopy\Matcher\PropertyMatcher;
293
+
294
+
$copier = new DeepCopy();
295
+
$callback = function ($currentValue) {
296
+
return $currentValue . ' (copy)'
297
+
};
298
+
$copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title'));
242
299
243
-
```php
244
-
use DeepCopy\DeepCopy;
245
-
use DeepCopy\Filter\ReplaceFilter;
246
-
use DeepCopy\Matcher\PropertyMatcher;
300
+
$copy = $copier->copy($object);
247
301
248
-
$deepCopy = new DeepCopy();
249
-
$callback = function ($currentValue) {
250
-
return $currentValue . ' (copy)'
251
-
};
252
-
$deepCopy->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title'));
253
-
$myCopy = $deepCopy->copy($myObject);
302
+
// $copy->title will contain the data returned by the callback, e.g. 'The title (copy)'
303
+
```
254
304
255
-
// $myCopy->title will contain the data returned by the callback, e.g. 'The title (copy)'
256
-
```
305
+
2. If you want to replace whole element:
257
306
258
-
2. If you want to replace whole element:
307
+
```php
308
+
use DeepCopy\DeepCopy;
309
+
use DeepCopy\TypeFilter\ReplaceFilter;
310
+
use DeepCopy\TypeMatcher\TypeMatcher;
259
311
260
-
```php
261
-
use DeepCopy\DeepCopy;
262
-
use DeepCopy\TypeFilter\ReplaceFilter;
263
-
use DeepCopy\TypeMatcher\TypeMatcher;
312
+
$copier = new DeepCopy();
313
+
$callback = function (MyClass $myClass) {
314
+
return get_class($myClass);
315
+
};
316
+
$copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass'));
264
317
265
-
$deepCopy = new DeepCopy();
266
-
$callback = function (MyClass $myClass) {
267
-
return get_class($myClass);
268
-
};
269
-
$deepCopy->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass'));
270
-
$myCopy = $deepCopy->copy(array(new MyClass, 'some string', new MyClass));
318
+
$copy = $copier->copy([new MyClass, 'some string', new MyClass]);
271
319
272
-
// $myCopy will contain ['MyClass', 'some string', 'MyClass']
273
-
```
320
+
// $copy will contain ['MyClass', 'some string', 'MyClass']
321
+
```
274
322
275
323
276
324
The `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable.
0 commit comments