Skip to content

Commit 1d33df7

Browse files
committed
Fix case when SerializableClosure uses as class property
1 parent d715a63 commit 1d33df7

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
composer.lock
33
/phpunit.xml
44
.phpunit.result.cache
5+
.idea

Diff for: src/Serializers/Native.php

+21-5
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,31 @@ public function __unserialize($data)
194194

195195
$this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']);
196196

197-
if (! empty($this->code['objects'])) {
198-
foreach ($this->code['objects'] as $item) {
199-
$item['property']->setValue($item['instance'], $item['object']->getClosure());
200-
}
201-
}
197+
$this->bindObjectsIfNeeded();
202198

203199
$this->code = $this->code['function'];
204200
}
205201

202+
private function bindObjectsIfNeeded() {
203+
if (!empty($this->code['objects'])) {
204+
$this->bindObjects();
205+
}
206+
}
207+
208+
private function bindObjects() {
209+
foreach ($this->code['objects'] as $item) {
210+
$item['property']->setValue($item['instance'], $this->calculateObjectValue($item));
211+
}
212+
}
213+
214+
private function calculateObjectValue($item) {
215+
return $this->isSerializableClosure($item['object']) ? $item['object'] : $item['object']->getClosure();
216+
}
217+
218+
private function isSerializableClosure($object): bool {
219+
return $object instanceof SerializableClosure || $object instanceof UnsignedSerializableClosure;
220+
}
221+
206222
/**
207223
* Ensures the given closures are serializable.
208224
*

Diff for: tests/Fixtures/ClassWithPublicProperty.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Fixtures;
6+
7+
class ClassWithPublicProperty {
8+
public $closure;
9+
10+
public function __construct($closure)
11+
{
12+
$this->closure = $closure;
13+
}
14+
}

Diff for: tests/SerializerTest.php

+27
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Laravel\SerializableClosure\Serializers\Signed;
77
use Laravel\SerializableClosure\Support\ReflectionClosure;
88
use Laravel\SerializableClosure\UnsignedSerializableClosure;
9+
use Tests\Fixtures\ClassWithPublicProperty;
910
use Tests\Fixtures\Model;
1011

1112
test('closure with simple const', function () {
@@ -485,6 +486,32 @@ function () {
485486
new CarbonImmutable,
486487
]);
487488

489+
test('SerializableClosure in the class property', function () {
490+
SerializableClosure::setSecretKey('foo');
491+
492+
$innerClosure = new ClassWithPublicProperty(new SerializableClosure(function () {}));
493+
$outerClosure = new SerializableClosure(function () use ($innerClosure) {
494+
return $innerClosure->closure;
495+
});
496+
497+
$unSerializedOuterClosure = unserialize(serialize($outerClosure));
498+
499+
expect($outerClosure())->toBeInstanceOf(SerializableClosure::class);
500+
expect($unSerializedOuterClosure())->toBeInstanceOf(SerializableClosure::class);
501+
});
502+
503+
test('UnsignedSerializableClosure in the class property', function () {
504+
$innerClosure = new ClassWithPublicProperty(SerializableClosure::unsigned(function () {}));
505+
$outerClosure = SerializableClosure::unsigned(function () use ($innerClosure) {
506+
return $innerClosure->closure;
507+
});
508+
509+
$unSerializedOuterClosure = unserialize(serialize($outerClosure));
510+
511+
expect($outerClosure())->toBeInstanceOf(UnsignedSerializableClosure::class);
512+
expect($unSerializedOuterClosure())->toBeInstanceOf(UnsignedSerializableClosure::class);
513+
});
514+
488515
function serializer_php_74_switch_statement_test_is_two($a)
489516
{
490517
return $a === 2;

0 commit comments

Comments
 (0)