Skip to content

Commit 7d291c6

Browse files
committed
Fixed object info resolver
1 parent 7ed0635 commit 7d291c6

7 files changed

Lines changed: 55 additions & 16 deletions

File tree

src/AbstractInfo.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Opis\Closure;
44

5+
use WeakMap;
6+
57
abstract class AbstractInfo
68
{
79
protected ?string $key = null;
@@ -116,4 +118,19 @@ final public static function createKey(string $header, string $body): string
116118
$code = "$body\n$header";
117119
return $code === "\n" ? "" : md5($code);
118120
}
121+
122+
private static ?WeakMap $weakAssoc = null;
123+
124+
final public function assoc(object $obj): void
125+
{
126+
(self::$weakAssoc ??= new WeakMap())->offsetSet($obj, $this);
127+
}
128+
129+
public static function search(object $object): ?static
130+
{
131+
if (!self::$weakAssoc || !self::$weakAssoc->offsetExists($object)) {
132+
return null;
133+
}
134+
return self::$weakAssoc->offsetGet($object);
135+
}
119136
}

src/AbstractParser.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,6 @@ protected static function resolve(
200200
return null;
201201
}
202202

203-
// Try already deserialized
204-
// closure://...
205-
if ($fromStream = CodeStream::info($file)) {
206-
return $fromStream;
207-
}
208-
209203
// Get file key
210204
$fileKey = md5($file);
211205

src/ClosureInfo.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ public function hasScope(): bool
6868

6969
public function getClosure(?array &$vars = null, ?object $thisObj = null, ?string $scope = null): Closure
7070
{
71-
return $this->getFactory($thisObj, $scope)($vars);
71+
$closure = $this->getFactory($thisObj, $scope)($vars);
72+
$this->assoc($closure);
73+
return $closure;
7274
}
7375

7476
/**

src/ReflectionClass.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,17 @@ public function info(): ?AnonymousClassInfo
7878
// we don't provide info for non-anonymous classes
7979
return null;
8080
}
81-
return $this->_info ??= AnonymousClassParser::parse($this);
81+
82+
if ($this->_info) {
83+
return $this->_info;
84+
}
85+
86+
if (parent::isAnonymous()) {
87+
return $this->_info = AnonymousClassParser::parse($this);
88+
}
89+
90+
$key = substr($this->getShortName(), strlen(ReflectionClass::ANONYMOUS_CLASS_PREFIX));
91+
return $this->_info = AnonymousClassInfo::resolve($key);
8292
}
8393

8494
/**

src/ReflectionClosure.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public function __construct(Closure $closure)
1919
{
2020
/** @noinspection PhpUnhandledExceptionInspection */
2121
parent::__construct($closure);
22+
// grab the info if deserialized
23+
$this->info = ClosureInfo::search($closure);
2224
}
2325

2426
public function info(): ClosureInfo

src/SerializationHandler.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ public function serialize(mixed $data): string
3434
try {
3535
// get boxed structure
3636
$data = $this->handle($data);
37-
if ($this->hasClosures && $this->priority->count()) {
37+
if ($this->hasClosures && ($count = $this->priority->count())) {
3838
// we only need priority when we have closures
39-
$data = new PriorityWrapper(iterator_to_array($this->priority), $data);
39+
// do not try to wrap a single object
40+
if ($count !== 1 || !is_object($data) || !$this->priority->offsetExists($data)) {
41+
$data = new PriorityWrapper(iterator_to_array($this->priority), $data);
42+
}
4043
}
4144
return serialize($data);
4245
} finally {
@@ -136,26 +139,26 @@ private function handleObject(object $data): object
136139
return $this->handleClosure($data);
137140
}
138141

139-
$info = ReflectionClass::get(get_class($data));
140-
if (!$this->shouldBox($info)) {
142+
$reflector = ReflectionClass::get($data);
143+
if (!$this->shouldBox($reflector)) {
141144
// skip boxing
142145
return $this->objectMap[$data] = $data;
143146
}
144147

145-
if ($info->isAnonymousLike()) {
146-
$anonInfo = AnonymousClassParser::parse($info);
148+
if ($reflector->isAnonymousLike()) {
149+
$anonInfo = $reflector->info();
147150
$box = new Box(Box::TYPE_ANONYMOUS_CLASS, [null, null]);
148151
$box->data[0] = &$this->getCachedInfo($anonInfo);
149152
unset($anonInfo);
150153
} else {
151-
$box = new Box(Box::TYPE_OBJECT, [$info->name, null]);
154+
$box = new Box(Box::TYPE_OBJECT, [$reflector->name, null]);
152155
}
153156

154157
// Set mapping (before vars!)
155158
$this->objectMap[$data] = $box;
156159

157160
// Set vars
158-
$box->data[1] = $this->getObjectVars($data, $info);
161+
$box->data[1] = $this->getObjectVars($data, $reflector);
159162

160163
// Add to priority
161164
$this->priority->offsetSet($box);

tests/PHP80/SerializeTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,17 @@ public function testFactoryObj()
474474
$this->assertTrue((new ReflectionClosure($u1->factory))->info() === (new ReflectionClosure($u2->factory))->info());
475475
}
476476

477+
public function testNestedReserialization()
478+
{
479+
$f1 = fn() => [
480+
fn(int $a, int $b) => $a + $b,
481+
];
482+
$f1 = $this->process($f1);
483+
484+
$f2 = $this->process($f1()[0]);
485+
$this->assertEquals(3, $f2(1, 2));
486+
}
487+
477488
/**
478489
* @dataProvider fnDataProvider
479490
*/

0 commit comments

Comments
 (0)