Skip to content

Commit 274f5c7

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

File tree

4 files changed

+69
-4
lines changed

4 files changed

+69
-4
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

+24-4
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,33 @@ public function __unserialize($data)
194194

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

197+
$this->bindObjectsIfNeeded();
198+
199+
$this->code = $this->code['function'];
200+
}
201+
202+
private function bindObjectsIfNeeded()
203+
{
197204
if (! empty($this->code['objects'])) {
198-
foreach ($this->code['objects'] as $item) {
199-
$item['property']->setValue($item['instance'], $item['object']->getClosure());
200-
}
205+
$this->bindObjects();
201206
}
207+
}
202208

203-
$this->code = $this->code['function'];
209+
private function bindObjects()
210+
{
211+
foreach ($this->code['objects'] as $item) {
212+
$item['property']->setValue($item['instance'], $this->calculateObjectValue($item));
213+
}
214+
}
215+
216+
private function calculateObjectValue($item)
217+
{
218+
return $this->isSerializableClosure($item['object']) ? $item['object'] : $item['object']->getClosure();
219+
}
220+
221+
private function isSerializableClosure($object): bool
222+
{
223+
return $object instanceof SerializableClosure || $object instanceof UnsignedSerializableClosure;
204224
}
205225

206226
/**

Diff for: tests/Fixtures/ClassWithPublicProperty.php

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

Diff for: tests/SerializerTest.php

+29
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,34 @@ 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+
}));
494+
$outerClosure = new SerializableClosure(function () use ($innerClosure) {
495+
return $innerClosure->closure;
496+
});
497+
498+
$unSerializedOuterClosure = unserialize(serialize($outerClosure));
499+
500+
expect($outerClosure())->toBeInstanceOf(SerializableClosure::class);
501+
expect($unSerializedOuterClosure())->toBeInstanceOf(SerializableClosure::class);
502+
});
503+
504+
test('UnsignedSerializableClosure in the class property', function () {
505+
$innerClosure = new ClassWithPublicProperty(SerializableClosure::unsigned(function () {
506+
}));
507+
$outerClosure = SerializableClosure::unsigned(function () use ($innerClosure) {
508+
return $innerClosure->closure;
509+
});
510+
511+
$unSerializedOuterClosure = unserialize(serialize($outerClosure));
512+
513+
expect($outerClosure())->toBeInstanceOf(UnsignedSerializableClosure::class);
514+
expect($unSerializedOuterClosure())->toBeInstanceOf(UnsignedSerializableClosure::class);
515+
});
516+
488517
function serializer_php_74_switch_statement_test_is_two($a)
489518
{
490519
return $a === 2;

0 commit comments

Comments
 (0)