-
Notifications
You must be signed in to change notification settings - Fork 11.5k
Open
Description
Laravel Version
12.26.4
PHP Version
8.4.8
Database Driver & Version
igbinary version => 3.2.16
Description
When using Redis as the cache store and enabling SERIALIZER_IGBINARY
, unserializing nested objects from the cache leads to inconsistent behavior: the unserialize process returns the wrong objects when Cache::many()
is called. In the example below, instead of receiving an instance of NestedClass
, an instance of RootClass
is returned.
This issue does not occur when the default serializer is used; it happens only when SERIALIZER_IGBINARY
is active.
I'm not certain whether this is an issue with Redis, the igbinary extension, or Laravel's Redis driver.
Example Output (Works as Expected: Default Serializer)
php artisan test-cache
"loaded in unserialize" // routes/console.php:27
NestedClass^ {#806
+name: "classC"
} // routes/console.php:27
"simple get" // routes/console.php:59
RootClass^ {#805
+content: "base"
+classC: NestedClass^ {#806
+name: "classC"
}
} // routes/console.php:59
"loaded in unserialize" // routes/console.php:27
NestedClass^ {#809
+name: "classC"
} // routes/console.php:27
"loaded in unserialize" // routes/console.php:27
NestedClass^ {#811
+name: "classC"
} // routes/console.php:27
"loaded in unserialize" // routes/console.php:27
NestedClass^ {#815
+name: "classC"
} // routes/console.php:27
array:3 [
"instance" => RootClass^ {#805
+content: "base"
+classC: NestedClass^ {#809
+name: "classC"
}
}
"instance-1" => RootClass^ {#808
+content: "base"
+classC: NestedClass^ {#811
+name: "classC"
}
}
"instance-2" => RootClass^ {#813
+content: "base"
+classC: NestedClass^ {#815
+name: "classC"
}
}
] // routes/console.php:63
Example Output (Error with SERIALIZER_IGBINARY
)
php artisan test-cache
"loaded in unserialize" // routes/console.php:27
NestedClass^ {#806
+name: "classC"
} // routes/console.php:27
"simple get" // routes/console.php:59
RootClass^ {#805
+content: "base"
+classC: NestedClass^ {#806
+name: "classC"
}
} // routes/console.php:59
"loaded in unserialize" // routes/console.php:27
NestedClass^ {#807
+name: "classC"
} // routes/console.php:27
"loaded in unserialize" // routes/console.php:27
RootClass^ {#813
+content: "base"
+classC: NestedClass^ {#807
+name: "classC"
}
} // routes/console.php:27
TypeError
Cannot assign RootClass to property RootClass::$classC of type NestedClass
at routes/console.php:28
24▕ {
25▕ $this->content = $data['content'];
26▕ $classC = Cache::get('classC');
27▕ dump('loaded in unserialize', $classC);
➜ 28▕ $this->classC = $classC;
29▕ }
30▕ }
31▕
32▕ class NestedClass {
1 [internal]:0
RootClass::__unserialize()
+7 vendor frames
9 routes/console.php:26
Illuminate\Support\Facades\Facade::__callStatic()
Steps To Reproduce
class RootClass {
public function __construct(
public string $content,
public NestedClass $classC,
) { }
public function __serialize(): array
{
return [
'content' => $this->content,
];
}
public function __unserialize(array $data): void
{
$this->content = $data['content'];
$classC = Cache::get('classC');
dump('loaded in unserialize', $classC);
$this->classC = $classC;
}
}
class NestedClass {
public function __construct(
public string $name,
) {}
public function __serialize(): array
{
return ['name' => $this->name];
}
public function __unserialize(array $data): void
{
$this->name = $data['name'];
}
}
Artisan::command('test-cache', function () {
$classC = new NestedClass('classC');
Cache::put('classC', $classC);
$instance = new RootClass('base', $classC);
Cache::put('instance', $instance);
Cache::put('instance-1', $instance);
Cache::put('instance-2', $instance);
// This works fine
dump('simple get', Cache::get('instance-1'));
// This works with the default serializer but not with SERIALIZER_IGBINARY
$back = Cache::many(['instance', 'instance-1', 'instance-2']);
dd($back);
});
Metadata
Metadata
Assignees
Labels
No labels