DeepCopy

repository·1.x·Indexed 27 days ago

https://github.com/myclabs/deepcopy

A PHP library for creating deep copies of objects while safely handling circular references in the object graph. It provides the DeepCopy::copy() method for recursive cloning and supports custom filters, type filters, and matchers to control the cloning process. Features include the ability to use native __clone() methods, skipping uncloneable properties, and specialized filters like SetNullFilter, KeepFilter, and ReplaceFilter.

Tokens
2.4K
Snippets
12
Records
18
Agent score
44%

What's inside myclabs/deepcopy

  1. Use ChainableFilter to apply multiple filters

    1.x

    By default, a matching filter stops the chain. Use DeepCopy\Filter\ChainableFilter to decorate a filter so that subsequent filters in the chain are still applied. This is recommended when using DoctrineProxyFilter.

    use DeepCopy\DeepCopy;
    use DeepCopy\Filter\ChainableFilter;
    use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
    use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
    
    $copier = new DeepCopy();
    // Decorate DoctrineProxyFilter so other filters can still run
    $copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher());
  2. Basic usage of DeepCopy

    1.x

    You can use the DeepCopy class directly or use the deep_copy helper function for a quick way to clone an object.

    use DeepCopy\DeepCopy;
    
    $copier = new DeepCopy();
    $myCopy = $copier->copy($myObject);

    Alternatively, use the helper function:

    use function DeepCopy\deep_copy;
    
    $copy = deep_copy($var);
  3. Install DeepCopy via Composer

    1.x

    Install the myclabs/deep-copy package using Composer to enable deep cloning of objects with cycle detection.

    composer require myclabs/deep-copy
  4. Use ReplaceFilter to transform property values

    1.x

    DeepCopy\Filter\ReplaceFilter allows you to replace a property value using a PHP callable.

    use DeepCopy\DeepCopy;
    use DeepCopy\Filter\ReplaceFilter;
    use DeepCopy\Matcher\PropertyMatcher;
    
    $copier = new DeepCopy();
    $callback = function ($currentValue) {
        return $currentValue . ' (copy)';
    };
    $copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title'));
    
    $copy = $copier->copy($object);
    // $copy->title will be transformed by the callback
  5. Use SetNullFilter to nullify properties

    1.x

    Use DeepCopy\Filter\SetNullFilter to ensure specific properties (like database IDs) are set to null in the cloned object.

    use DeepCopy\DeepCopy;
    use DeepCopy\Filter\SetNullFilter;
    use DeepCopy\Matcher\PropertyNameMatcher;
    
    $copier = new DeepCopy();
    $copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));
    
    $copy = $copier->copy($object);
    // $copy->id will be null
  6. Use ReplaceFilter to replace whole elements by type

    1.x

    DeepCopy\Filter\TypeFilter\ReplaceFilter can replace entire elements in the graph based on their type.

    use DeepCopy\DeepCopy;
    use DeepCopy\Filter\TypeFilter\ReplaceFilter;
    use DeepCopy\TypeMatcher\TypeMatcher;
    
    $copier = new DeepCopy();
    $callback = function (MyClass $myClass) {
        return get_class($myClass);
    };
    $copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass'));
    
    $copy = $copier->copy([new MyClass, 'some string', new MyClass]);
    // $copy will contain ['MyClass', 'some string', 'MyClass']
  7. Use KeepFilter to prevent property cloning

    1.x

    Use DeepCopy\Filter\KeepFilter to keep a property untouched during the cloning process (e.g., to maintain an existing association).

    use DeepCopy\DeepCopy;
    use DeepCopy\Filter\KeepFilter;
    use DeepCopy\Matcher\PropertyMatcher;
    
    $copier = new DeepCopy();
    $copier->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category'));
    
    $copy = $copier->copy($object);
    // $copy->category remains the same instance as $object->category
  8. Use ShallowCopyFilter to skip recursive cloning

    1.x

    Use DeepCopy\TypeFilter\ShallowCopyFilter to stop DeepCopy from recursively copying specific types, using standard PHP clone instead. This is useful for objects like Mocks.

    use DeepCopy\DeepCopy;
    use DeepCopy\TypeFilter\ShallowCopyFilter;
    use DeepCopy\TypeMatcher\TypeMatcher;
    
    $copier = new DeepCopy();
    $copier->addTypeFilter(
        new ShallowCopyFilter,
        new TypeMatcher(MockInterface::class)
    );
    
    $copy = $copier->copy($myServiceWithMocks);
    // Mocks will be shallow cloned, not deep copied
  9. Add filters to DeepCopy using Matchers

    1.x

    Customize the cloning process by adding filters. Use DeepCopy\DeepCopy::addFilter($filter, $matcher) where $filter implements DeepCopy\Filter\Filter and $matcher implements DeepCopy\Matcher\Matcher.

    use DeepCopy\DeepCopy;
    use DeepCopy\Filter\SetNullFilter;
    use DeepCopy\Matcher\PropertyNameMatcher;
    
    $copier = new DeepCopy();
    // Apply a filter to any property named 'id'
    $copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));
    
    $copy = $copier->copy($object);
  10. Configure DeepCopy with custom instances

    1.x

    To configure specific behaviors (like using a specific constructor argument), instantiate DeepCopy manually.

    use DeepCopy\DeepCopy;
    
    // Passing true to the constructor
    $copier = new DeepCopy(true);
    
    $copy = $copier->copy($var);
  11. Handle uncloneable properties with skipUncloneable()

    1.x
    If DeepCopy encounters a property that is not cloneable, it will throw a DeepCopy\Exception\CloneException. To prevent this and instead keep the original reference for uncloneable properties, call skipUncloneable(true) on the DeepCopy instance.
  12. Configure DeepCopy to use the __clone() method

    1.x
    By default, DeepCopy performs a deep clone by inspecting object properties via reflection. If you pass true to the DeepCopy constructor, the library will use the object's native __clone() method instead of performing its own deep cloning when it encounters an object that implements it.