Файловый менеджер - Редактировать - /home/tuudkjt/globeasy/wp-includes/ID3/myclabs.tar
Назад
deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php 0000777 00000002537 15251766565 0017056 0 ustar 00 <?php namespace Rvx\DeepCopy\Matcher; use Rvx\DeepCopy\Reflection\ReflectionHelper; use ReflectionException; /** * Matches a property by its type. * * It is recommended to use {@see DeepCopy\TypeFilter\TypeFilter} instead, as it applies on all occurrences * of given type in copied context (eg. array elements), not just on object properties. * * @final */ class PropertyTypeMatcher implements Matcher { /** * @var string */ private $propertyType; /** * @param string $propertyType Property type */ public function __construct($propertyType) { $this->propertyType = $propertyType; } /** * {@inheritdoc} */ public function matches($object, $property) { try { $reflectionProperty = ReflectionHelper::getProperty($object, $property); } catch (ReflectionException $exception) { return \false; } if (\PHP_VERSION_ID < 80100) { $reflectionProperty->setAccessible(\true); } // Uninitialized properties (for PHP >7.4) if (\method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) { // null instanceof $this->propertyType return \false; } return $reflectionProperty->getValue($object) instanceof $this->propertyType; } } deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php 0000777 00000001262 15251766565 0016206 0 ustar 00 <?php namespace Rvx\DeepCopy\Matcher; /** * @final */ class PropertyMatcher implements Matcher { /** * @var string */ private $class; /** * @var string */ private $property; /** * @param string $class Class name * @param string $property Property name */ public function __construct($class, $property) { $this->class = $class; $this->property = $property; } /** * Matches a specific property of a specific class. * * {@inheritdoc} */ public function matches($object, $property) { return $object instanceof $this->class && $property == $this->property; } } deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php 0000777 00000000772 15251766565 0017014 0 ustar 00 <?php namespace Rvx\DeepCopy\Matcher; /** * @final */ class PropertyNameMatcher implements Matcher { /** * @var string */ private $property; /** * @param string $property Property name */ public function __construct($property) { $this->property = $property; } /** * Matches a property by its name. * * {@inheritdoc} */ public function matches($object, $property) { return $property == $this->property; } } deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php 0000777 00000000563 15251766565 0020745 0 ustar 00 <?php namespace Rvx\DeepCopy\Matcher\Doctrine; use Rvx\DeepCopy\Matcher\Matcher; use Rvx\Doctrine\Persistence\Proxy; /** * @final */ class DoctrineProxyMatcher implements Matcher { /** * Matches a Doctrine Proxy class. * * {@inheritdoc} */ public function matches($object, $property) { return $object instanceof Proxy; } } deep-copy/src/DeepCopy/Matcher/Matcher.php 0000777 00000000331 15251766565 0014435 0 ustar 00 <?php namespace Rvx\DeepCopy\Matcher; interface Matcher { /** * @param object $object * @param string $property * * @return boolean */ public function matches($object, $property); } deep-copy/src/DeepCopy/Filter/ChainableFilter.php 0000777 00000000703 15251766565 0015733 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter; /** * Defines a decorator filter that will not stop the chain of filters. */ class ChainableFilter implements Filter { /** * @var Filter */ protected $filter; public function __construct(Filter $filter) { $this->filter = $filter; } public function apply($object, $property, $objectCopier) { $this->filter->apply($object, $property, $objectCopier); } } deep-copy/src/DeepCopy/Filter/ReplaceFilter.php 0000777 00000001712 15251766565 0015441 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter; use Rvx\DeepCopy\Reflection\ReflectionHelper; /** * @final */ class ReplaceFilter implements Filter { /** * @var callable */ protected $callback; /** * @param callable $callable Will be called to get the new value for each property to replace */ public function __construct(callable $callable) { $this->callback = $callable; } /** * Replaces the object property by the result of the callback called with the object property. * * {@inheritdoc} */ public function apply($object, $property, $objectCopier) { $reflectionProperty = ReflectionHelper::getProperty($object, $property); if (\PHP_VERSION_ID < 80100) { $reflectionProperty->setAccessible(\true); } $value = \call_user_func($this->callback, $reflectionProperty->getValue($object)); $reflectionProperty->setValue($object, $value); } } deep-copy/src/DeepCopy/Filter/KeepFilter.php 0000777 00000000413 15251766565 0014747 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter; class KeepFilter implements Filter { /** * Keeps the value of the object property. * * {@inheritdoc} */ public function apply($object, $property, $objectCopier) { // Nothing to do } } deep-copy/src/DeepCopy/Filter/Filter.php 0000777 00000000540 15251766565 0014143 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter; /** * Filter to apply to a property while copying an object */ interface Filter { /** * Applies the filter to the object. * * @param object $object * @param string $property * @param callable $objectCopier */ public function apply($object, $property, $objectCopier); } deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php 0000777 00000000632 15251766565 0020446 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter\Doctrine; use Rvx\DeepCopy\Filter\Filter; /** * @final */ class DoctrineProxyFilter implements Filter { /** * Triggers the magic method __load() on a Doctrine Proxy class to load the * actual entity from the database. * * {@inheritdoc} */ public function apply($object, $property, $objectCopier) { $object->__load(); } } deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php 0000777 00000001405 15251766565 0022436 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter\Doctrine; use Rvx\DeepCopy\Filter\Filter; use Rvx\DeepCopy\Reflection\ReflectionHelper; use Rvx\Doctrine\Common\Collections\ArrayCollection; /** * @final */ class DoctrineEmptyCollectionFilter implements Filter { /** * Sets the object property to an empty doctrine collection. * * @param object $object * @param string $property * @param callable $objectCopier */ public function apply($object, $property, $objectCopier) { $reflectionProperty = ReflectionHelper::getProperty($object, $property); if (\PHP_VERSION_ID < 80100) { $reflectionProperty->setAccessible(\true); } $reflectionProperty->setValue($object, new ArrayCollection()); } } deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php 0000777 00000001463 15251766565 0021423 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter\Doctrine; use Rvx\DeepCopy\Filter\Filter; use Rvx\DeepCopy\Reflection\ReflectionHelper; /** * @final */ class DoctrineCollectionFilter implements Filter { /** * Copies the object property doctrine collection. * * {@inheritdoc} */ public function apply($object, $property, $objectCopier) { $reflectionProperty = ReflectionHelper::getProperty($object, $property); if (\PHP_VERSION_ID < 80100) { $reflectionProperty->setAccessible(\true); } $oldCollection = $reflectionProperty->getValue($object); $newCollection = $oldCollection->map(function ($item) use($objectCopier) { return $objectCopier($item); }); $reflectionProperty->setValue($object, $newCollection); } } deep-copy/src/DeepCopy/Filter/SetNullFilter.php 0000777 00000001036 15251766565 0015453 0 ustar 00 <?php namespace Rvx\DeepCopy\Filter; use Rvx\DeepCopy\Reflection\ReflectionHelper; /** * @final */ class SetNullFilter implements Filter { /** * Sets the object property to null. * * {@inheritdoc} */ public function apply($object, $property, $objectCopier) { $reflectionProperty = ReflectionHelper::getProperty($object, $property); if (\PHP_VERSION_ID < 80100) { $reflectionProperty->setAccessible(\true); } $reflectionProperty->setValue($object, null); } } deep-copy/src/DeepCopy/DeepCopy.php 0000777 00000020353 15251766565 0013205 0 ustar 00 <?php namespace Rvx\DeepCopy; use ArrayObject; use DateInterval; use DatePeriod; use DateTimeInterface; use DateTimeZone; use Rvx\DeepCopy\Exception\CloneException; use Rvx\DeepCopy\Filter\ChainableFilter; use Rvx\DeepCopy\Filter\Filter; use Rvx\DeepCopy\Matcher\Matcher; use Rvx\DeepCopy\Reflection\ReflectionHelper; use Rvx\DeepCopy\TypeFilter\Date\DateIntervalFilter; use Rvx\DeepCopy\TypeFilter\Date\DatePeriodFilter; use Rvx\DeepCopy\TypeFilter\Spl\ArrayObjectFilter; use Rvx\DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter; use Rvx\DeepCopy\TypeFilter\TypeFilter; use Rvx\DeepCopy\TypeMatcher\TypeMatcher; use ReflectionObject; use ReflectionProperty; use SplDoublyLinkedList; /** * @final */ class DeepCopy { /** * @var object[] List of objects copied. */ private $hashMap = []; /** * Filters to apply. * * @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs. */ private $filters = []; /** * Type Filters to apply. * * @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs. */ private $typeFilters = []; /** * @var bool */ private $skipUncloneable = \false; /** * @var bool */ 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. */ public function __construct($useCloneMethod = \false) { $this->useCloneMethod = $useCloneMethod; $this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class)); $this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class)); $this->addTypeFilter(new DatePeriodFilter(), new TypeMatcher(DatePeriod::class)); $this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class)); } /** * If enabled, will not throw an exception when coming across an uncloneable property. * * @param $skipUncloneable * * @return $this */ public function skipUncloneable($skipUncloneable = \true) { $this->skipUncloneable = $skipUncloneable; return $this; } /** * Deep copies the given object. * * @template TObject * * @param TObject $object * * @return TObject */ public function copy($object) { $this->hashMap = []; return $this->recursiveCopy($object); } public function addFilter(Filter $filter, Matcher $matcher) { $this->filters[] = ['matcher' => $matcher, 'filter' => $filter]; } public function prependFilter(Filter $filter, Matcher $matcher) { \array_unshift($this->filters, ['matcher' => $matcher, 'filter' => $filter]); } public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher) { $this->typeFilters[] = ['matcher' => $matcher, 'filter' => $filter]; } public function prependTypeFilter(TypeFilter $filter, TypeMatcher $matcher) { \array_unshift($this->typeFilters, ['matcher' => $matcher, 'filter' => $filter]); } private function recursiveCopy($var) { // Matches Type Filter if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) { return $filter->apply($var); } // Resource if (\is_resource($var)) { return $var; } // Array if (\is_array($var)) { return $this->copyArray($var); } // Scalar if (!\is_object($var)) { return $var; } // Enum if (\PHP_VERSION_ID >= 80100 && \enum_exists(\get_class($var))) { return $var; } // Object return $this->copyObject($var); } /** * Copy an array * @param array $array * @return array */ private function copyArray(array $array) { foreach ($array as $key => $value) { $array[$key] = $this->recursiveCopy($value); } return $array; } /** * Copies an object. * * @param object $object * * @throws CloneException * * @return object */ private function copyObject($object) { $objectHash = \spl_object_hash($object); if (isset($this->hashMap[$objectHash])) { return $this->hashMap[$objectHash]; } $reflectedObject = new ReflectionObject($object); $isCloneable = $reflectedObject->isCloneable(); if (\false === $isCloneable) { if ($this->skipUncloneable) { $this->hashMap[$objectHash] = $object; return $object; } throw new CloneException(\sprintf('The class "%s" is not cloneable.', $reflectedObject->getName())); } $newObject = clone $object; $this->hashMap[$objectHash] = $newObject; if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) { return $newObject; } if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) { return $newObject; } foreach (ReflectionHelper::getProperties($reflectedObject) as $property) { $this->copyObjectProperty($newObject, $property); } return $newObject; } private function copyObjectProperty($object, ReflectionProperty $property) { // Ignore static properties if ($property->isStatic()) { return; } // Ignore readonly properties if (\method_exists($property, 'isReadOnly') && $property->isReadOnly()) { return; } // Apply the filters foreach ($this->filters as $item) { /** @var Matcher $matcher */ $matcher = $item['matcher']; /** @var Filter $filter */ $filter = $item['filter']; if ($matcher->matches($object, $property->getName())) { $filter->apply($object, $property->getName(), function ($object) { return $this->recursiveCopy($object); }); if ($filter instanceof ChainableFilter) { continue; } // If a filter matches, we stop processing this property return; } } if (\PHP_VERSION_ID < 80100) { $property->setAccessible(\true); } // Ignore uninitialized properties (for PHP >7.4) if (\method_exists($property, 'isInitialized') && !$property->isInitialized($object)) { return; } $propertyValue = $property->getValue($object); // Copy the property $property->setValue($object, $this->recursiveCopy($propertyValue)); } /** * Returns first filter that matches variable, `null` if no such filter found. * * @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and * 'matcher' with value of type {@see TypeMatcher} * @param mixed $var * * @return TypeFilter|null */ private function getFirstMatchedTypeFilter(array $filterRecords, $var) { $matched = $this->first($filterRecords, function (array $record) use($var) { /* @var TypeMatcher $matcher */ $matcher = $record['matcher']; return $matcher->matches($var); }); return isset($matched) ? $matched['filter'] : null; } /** * Returns first element that matches predicate, `null` if no such element found. * * @param array $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs. * @param callable $predicate Predicate arguments are: element. * * @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher' * with value of type {@see TypeMatcher} or `null`. */ private function first(array $elements, callable $predicate) { foreach ($elements as $element) { if (\call_user_func($predicate, $element)) { return $element; } } return null; } } deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php 0000777 00000000731 15251766565 0016145 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeMatcher; class TypeMatcher { /** * @var string */ private $type; /** * @param string $type */ public function __construct($type) { $this->type = $type; } /** * @param mixed $element * * @return boolean */ public function matches($element) { return \is_object($element) ? \is_a($element, $this->type) : \gettype($element) === $this->type; } } deep-copy/src/DeepCopy/Exception/PropertyException.php 0000777 00000000173 15251766565 0017134 0 ustar 00 <?php namespace Rvx\DeepCopy\Exception; use ReflectionException; class PropertyException extends ReflectionException { } deep-copy/src/DeepCopy/Exception/CloneException.php 0000777 00000000202 15251766565 0016341 0 ustar 00 <?php namespace Rvx\DeepCopy\Exception; use UnexpectedValueException; class CloneException extends UnexpectedValueException { } deep-copy/src/DeepCopy/deep_copy.php 0000777 00000000627 15251766565 0013446 0 ustar 00 <?php namespace Rvx\DeepCopy; use function function_exists; if (\false === function_exists('Rvx\\DeepCopy\\deep_copy')) { /** * Deep copies the given value. * * @param mixed $value * @param bool $useCloneMethod * * @return mixed */ function deep_copy($value, $useCloneMethod = \false) { return (new DeepCopy($useCloneMethod))->copy($value); } } deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php 0000777 00000004055 15251766565 0017022 0 ustar 00 <?php namespace Rvx\DeepCopy\Reflection; use Rvx\DeepCopy\Exception\PropertyException; use ReflectionClass; use ReflectionException; use ReflectionObject; use ReflectionProperty; class ReflectionHelper { /** * Retrieves all properties (including private ones), from object and all its ancestors. * * Standard \ReflectionClass->getProperties() does not return private properties from ancestor classes. * * @author muratyaman@gmail.com * @see http://php.net/manual/en/reflectionclass.getproperties.php * * @param ReflectionClass $ref * * @return ReflectionProperty[] */ public static function getProperties(ReflectionClass $ref) { $props = $ref->getProperties(); $propsArr = array(); foreach ($props as $prop) { $propertyName = $prop->getName(); $propsArr[$propertyName] = $prop; } if ($parentClass = $ref->getParentClass()) { $parentPropsArr = self::getProperties($parentClass); foreach ($propsArr as $key => $property) { $parentPropsArr[$key] = $property; } return $parentPropsArr; } return $propsArr; } /** * Retrieves property by name from object and all its ancestors. * * @param object|string $object * @param string $name * * @throws PropertyException * @throws ReflectionException * * @return ReflectionProperty */ public static function getProperty($object, $name) { $reflection = \is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object); if ($reflection->hasProperty($name)) { return $reflection->getProperty($name); } if ($parentClass = $reflection->getParentClass()) { return self::getProperty($parentClass->getName(), $name); } throw new PropertyException(\sprintf('The class "%s" doesn\'t have a property with the given name: "%s".', \is_object($object) ? \get_class($object) : $object, $name)); } } deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php 0000777 00000001017 15251766565 0016301 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter; /** * @final */ class ReplaceFilter implements TypeFilter { /** * @var callable */ protected $callback; /** * @param callable $callable Will be called to get the new value for each element to replace */ public function __construct(callable $callable) { $this->callback = $callable; } /** * {@inheritdoc} */ public function apply($element) { return \call_user_func($this->callback, $element); } } deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php 0000777 00000000343 15251766565 0017173 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter; /** * @final */ class ShallowCopyFilter implements TypeFilter { /** * {@inheritdoc} */ public function apply($element) { return clone $element; } } deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php 0000777 00000000306 15251766565 0015647 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter; interface TypeFilter { /** * Applies the filter to the object. * * @param mixed $element */ public function apply($element); } deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php 0000777 00000001203 15251766565 0020162 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter\Date; use DateInterval; use Rvx\DeepCopy\TypeFilter\TypeFilter; /** * @final * * @deprecated Will be removed in 2.0. This filter will no longer be necessary in PHP 7.1+. */ class DateIntervalFilter implements TypeFilter { /** * {@inheritdoc} * * @param DateInterval $element * * @see http://news.php.net/php.bugs/205076 */ public function apply($element) { $copy = new DateInterval('P0D'); foreach ($element as $propertyName => $propertyValue) { $copy->{$propertyName} = $propertyValue; } return $copy; } } deep-copy/src/DeepCopy/TypeFilter/Date/DatePeriodFilter.php 0000777 00000002120 15251766565 0017617 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter\Date; use DatePeriod; use Rvx\DeepCopy\TypeFilter\TypeFilter; /** * @final */ class DatePeriodFilter implements TypeFilter { /** * {@inheritdoc} * * @param DatePeriod $element * * @see http://news.php.net/php.bugs/205076 */ public function apply($element) { $options = 0; if (\PHP_VERSION_ID >= 80200 && $element->include_end_date) { $options |= DatePeriod::INCLUDE_END_DATE; } if (!$element->include_start_date) { $options |= DatePeriod::EXCLUDE_START_DATE; } if ($element->getEndDate()) { return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $element->getEndDate(), $options); } if (\PHP_VERSION_ID >= 70217) { $recurrences = $element->getRecurrences(); } else { $recurrences = $element->recurrences - $element->include_start_date; } return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $recurrences, $options); } } deep-copy/src/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php 0000777 00000001330 15251766565 0017667 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter\Spl; use Rvx\DeepCopy\DeepCopy; use Rvx\DeepCopy\TypeFilter\TypeFilter; /** * In PHP 7.4 the storage of an ArrayObject isn't returned as * ReflectionProperty. So we deep copy its array copy. */ final class ArrayObjectFilter implements TypeFilter { /** * @var DeepCopy */ private $copier; public function __construct(DeepCopy $copier) { $this->copier = $copier; } /** * {@inheritdoc} */ public function apply($arrayObject) { $clone = clone $arrayObject; foreach ($arrayObject->getArrayCopy() as $k => $v) { $clone->offsetSet($k, $this->copier->copy($v)); } return $clone; } } deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php 0000777 00000002021 15251766565 0021360 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter\Spl; use Closure; use Rvx\DeepCopy\DeepCopy; use Rvx\DeepCopy\TypeFilter\TypeFilter; use SplDoublyLinkedList; /** * @final */ class SplDoublyLinkedListFilter implements TypeFilter { private $copier; public function __construct(DeepCopy $copier) { $this->copier = $copier; } /** * {@inheritdoc} */ public function apply($element) { $newElement = clone $element; $copy = $this->createCopyClosure(); return $copy($newElement); } private function createCopyClosure() { $copier = $this->copier; $copy = function (SplDoublyLinkedList $list) use($copier) { // Replace each element in the list with a deep copy of itself for ($i = 1; $i <= $list->count(); $i++) { $copy = $copier->recursiveCopy($list->shift()); $list->push($copy); } return $list; }; return Closure::bind($copy, null, DeepCopy::class); } } deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php 0000777 00000000264 15251766565 0020221 0 ustar 00 <?php namespace Rvx\DeepCopy\TypeFilter\Spl; /** * @deprecated Use {@see SplDoublyLinkedListFilter} instead. */ class SplDoublyLinkedList extends SplDoublyLinkedListFilter { } deep-copy/composer.json 0000777 00000002032 15251766565 0011201 0 ustar 00 { "name": "myclabs\/deep-copy", "description": "Create deep copies (clones) of your objects", "license": "MIT", "type": "library", "keywords": [ "clone", "copy", "duplicate", "object", "object graph" ], "require": { "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine\/collections": "^1.6.8", "doctrine\/common": "^2.13.3 || ^3.2.2", "phpspec\/prophecy": "^1.10", "phpunit\/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "conflict": { "doctrine\/collections": "<1.6.8", "doctrine\/common": "<2.13.3 || >=3 <3.2.2" }, "autoload": { "psr-4": { "Rvx\\DeepCopy\\": "src\/DeepCopy\/" }, "files": [ "src\/DeepCopy\/deep_copy.php" ] }, "autoload-dev": { "psr-4": { "Rvx\\DeepCopyTest\\": "tests\/DeepCopyTest\/", "Rvx\\DeepCopy\\": "fixtures\/" } }, "config": { "sort-packages": true } } deep-copy/LICENSE 0000777 00000002065 15251766565 0007472 0 ustar 00 The MIT License (MIT) Copyright (c) 2013 My C-Sense Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. deep-copy/README.md 0000777 00000025017 15251766565 0007746 0 ustar 00 # DeepCopy DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph. [](https://packagist.org/packages/myclabs/deep-copy) [](https://github.com/myclabs/DeepCopy/actions/workflows/ci.yaml) ## Table of Contents 1. [How](#how) 1. [Why](#why) 1. [Using simply `clone`](#using-simply-clone) 1. [Overriding `__clone()`](#overriding-__clone) 1. [With `DeepCopy`](#with-deepcopy) 1. [How it works](#how-it-works) 1. [Going further](#going-further) 1. [Matchers](#matchers) 1. [Property name](#property-name) 1. [Specific property](#specific-property) 1. [Type](#type) 1. [Filters](#filters) 1. [`SetNullFilter`](#setnullfilter-filter) 1. [`KeepFilter`](#keepfilter-filter) 1. [`DoctrineCollectionFilter`](#doctrinecollectionfilter-filter) 1. [`DoctrineEmptyCollectionFilter`](#doctrineemptycollectionfilter-filter) 1. [`DoctrineProxyFilter`](#doctrineproxyfilter-filter) 1. [`ReplaceFilter`](#replacefilter-type-filter) 1. [`ShallowCopyFilter`](#shallowcopyfilter-type-filter) 1. [Edge cases](#edge-cases) 1. [Contributing](#contributing) 1. [Tests](#tests) ## How? Install with Composer: ``` composer require myclabs/deep-copy ``` Use it: ```php use DeepCopy\DeepCopy; $copier = new DeepCopy(); $myCopy = $copier->copy($myObject); ``` ## Why? - How do you create copies of your objects? ```php $myCopy = clone $myObject; ``` - How do you create **deep** copies of your objects (i.e. copying also all the objects referenced in the properties)? You use [`__clone()`](http://www.php.net/manual/en/language.oop5.cloning.php#object.clone) and implement the behavior yourself. - But how do you handle **cycles** in the association graph? Now you're in for a big mess :(  ### Using simply `clone`  ### Overriding `__clone()`  ### With `DeepCopy`  ## How it works 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. To use it: ```php use function DeepCopy\deep_copy; $copy = deep_copy($var); ``` Alternatively, you can create your own `DeepCopy` instance to configure it differently for example: ```php use DeepCopy\DeepCopy; $copier = new DeepCopy(true); $copy = $copier->copy($var); ``` You may want to roll your own deep copy function: ```php namespace Acme; use DeepCopy\DeepCopy; function deep_copy($var) { static $copier = null; if (null === $copier) { $copier = new DeepCopy(true); } return $copier->copy($var); } ``` ## Going further You can add filters to customize the copy process. The method to add a filter is `DeepCopy\DeepCopy::addFilter($filter, $matcher)`, with `$filter` implementing `DeepCopy\Filter\Filter` and `$matcher` implementing `DeepCopy\Matcher\Matcher`. We provide some generic filters and matchers. ### Matchers - `DeepCopy\Matcher` applies on a object attribute. - `DeepCopy\TypeMatcher` applies on any element found in graph, including array elements. #### Property name The `PropertyNameMatcher` will match a property by its name: ```php use DeepCopy\Matcher\PropertyNameMatcher; // Will apply a filter to any property of any objects named "id" $matcher = new PropertyNameMatcher('id'); ``` #### Specific property The `PropertyMatcher` will match a specific property of a specific class: ```php use DeepCopy\Matcher\PropertyMatcher; // Will apply a filter to the property "id" of any objects of the class "MyClass" $matcher = new PropertyMatcher('MyClass', 'id'); ``` #### Type 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): ```php use DeepCopy\TypeMatcher\TypeMatcher; // Will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection $matcher = new TypeMatcher('Doctrine\Common\Collections\Collection'); ``` ### Filters - `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` By design, matching a filter will stop the chain of filters (i.e. the next ones will not be applied). Using the ([`ChainableFilter`](#chainablefilter-filter)) won't stop the chain of filters. #### `SetNullFilter` (filter) 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: ```php use DeepCopy\DeepCopy; use DeepCopy\Filter\SetNullFilter; use DeepCopy\Matcher\PropertyNameMatcher; $object = MyClass::load(123); echo $object->id; // 123 $copier = new DeepCopy(); $copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); $copy = $copier->copy($object); echo $copy->id; // null ``` #### `KeepFilter` (filter) If you want a property to remain untouched (for example, an association to an object): ```php 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 has not been touched ``` #### `ChainableFilter` (filter) If you use cloning on proxy classes, you might want to apply two filters for: 1. loading the data 2. applying a transformation You can use the `ChainableFilter` as a decorator of the proxy loader filter, which won't stop the chain of filters (i.e. the next ones may be applied). ```php use DeepCopy\DeepCopy; use DeepCopy\Filter\ChainableFilter; use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; use DeepCopy\Filter\SetNullFilter; use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; use DeepCopy\Matcher\PropertyNameMatcher; $copier = new DeepCopy(); $copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); $copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); $copy = $copier->copy($object); echo $copy->id; // null ``` #### `DoctrineCollectionFilter` (filter) If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`: ```php use DeepCopy\DeepCopy; use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter; use DeepCopy\Matcher\PropertyTypeMatcher; $copier = new DeepCopy(); $copier->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection')); $copy = $copier->copy($object); ``` #### `DoctrineEmptyCollectionFilter` (filter) 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` ```php use DeepCopy\DeepCopy; use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter; use DeepCopy\Matcher\PropertyMatcher; $copier = new DeepCopy(); $copier->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty')); $copy = $copier->copy($object); // $copy->myProperty will return an empty collection ``` #### `DoctrineProxyFilter` (filter) 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!** We recommend to decorate the `DoctrineProxyFilter` with the `ChainableFilter` to allow applying other filters to the cloned lazy loaded entities. ```php use DeepCopy\DeepCopy; use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; $copier = new DeepCopy(); $copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); $copy = $copier->copy($object); // $copy should now contain a clone of all entities, including those that were not yet fully loaded. ``` #### `ReplaceFilter` (type filter) 1. If you want to replace the value of a property: ```php 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 contain the data returned by the callback, e.g. 'The title (copy)' ``` 2. If you want to replace whole element: ```php use DeepCopy\DeepCopy; use DeepCopy\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'] ``` The `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable. #### `ShallowCopyFilter` (type filter) Stop *DeepCopy* from recursively copying element, using standard `clone` instead: ```php 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 ``` ## Edge cases The following structures cannot be deep-copied with PHP Reflection. As a result they are shallow cloned and filters are not applied. There is two ways for you to handle them: - Implement your own `__clone()` method - Use a filter with a type matcher ## Contributing DeepCopy is distributed under the MIT license. ### Tests Running the tests is simple: ```php vendor/bin/phpunit ``` ### Support Get professional support via [the Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-myclabs-deep-copy?utm_source=packagist-myclabs-deep-copy&utm_medium=referral&utm_campaign=readme).
| ver. 1.6 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка