Skip to content

Commit

Permalink
Fix deep copying of ArrayObject in PHP 7.4
Browse files Browse the repository at this point in the history
In PHP 7.4 the storage of an ArrayObject isn't returned as
ReflectionProperty.
  • Loading branch information
Dominic Tubach committed Dec 17, 2019
1 parent 579bb73 commit 8dcad4e
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/DeepCopy/DeepCopy.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@

namespace DeepCopy;

use ArrayObject;
use DateInterval;
use DateTimeInterface;
use DateTimeZone;
use DeepCopy\Exception\CloneException;
use DeepCopy\Filter\Filter;
use DeepCopy\Matcher\Matcher;
use DeepCopy\Reflection\ReflectionHelper;
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
use DeepCopy\TypeFilter\TypeFilter;
use DeepCopy\TypeMatcher\TypeMatcher;
use ReflectionObject;
use ReflectionProperty;
use DeepCopy\Reflection\ReflectionHelper;
use SplDoublyLinkedList;

/**
Expand Down Expand Up @@ -59,6 +61,7 @@ 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 SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
}
Expand Down
36 changes: 36 additions & 0 deletions src/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
namespace DeepCopy\TypeFilter\Spl;

use ArrayObject;
use DeepCopy\DeepCopy;
use 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)
{
return new ArrayObject(
$this->copier->copy($arrayObject->getArrayCopy()),
$arrayObject->getFlags(),
$arrayObject->getIteratorClass()
);
}
}

14 changes: 14 additions & 0 deletions tests/DeepCopyTest/DeepCopyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace DeepCopyTest;

use ArrayObject;
use DateInterval;
use DateTime;
use DateTimeImmutable;
Expand All @@ -24,6 +25,7 @@
use DeepCopy\TypeFilter\ShallowCopyFilter;
use DeepCopy\TypeMatcher\TypeMatcher;
use PHPUnit\Framework\TestCase;
use RecursiveArrayIterator;
use SplDoublyLinkedList;
use stdClass;
use function DeepCopy\deep_copy;
Expand Down Expand Up @@ -385,6 +387,18 @@ public function test_it_uses_the_first_filter_matching_for_copying_object_proper
$this->assertNull($copy->getAProp()->cloned);
}

public function test_it_can_deep_copy_an_array_object()
{
$foo = new f003\Foo('foo');
$foo->setProp('bar');
$object = new ArrayObject(['foo' => $foo, \ArrayObject::ARRAY_AS_PROPS, \RecursiveArrayIterator::class]);

$copy = deep_copy($object);

$this->assertEqualButNotSame($object, $copy);
$this->assertEqualButNotSame($foo, $copy['foo']);
}

/**
* @ticket https://github.com/myclabs/DeepCopy/pull/49
*/
Expand Down
48 changes: 48 additions & 0 deletions tests/DeepCopyTest/TypeFilter/Spl/ArrayObjectFilterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php declare(strict_types=1);

namespace DeepCopyTest\TypeFilter\Spl;

use ArrayObject;
use DeepCopy\DeepCopy;
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
use PHPUnit\Framework\TestCase;
use Prophecy\Prophecy\ObjectProphecy;
use RecursiveArrayIterator;

/**
* @author Dominic Tubach <dominic.tubach@to.com>
*
* @covers \DeepCopy\TypeFilter\Spl\ArrayObjectFilter
*/
final class ArrayObjectFilterTest extends TestCase
{
/**
* @var ArrayObjectFilter
*/
private $arrayObjectFilter;

/**
* @var DeepCopy|ObjectProphecy
*/
private $copierProphecy;

protected function setUp(): void
{
$this->copierProphecy = $this->prophesize(DeepCopy::class);
$this->arrayObjectFilter = new ArrayObjectFilter(
$this->copierProphecy->reveal()
);
}

public function test_it_deep_copies_an_array_object(): void
{
$arrayObject = new ArrayObject(['foo' => 'bar'], ArrayObject::ARRAY_AS_PROPS, RecursiveArrayIterator::class);
$this->copierProphecy->copy(['foo' => 'bar'])->willReturn(['copy' => 'bar']);

/** @var \ArrayObject $newArrayObject */
$newArrayObject = $this->arrayObjectFilter->apply($arrayObject);
$this->assertSame(['copy' => 'bar'], $newArrayObject->getArrayCopy());
$this->assertSame(ArrayObject::ARRAY_AS_PROPS, $newArrayObject->getFlags());
$this->assertSame(RecursiveArrayIterator::class, $newArrayObject->getIteratorClass());
}
}

0 comments on commit 8dcad4e

Please sign in to comment.