Yannick Guern 3c45fcac29 set permission on code | 7 سال پیش | |
---|---|---|
.. | ||
doc | 7 سال پیش | |
src | 7 سال پیش | |
.gitattributes | 7 سال پیش | |
.gitignore | 7 سال پیش | |
.travis.yml | 7 سال پیش | |
LICENSE | 7 سال پیش | |
README.md | 7 سال پیش | |
composer.json | 7 سال پیش |
DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph.
Install with Composer:
composer require myclabs/deep-copy
Use simply:
use DeepCopy\DeepCopy;
$deepCopy = new DeepCopy();
$myCopy = $deepCopy->copy($myObject);
$myCopy = clone $myObject;
You use __clone()
and implement the behavior yourself.
Now you're in for a big mess :(
clone
__clone()
DeepCopy
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.
You can add filters to customize the copy process.
The method to add a filter is $deepCopy->addFilter($filter, $matcher)
,
with $filter
implementing DeepCopy\Filter\Filter
and $matcher
implementing DeepCopy\Matcher\Matcher
.
We provide some generic filters and matchers.
DeepCopy\Matcher
applies on a object attribute.DeepCopy\TypeMatcher
applies on any element found in graph, including array elements.The PropertyNameMatcher
will match a property by its name:
use DeepCopy\Matcher\PropertyNameMatcher;
$matcher = new PropertyNameMatcher('id');
// will apply a filter to any property of any objects named "id"
The PropertyMatcher
will match a specific property of a specific class:
use DeepCopy\Matcher\PropertyMatcher;
$matcher = new PropertyMatcher('MyClass', 'id');
// will apply a filter to the property "id" of any objects of the class "MyClass"
The TypeMatcher
will match any element by its type (instance of a class or any value that could be parameter of gettype() function):
use DeepCopy\TypeMatcher\TypeMatcher;
$matcher = new TypeMatcher('Doctrine\Common\Collections\Collection');
// will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection
DeepCopy\Filter
applies a transformation to the object attribute matched by DeepCopy\Matcher
.DeepCopy\TypeFilter
applies a transformation to any element matched by DeepCopy\TypeMatcher
.SetNullFilter
Let's say for example that you are copying a database record (or a Doctrine entity), so you want the copy not to have any ID:
use DeepCopy\DeepCopy;
use DeepCopy\Filter\SetNullFilter;
use DeepCopy\Matcher\PropertyNameMatcher;
$myObject = MyClass::load(123);
echo $myObject->id; // 123
$deepCopy = new DeepCopy();
$deepCopy->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));
$myCopy = $deepCopy->copy($myObject);
echo $myCopy->id; // null
KeepFilter
If you want a property to remain untouched (for example, an association to an object):
use DeepCopy\DeepCopy;
use DeepCopy\Filter\KeepFilter;
use DeepCopy\Matcher\PropertyMatcher;
$deepCopy = new DeepCopy();
$deepCopy->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category'));
$myCopy = $deepCopy->copy($myObject);
// $myCopy->category has not been touched
ReplaceFilter
use DeepCopy\DeepCopy;
use DeepCopy\Filter\ReplaceFilter;
use DeepCopy\Matcher\PropertyMatcher;
$deepCopy = new DeepCopy();
$callback = function ($currentValue) {
return $currentValue . ' (copy)'
};
$deepCopy->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title'));
$myCopy = $deepCopy->copy($myObject);
// $myCopy->title will contain the data returned by the callback, e.g. 'The title (copy)'
use DeepCopy\DeepCopy;
use DeepCopy\TypeFilter\ReplaceFilter;
use DeepCopy\TypeMatcher\TypeMatcher;
$deepCopy = new DeepCopy();
$callback = function (MyClass $myClass) {
return get_class($myClass);
};
$deepCopy->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass'));
$myCopy = $deepCopy->copy(array(new MyClass, 'some string', new MyClass));
// $myCopy will contain ['MyClass', 'some string', 'MyClass']
The $callback
parameter of the ReplaceFilter
constructor accepts any PHP callable.
ShallowCopyFilter
Stop DeepCopy from recursively copying element, using standard clone
instead:
use DeepCopy\DeepCopy;
use DeepCopy\TypeFilter\ShallowCopyFilter;
use DeepCopy\TypeMatcher\TypeMatcher;
use Mockery as m;
$this->deepCopy = new DeepCopy();
$this->deepCopy->addTypeFilter(
new ShallowCopyFilter,
new TypeMatcher(m\MockInterface::class)
);
$myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDependency2::class));
// all mocks will be just cloned, not deep-copied
DoctrineCollectionFilter
If you use Doctrine and want to copy an entity, you will need to use the DoctrineCollectionFilter
:
use DeepCopy\DeepCopy;
use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter;
use DeepCopy\Matcher\PropertyTypeMatcher;
$deepCopy = new DeepCopy();
$deepCopy->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection'));
$myCopy = $deepCopy->copy($myObject);
DoctrineEmptyCollectionFilter
If you use Doctrine and want to copy an entity who contains a Collection
that you want to be reset, you can use the DoctrineEmptyCollectionFilter
use DeepCopy\DeepCopy;
use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter;
use DeepCopy\Matcher\PropertyMatcher;
$deepCopy = new DeepCopy();
$deepCopy->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty'));
$myCopy = $deepCopy->copy($myObject);
// $myCopy->myProperty will return an empty collection
DoctrineProxyFilter
If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a
Doctrine proxy class (...\__CG__\Proxy).
You can use the DoctrineProxyFilter
to load the actual entity behind the Doctrine proxy class.
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!
use DeepCopy\DeepCopy;
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
$deepCopy = new DeepCopy();
$deepCopy->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher());
$myCopy = $deepCopy->copy($myObject);
// $myCopy should now contain a clone of all entities, including those that were not yet fully loaded.
DeepCopy is distributed under the MIT license.
Running the tests is simple:
phpunit