Skip to content

Commit c5f82d0

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

File tree

4 files changed

+70
-5
lines changed

4 files changed

+70
-5
lines changed

.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

src/Serializers/Native.php

+25-5
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,35 @@ 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+
{
204+
if (!empty($this->code['objects'])) {
205+
$this->bindObjects();
206+
}
207+
}
208+
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;
224+
}
225+
206226
/**
207227
* Ensures the given closures are serializable.
208228
*
+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+
}

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)