Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should closures with $this keyword be wrapped in an additional closure? #117

Open
nmeri17 opened this issue Apr 12, 2022 · 2 comments
Open

Comments

@nmeri17
Copy link

nmeri17 commented Apr 12, 2022

The examples in the docs referring to $this all use classes, but I just want to serialize a closure, not the entire class. I'm passing the following closure to the serializer

function () use ($outerVar) {

	return $outerVar . "/" . $this->myProperty;
}

And it throws the error "PDOException: You cannot serialize or unserialize PDO instances". I don't have a PDO instance anywhere close to where this closure is sent down to serializer. I realized other closures work without the $this keyword, combined with clues from reading other issues, I wrapped closure in additional closure

function () use ($outerVar) {

	return function () use ($outerVar) {

		return $outerVar . "/" . $this->myProperty;
	};
}

And error disappeared during serialization, but issue still stands. See next paragraph. I'm able to serialize and unserialize, but this doesn't seem to be intended use since I can't bind $this to context where closure is unserialized at. When I unserialize like so:

public function evaluateClosure (callable $receivedClosure) {
	$callable = unserialize($receivedClosure)->getClosure();

	$callable->bindTo($this, $this); // so dev can have access to `myProperty`
	// also tried ->bindTo(null)

	var_dump($callable()); // returns the outer closure

Then, going further to call $callable()() results in "Error: Using $this when not in object context". Is this a serialization problem or a binding one?

@nmeri17
Copy link
Author

nmeri17 commented Apr 12, 2022

Update: My bad. I just realised bindTo doesn't modify original closure but returns a new instance. I should have assigned the result of $callable->bindTo($this, $this);

You can close issue after confirming closure should be doubly wrapped

@sorinsarca
Copy link
Member

If your $this is not serializable then it has nothing to do with closure serialization.
To avoid $this serialization consider making the closure static and possibly refactor the code.
You may may need to wrap the closure if you want to have an unserializable $this and still serialize the closure

$wrapper = static function ($self) use ($outerVar) {
  return static function() use ($self, $outerVar) {
    return $outerVar . "./" . $self->myProperty;
  };
};
public function evaluateClosure (callable $receivedClosure) {
	$callable = unserialize($receivedClosure)->getClosure();

	return $callable($this); // set $self to $this in inner closure and return it
}

Anyway, this may work for simple cases, but wrapping a lot of closures makes the code hard to follow.
The best option is to make $this serializable, there are lot of libs you can use instead of raw PDO objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants