Skip to content

Commit b2c2878

Browse files
dontubtheofidry
authored andcommitted
Fix deep copying of ArrayObject in PHP 7.4 (#145)
1 parent 579bb73 commit b2c2878

File tree

4 files changed

+102
-1
lines changed

4 files changed

+102
-1
lines changed

src/DeepCopy/DeepCopy.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@
22

33
namespace DeepCopy;
44

5+
use ArrayObject;
56
use DateInterval;
67
use DateTimeInterface;
78
use DateTimeZone;
89
use DeepCopy\Exception\CloneException;
910
use DeepCopy\Filter\Filter;
1011
use DeepCopy\Matcher\Matcher;
12+
use DeepCopy\Reflection\ReflectionHelper;
1113
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
14+
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
1215
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
1316
use DeepCopy\TypeFilter\TypeFilter;
1417
use DeepCopy\TypeMatcher\TypeMatcher;
1518
use ReflectionObject;
1619
use ReflectionProperty;
17-
use DeepCopy\Reflection\ReflectionHelper;
1820
use SplDoublyLinkedList;
1921

2022
/**
@@ -59,6 +61,7 @@ public function __construct($useCloneMethod = false)
5961
{
6062
$this->useCloneMethod = $useCloneMethod;
6163

64+
$this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class));
6265
$this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class));
6366
$this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
6467
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
namespace DeepCopy\TypeFilter\Spl;
3+
4+
use ArrayObject;
5+
use DeepCopy\DeepCopy;
6+
use DeepCopy\TypeFilter\TypeFilter;
7+
8+
/**
9+
* In PHP 7.4 the storage of an ArrayObject isn't returned as
10+
* ReflectionProperty. So we deep copy its array copy.
11+
*/
12+
final class ArrayObjectFilter implements TypeFilter
13+
{
14+
/**
15+
* @var DeepCopy
16+
*/
17+
private $copier;
18+
19+
public function __construct(DeepCopy $copier)
20+
{
21+
$this->copier = $copier;
22+
}
23+
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function apply($arrayObject)
28+
{
29+
return new ArrayObject(
30+
$this->copier->copy($arrayObject->getArrayCopy()),
31+
$arrayObject->getFlags(),
32+
$arrayObject->getIteratorClass()
33+
);
34+
}
35+
}
36+

tests/DeepCopyTest/DeepCopyTest.php

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace DeepCopyTest;
44

5+
use ArrayObject;
56
use DateInterval;
67
use DateTime;
78
use DateTimeImmutable;
@@ -24,6 +25,7 @@
2425
use DeepCopy\TypeFilter\ShallowCopyFilter;
2526
use DeepCopy\TypeMatcher\TypeMatcher;
2627
use PHPUnit\Framework\TestCase;
28+
use RecursiveArrayIterator;
2729
use SplDoublyLinkedList;
2830
use stdClass;
2931
use function DeepCopy\deep_copy;
@@ -385,6 +387,18 @@ public function test_it_uses_the_first_filter_matching_for_copying_object_proper
385387
$this->assertNull($copy->getAProp()->cloned);
386388
}
387389

390+
public function test_it_can_deep_copy_an_array_object()
391+
{
392+
$foo = new f003\Foo('foo');
393+
$foo->setProp('bar');
394+
$object = new ArrayObject(['foo' => $foo, \ArrayObject::ARRAY_AS_PROPS, \RecursiveArrayIterator::class]);
395+
396+
$copy = deep_copy($object);
397+
398+
$this->assertEqualButNotSame($object, $copy);
399+
$this->assertEqualButNotSame($foo, $copy['foo']);
400+
}
401+
388402
/**
389403
* @ticket https://github.com/myclabs/DeepCopy/pull/49
390404
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace DeepCopyTest\TypeFilter\Spl;
4+
5+
use ArrayObject;
6+
use DeepCopy\DeepCopy;
7+
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
8+
use PHPUnit\Framework\TestCase;
9+
use Prophecy\Prophecy\ObjectProphecy;
10+
use RecursiveArrayIterator;
11+
12+
/**
13+
* @author Dominic Tubach <[email protected]>
14+
*
15+
* @covers \DeepCopy\TypeFilter\Spl\ArrayObjectFilter
16+
*/
17+
final class ArrayObjectFilterTest extends TestCase
18+
{
19+
/**
20+
* @var ArrayObjectFilter
21+
*/
22+
private $arrayObjectFilter;
23+
24+
/**
25+
* @var DeepCopy|ObjectProphecy
26+
*/
27+
private $copierProphecy;
28+
29+
protected function setUp(): void
30+
{
31+
$this->copierProphecy = $this->prophesize(DeepCopy::class);
32+
$this->arrayObjectFilter = new ArrayObjectFilter(
33+
$this->copierProphecy->reveal()
34+
);
35+
}
36+
37+
public function test_it_deep_copies_an_array_object(): void
38+
{
39+
$arrayObject = new ArrayObject(['foo' => 'bar'], ArrayObject::ARRAY_AS_PROPS, RecursiveArrayIterator::class);
40+
$this->copierProphecy->copy(['foo' => 'bar'])->willReturn(['copy' => 'bar']);
41+
42+
/** @var \ArrayObject $newArrayObject */
43+
$newArrayObject = $this->arrayObjectFilter->apply($arrayObject);
44+
$this->assertSame(['copy' => 'bar'], $newArrayObject->getArrayCopy());
45+
$this->assertSame(ArrayObject::ARRAY_AS_PROPS, $newArrayObject->getFlags());
46+
$this->assertSame(RecursiveArrayIterator::class, $newArrayObject->getIteratorClass());
47+
}
48+
}

0 commit comments

Comments
 (0)