Call to undefined method Laravel\SerializableClosure\Serializers\Native::from()
henze-housepedia opened this issue · 6 comments
- Serializable Closure Version: 1.0.0
- Laravel Version: 8.62.0
- PHP Version: 8.0.11
- Database Driver & Version: -
Description:
I get Call to undefined method Laravel\SerializableClosure\Serializers\Native::from() when I serialize a closure that is using a $this object that contains closures.
Steps To Reproduce:
class BindToMe
{
private Closure $closure;
public function __construct(Closure $closure)
{
$this->closure = $closure;
}
public function hello()
{
echo ($this->closure)();
}
}
$serializable = new \Laravel\SerializableClosure\SerializableClosure(
Closure::bind(
function () {
$this->hello();
},
new BindToMe(fn() => 'Hi')
)
);
serialize($serializable);
You forgot to serialize the fn () => 'Hi'
closure, and you also forgot to bind the static::class
. Here is your example fixed:
class BindToMe
{
private $closure;
public function __construct($closure)
{
$this->closure = $closure;
}
public function hello()
{
echo ($this->closure)();
}
}
$serializable = new SerializableClosure(
Closure::bind(
function () {
$this->hello();
},
new BindToMe(new SerializableClosure(fn() => 'Hi')),
BindToMe::class
)
);
unserialize(serialize($serializable))->getClosure()(); // Hi
eh... but this has worked with the opis/closure package. Besides, I have checked this Native.php file, and it uses a static:from. That should point to a method in the same object (Native) and I can't find 'from'.
Also, if I wrote that class I encountered the error in, I could fix that yes, and I can add a workaround using opis that serializes it before this package does, but the missing 'from' method is clearly a bug.
adding the missing newScope parameter has no effect.
As this is used in laravel, this either is a breaking change or a bug (missing from method in the wrapClosures method of the Native class, line 227)
This bug would be fixed if you simply add the following code to the Native class:
public static function from(Closure $closure)
{
if (static::$context === null) {
$instance = new static($closure);
} elseif (isset(static::$context->scope[$closure])) {
$instance = static::$context->scope[$closure];
} else {
$instance = new static($closure);
static::$context->scope[$closure] = $instance;
}
return $instance;
}
Can you create an open source repository with that example working with the opis/closure package? I've just tested it, using opis/closure and laravel/serializable closure, and in both it requires the changes I've mentioned.
Here you go:
https://github.com/henze-housepedia/laravel-serializable-closure-bug
You where right about the newScope, and Opis requires the class variable without type definition, but other than that, Opis works like a charm, while this package still needs the 'from' method as mentioned in an earlier comment.
I saw a new release, but that won't fix it.
@henze-housepedia Thank you for replicating the bug on that open source repository.