Skip to content

Commit 9b6ef5f

Browse files
authored
Reference bug (#155)
* Fixed #154 - reference bug * Updated changelog
1 parent 1a22899 commit 9b6ef5f

File tree

4 files changed

+32
-7
lines changed

4 files changed

+32
-7
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
CHANGELOG
22
---------
33

4+
### v4.3.1, 2025.01.10
5+
6+
- Fixed reference bug [#154](https://github.com/opis/closure/issues/154)
7+
48
### v4.3.0, 2025.01.08
59

610
- Proper serialization of private properties

src/DeserializationHandler.php

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

33
namespace Opis\Closure;
44

5-
use stdClass, WeakMap, Closure;
5+
use stdClass, WeakMap, Closure, SplObjectStorage;
66
use function unserialize;
77

88
/**
@@ -15,6 +15,8 @@ class DeserializationHandler
1515
private ?array $visitedArrays = null;
1616
private array $options;
1717

18+
private ?SplObjectStorage $refKeepAlive;
19+
1820
public function __construct(?array $options = null)
1921
{
2022
$this->options = $options ?? [];
@@ -25,6 +27,7 @@ public function unserialize(string $serialized): mixed
2527
$this->unboxed = new WeakMap();
2628
$this->refs = new WeakMap();
2729
$this->visitedArrays = [];
30+
$this->refKeepAlive = new SplObjectStorage();
2831

2932
if (Serializer::$v3Compatible) {
3033
$this->v3_unboxed = [];
@@ -46,7 +49,7 @@ public function unserialize(string $serialized): mixed
4649

4750
return $data;
4851
} finally {
49-
$this->unboxed = $this->refs = $this->visitedArrays = null;
52+
$this->unboxed = $this->refs = $this->visitedArrays = $this->refKeepAlive = null;
5053
$this->v3_unboxed = $this->v3_refs = null;
5154
}
5255
}
@@ -74,7 +77,7 @@ private function handleIterable(array|object &$iterable): void
7477

7578
private function handleArray(array &$array): void
7679
{
77-
$id = ReflectionClass::getRefId($array);
80+
$id = ReflectionClass::getRefId($array, $this->refKeepAlive);
7881
if (!isset($this->visitedArrays[$id])) {
7982
$this->visitedArrays[$id] = true;
8083
$this->handleIterable($array);

src/ReflectionClass.php

+10-2
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,17 @@ public static function objectIsEnum(object $value): bool
107107
return self::$enumExists && ($value instanceof \UnitEnum);
108108
}
109109

110-
public static function getRefId(mixed &$reference): ?string
110+
public static function getRefId(mixed &$reference, ?\SplObjectStorage $keepAlive = null): ?string
111111
{
112-
return \ReflectionReference::fromArrayElement([&$reference], 0)?->getId();
112+
$ref = \ReflectionReference::fromArrayElement([&$reference], 0);
113+
if (!$ref) {
114+
return null;
115+
}
116+
117+
// we save this so the ref ids cannot be reused while serializing/deserializing
118+
$keepAlive?->attach($ref);
119+
120+
return $ref->getId();
113121
}
114122

115123
public static function isAnonymousClassName(string $class): bool

src/SerializationHandler.php

+12-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class SerializationHandler
1919

2020
private bool $hasClosures;
2121

22+
private ?SplObjectStorage $refKeepAlive;
23+
2224
public function serialize(mixed $data): string
2325
{
2426
$this->arrayMap = [];
@@ -27,6 +29,7 @@ public function serialize(mixed $data): string
2729
$this->shouldBox = new WeakMap();
2830
$this->info = [];
2931
$this->hasClosures = false;
32+
$this->refKeepAlive = new SplObjectStorage();
3033

3134
try {
3235
// get boxed structure
@@ -37,7 +40,12 @@ public function serialize(mixed $data): string
3740
}
3841
return serialize($data);
3942
} finally {
40-
$this->arrayMap = $this->objectMap = $this->priority = $this->shouldBox = $this->info = null;
43+
$this->arrayMap =
44+
$this->objectMap =
45+
$this->priority =
46+
$this->refKeepAlive =
47+
$this->shouldBox =
48+
$this->info = null;
4149
}
4250
}
4351

@@ -155,12 +163,14 @@ private function handleObject(object $data): object
155163
return $box;
156164
}
157165

166+
private SplObjectStorage $keep;
167+
158168
private function &handleArray(array &$data, bool $skipRefId = false): array
159169
{
160170
if ($skipRefId) {
161171
$box = [];
162172
} else {
163-
$id = ReflectionClass::getRefId($data);
173+
$id = ReflectionClass::getRefId($data, $this->refKeepAlive);
164174
if (array_key_exists($id, $this->arrayMap)) {
165175
return $this->arrayMap[$id];
166176
}

0 commit comments

Comments
 (0)