Closed
Description
Serializable Closure Version
2.0.3
PHP Version
8.4.4 on Linux / 8.4.5 on Windows
Description
Usages of relative namespaces get serialized to a wrong absolute namespace in PHP 8.4. It worked correctly in PHP 8.2.
Steps To Reproduce
Example code:
<?php
namespace MyApp\Cache;
class CacheFactory {
public function getCache() {
return 'cache';
}
}
namespace MyApp;
use Laravel\SerializableClosure\SerializableClosure;
require_once __DIR__ . '/vendor/autoload.php';
// The name 'Cache' is relative to the 'MyApp' namespace.
$closure = function (Cache\CacheFactory $cacheFactory) {
return $cacheFactory->getCache();
};
$serialized = serialize(new SerializableClosure($closure));
echo "Serialized: $serialized\n";
$closure = unserialize($serialized)->getClosure();
echo 'Received: ', $closure(new Cache\CacheFactory()), "\n";
Output in PHP 8.2:
Serialized: O:47:"Laravel\SerializableClosure\SerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:0:{}s:8:"function";s:92:"function (\MyApp\Cache\CacheFactory $cacheFactory) {
return $cacheFactory->getCache();
}";s:5:"scope";N;s:4:"this";N;s:4:"self";s:32:"00000000000000020000000000000000";}}
Received: cache
Note how in the closure, the name Cache
was not imported via use
and thus resolves relatively to MyApp
to mean \MyApp\Cache
. However, with PHP 8.4, this fails and outputs the following:
Serialized: O:47:"Laravel\SerializableClosure\SerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:0:{}s:8:"function";s:86:"function (\Cache\CacheFactory $cacheFactory) {
return $cacheFactory->getCache();
}";s:5:"scope";N;s:4:"this";N;s:4:"self";s:32:"00000000000000020000000000000000";}}
Received: PHP Fatal error: Uncaught TypeError: {closure:laravel-serializable-closure://function (\Cache\CacheFactory $cacheFactory) {
return $cacheFactory->getCache();
}:2}(): Argument #1 ($cacheFactory) must be of type Cache\CacheFactory, MyApp\Cache\CacheFactory given, called in C:\<snip>\b.php on line 27 and defined in laravel-serializable-closure://function (\Cache\CacheFactory $cacheFactory) {
return $cacheFactory->getCache();
}:2
The name Cache
was resolved to mean \Cache
for some reason, which obviously does not work.