[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-8208":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":18,"rankGlobal":9,"rankLanguage":9,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":20,"hasPages":20,"topics":22,"createdAt":9,"pushedAt":9,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":15,"starSnapshotCount":15,"syncStatus":28,"lastSyncTime":29,"discoverSource":30},8208,"DeepCopy","myclabs\u002FDeepCopy","myclabs","Create deep copies (clones) of your objects",null,"PHP",8889,108,22,17,0,1,4,37.11,"MIT License",false,"1.x",[23,24],"clone","clone-deep","2026-06-12 02:01:50","# DeepCopy\n\nDeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph.\n\n[![Total Downloads](https:\u002F\u002Fposer.pugx.org\u002Fmyclabs\u002Fdeep-copy\u002Fdownloads.svg)](https:\u002F\u002Fpackagist.org\u002Fpackages\u002Fmyclabs\u002Fdeep-copy)\n[![Integrate](https:\u002F\u002Fgithub.com\u002Fmyclabs\u002FDeepCopy\u002Factions\u002Fworkflows\u002Fci.yaml\u002Fbadge.svg?branch=1.x)](https:\u002F\u002Fgithub.com\u002Fmyclabs\u002FDeepCopy\u002Factions\u002Fworkflows\u002Fci.yaml)\n\n## Table of Contents\n\n1. [How](#how)\n1. [Why](#why)\n    1. [Using simply `clone`](#using-simply-clone)\n    1. [Overriding `__clone()`](#overriding-__clone)\n    1. [With `DeepCopy`](#with-deepcopy)\n1. [How it works](#how-it-works)\n1. [Going further](#going-further)\n    1. [Matchers](#matchers)\n        1. [Property name](#property-name)\n        1. [Specific property](#specific-property)\n        1. [Type](#type)\n    1. [Filters](#filters)\n        1. [`SetNullFilter`](#setnullfilter-filter)\n        1. [`KeepFilter`](#keepfilter-filter)\n        1. [`DoctrineCollectionFilter`](#doctrinecollectionfilter-filter)\n        1. [`DoctrineEmptyCollectionFilter`](#doctrineemptycollectionfilter-filter)\n        1. [`DoctrineProxyFilter`](#doctrineproxyfilter-filter)\n        1. [`ReplaceFilter`](#replacefilter-type-filter)\n        1. [`ShallowCopyFilter`](#shallowcopyfilter-type-filter)\n1. [Edge cases](#edge-cases)\n1. [Contributing](#contributing)\n    1. [Tests](#tests)\n\n\n## How?\n\nInstall with Composer:\n\n```\ncomposer require myclabs\u002Fdeep-copy\n```\n\nUse it:\n\n```php\nuse DeepCopy\\DeepCopy;\n\n$copier = new DeepCopy();\n$myCopy = $copier->copy($myObject);\n```\n\n\n## Why?\n\n- How do you create copies of your objects?\n\n```php\n$myCopy = clone $myObject;\n```\n\n- How do you create **deep** copies of your objects (i.e. copying also all the objects referenced in the properties)?\n\nYou use [`__clone()`](http:\u002F\u002Fwww.php.net\u002Fmanual\u002Fen\u002Flanguage.oop5.cloning.php#object.clone) and implement the behavior\nyourself.\n\n- But how do you handle **cycles** in the association graph?\n\nNow you're in for a big mess :(\n\n![association graph](doc\u002Fgraph.png)\n\n\n### Using simply `clone`\n\n![Using clone](doc\u002Fclone.png)\n\n\n### Overriding `__clone()`\n\n![Overriding __clone](doc\u002Fdeep-clone.png)\n\n\n### With `DeepCopy`\n\n![With DeepCopy](doc\u002Fdeep-copy.png)\n\n\n## How it works\n\nDeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it\nkeeps a hash map of all instances and thus preserves the object graph.\n\nTo use it:\n\n```php\nuse function DeepCopy\\deep_copy;\n\n$copy = deep_copy($var);\n```\n\nAlternatively, you can create your own `DeepCopy` instance to configure it differently for example:\n\n```php\nuse DeepCopy\\DeepCopy;\n\n$copier = new DeepCopy(true);\n\n$copy = $copier->copy($var);\n```\n\nYou may want to roll your own deep copy function:\n\n```php\nnamespace Acme;\n\nuse DeepCopy\\DeepCopy;\n\nfunction deep_copy($var)\n{\n    static $copier = null;\n    \n    if (null === $copier) {\n        $copier = new DeepCopy(true);\n    }\n    \n    return $copier->copy($var);\n}\n```\n\n\n## Going further\n\nYou can add filters to customize the copy process.\n\nThe method to add a filter is `DeepCopy\\DeepCopy::addFilter($filter, $matcher)`,\nwith `$filter` implementing `DeepCopy\\Filter\\Filter`\nand `$matcher` implementing `DeepCopy\\Matcher\\Matcher`.\n\nWe provide some generic filters and matchers.\n\n\n### Matchers\n\n  - `DeepCopy\\Matcher` applies on a object attribute.\n  - `DeepCopy\\TypeMatcher` applies on any element found in graph, including array elements.\n\n\n#### Property name\n\nThe `PropertyNameMatcher` will match a property by its name:\n\n```php\nuse DeepCopy\\Matcher\\PropertyNameMatcher;\n\n\u002F\u002F Will apply a filter to any property of any objects named \"id\"\n$matcher = new PropertyNameMatcher('id');\n```\n\n\n#### Specific property\n\nThe `PropertyMatcher` will match a specific property of a specific class:\n\n```php\nuse DeepCopy\\Matcher\\PropertyMatcher;\n\n\u002F\u002F Will apply a filter to the property \"id\" of any objects of the class \"MyClass\"\n$matcher = new PropertyMatcher('MyClass', 'id');\n```\n\n\n#### Type\n\nThe `TypeMatcher` will match any element by its type (instance of a class or any value that could be parameter of\n[gettype()](http:\u002F\u002Fphp.net\u002Fmanual\u002Fen\u002Ffunction.gettype.php) function):\n\n```php\nuse DeepCopy\\TypeMatcher\\TypeMatcher;\n\n\u002F\u002F Will apply a filter to any object that is an instance of Doctrine\\Common\\Collections\\Collection\n$matcher = new TypeMatcher('Doctrine\\Common\\Collections\\Collection');\n```\n\n\n### Filters\n\n- `DeepCopy\\Filter` applies a transformation to the object attribute matched by `DeepCopy\\Matcher`\n- `DeepCopy\\TypeFilter` applies a transformation to any element matched by `DeepCopy\\TypeMatcher`\n\nBy design, matching a filter will stop the chain of filters (i.e. the next ones will not be applied).\nUsing the ([`ChainableFilter`](#chainablefilter-filter)) won't stop the chain of filters.\n\n\n#### `SetNullFilter` (filter)\n\nLet's say for example that you are copying a database record (or a Doctrine entity), so you want the copy not to have\nany ID:\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\Filter\\SetNullFilter;\nuse DeepCopy\\Matcher\\PropertyNameMatcher;\n\n$object = MyClass::load(123);\necho $object->id; \u002F\u002F 123\n\n$copier = new DeepCopy();\n$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));\n\n$copy = $copier->copy($object);\n\necho $copy->id; \u002F\u002F null\n```\n\n\n#### `KeepFilter` (filter)\n\nIf you want a property to remain untouched (for example, an association to an object):\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\Filter\\KeepFilter;\nuse DeepCopy\\Matcher\\PropertyMatcher;\n\n$copier = new DeepCopy();\n$copier->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category'));\n\n$copy = $copier->copy($object);\n\u002F\u002F $copy->category has not been touched\n```\n\n\n#### `ChainableFilter` (filter)\n\nIf you use cloning on proxy classes, you might want to apply two filters for:\n1. loading the data\n2. applying a transformation\n\nYou can use the `ChainableFilter` as a decorator of the proxy loader filter, which won't stop the chain of filters (i.e. \nthe next ones may be applied).\n\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\Filter\\ChainableFilter;\nuse DeepCopy\\Filter\\Doctrine\\DoctrineProxyFilter;\nuse DeepCopy\\Filter\\SetNullFilter;\nuse DeepCopy\\Matcher\\Doctrine\\DoctrineProxyMatcher;\nuse DeepCopy\\Matcher\\PropertyNameMatcher;\n\n$copier = new DeepCopy();\n$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher());\n$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));\n\n$copy = $copier->copy($object);\n\necho $copy->id; \u002F\u002F null\n```\n\n\n#### `DoctrineCollectionFilter` (filter)\n\nIf you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`:\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\Filter\\Doctrine\\DoctrineCollectionFilter;\nuse DeepCopy\\Matcher\\PropertyTypeMatcher;\n\n$copier = new DeepCopy();\n$copier->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\\Common\\Collections\\Collection'));\n\n$copy = $copier->copy($object);\n```\n\n\n#### `DoctrineEmptyCollectionFilter` (filter)\n\nIf you use Doctrine and want to copy an entity who contains a `Collection` that you want to be reset, you can use the\n`DoctrineEmptyCollectionFilter`\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\Filter\\Doctrine\\DoctrineEmptyCollectionFilter;\nuse DeepCopy\\Matcher\\PropertyMatcher;\n\n$copier = new DeepCopy();\n$copier->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty'));\n\n$copy = $copier->copy($object);\n\n\u002F\u002F $copy->myProperty will return an empty collection\n```\n\n\n#### `DoctrineProxyFilter` (filter)\n\nIf you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a\nDoctrine proxy class (...\\\\\\_\\_CG\\_\\_\\Proxy).\nYou can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class.\n**Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded\nbefore other filters are applied!**\nWe recommend to decorate the `DoctrineProxyFilter` with the `ChainableFilter` to allow applying other filters to the\ncloned lazy loaded entities.\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\Filter\\Doctrine\\DoctrineProxyFilter;\nuse DeepCopy\\Matcher\\Doctrine\\DoctrineProxyMatcher;\n\n$copier = new DeepCopy();\n$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher());\n\n$copy = $copier->copy($object);\n\n\u002F\u002F $copy should now contain a clone of all entities, including those that were not yet fully loaded.\n```\n\n\n#### `ReplaceFilter` (type filter)\n\n1. If you want to replace the value of a property:\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\Filter\\ReplaceFilter;\nuse DeepCopy\\Matcher\\PropertyMatcher;\n\n$copier = new DeepCopy();\n$callback = function ($currentValue) {\n  return $currentValue . ' (copy)'\n};\n$copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title'));\n\n$copy = $copier->copy($object);\n\n\u002F\u002F $copy->title will contain the data returned by the callback, e.g. 'The title (copy)'\n```\n\n2. If you want to replace whole element:\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\TypeFilter\\ReplaceFilter;\nuse DeepCopy\\TypeMatcher\\TypeMatcher;\n\n$copier = new DeepCopy();\n$callback = function (MyClass $myClass) {\n  return get_class($myClass);\n};\n$copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass'));\n\n$copy = $copier->copy([new MyClass, 'some string', new MyClass]);\n\n\u002F\u002F $copy will contain ['MyClass', 'some string', 'MyClass']\n```\n\n\nThe `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable.\n\n\n#### `ShallowCopyFilter` (type filter)\n\nStop *DeepCopy* from recursively copying element, using standard `clone` instead:\n\n```php\nuse DeepCopy\\DeepCopy;\nuse DeepCopy\\TypeFilter\\ShallowCopyFilter;\nuse DeepCopy\\TypeMatcher\\TypeMatcher;\nuse Mockery as m;\n\n$this->deepCopy = new DeepCopy();\n$this->deepCopy->addTypeFilter(\n\tnew ShallowCopyFilter,\n\tnew TypeMatcher(m\\MockInterface::class)\n);\n\n$myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDependency2::class));\n\u002F\u002F All mocks will be just cloned, not deep copied\n```\n\n\n## Edge cases\n\nThe following structures cannot be deep-copied with PHP Reflection. As a result they are shallow cloned and filters are\nnot applied. There is two ways for you to handle them:\n\n- Implement your own `__clone()` method\n- Use a filter with a type matcher\n\n\n## Contributing\n\nDeepCopy is distributed under the MIT license.\n\n\n### Tests\n\nRunning the tests is simple:\n\n```php\nvendor\u002Fbin\u002Fphpunit\n```\n\n### Support\n\nGet professional support via [the Tidelift Subscription](https:\u002F\u002Ftidelift.com\u002Fsubscription\u002Fpkg\u002Fpackagist-myclabs-deep-copy?utm_source=packagist-myclabs-deep-copy&utm_medium=referral&utm_campaign=readme).\n","DeepCopy 是一个用于创建对象深层副本（克隆）的 PHP 库。其核心功能在于能够处理对象关联图中的循环引用，确保在复制过程中不会出现重复或丢失数据的情况。通过使用匹配器和过滤器，用户可以自定义复制行为，如设置空值、保留特定属性或替换某些类型的数据。DeepCopy 适用于需要对复杂对象结构进行深度复制的场景，特别是在那些对象间存在相互引用的情况下，比如在数据库实体之间的关系映射中。借助 Composer 可以轻松集成到项目中，为开发者提供了一个强大且灵活的对象复制解决方案。",2,"2026-06-11 03:16:48","top_language"]