[VOTE][RFC] Closure::call()

php.internals

Andrew Faulds

12 years ago
Good evening, I’ve updated the patch to work with phpng, so the Closure::call() RFC has been put to a vote: https://wiki.php.net/rfc/closure_apply#vote The vote ends 2014-08-17. The Function Referencing as Closures RFC is not yet being put to a vote. Thanks!
-- Andrea Faulds http://ajf.me/

Levi Morrison

12 years ago
I have a small clarification question on the RFC: you are adding another parameter to bindTo which defaults to false, but I didn't quite understand the reasoning. Can you try explaining that to me in a different way?

Stas Malyshev

12 years ago
Hi!
> I have a small clarification question on the RFC: you are adding > another parameter to bindTo which defaults to false, but I didn't > quite understand the reasoning. Can you try explaining that to me in a > different way?
Interestingly enough, the RFC doesn't even mention this change.
-- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/

Andrew Faulds

12 years ago
On 17 Aug 2014, at 22:36, Levi Morrison <levim@php.net> wrote:
> I have a small clarification question on the RFC: you are adding > another parameter to bindTo which defaults to false, but I didn't > quite understand the reasoning. Can you try explaining that to me in a > different way?
I’ll give it a go. Closures have a bound object and a scope. The bound object is whatever $this will be set to when that closure is called. The scope is the class whose private variables can be seen by a closure. ->call() will call the closure and use its existing scope but the bound object will be what is passed as its first parameter. ->call() doesn’t permit calling with a different scope. This presents a conundrum, however, if you want to use ->call() with a closure and you want to have a scope. Currently, ::bind() and ->bindTo() only permit two types of closures with scopes: those that are static (can’t have $this bound) and those that have an object bound. This means to create a closure with a scope that you can then use with ->call(), you’d have to make one with a dummy object already bound. In most cases you can do this, but there are a few you can’t, and it’s weird to have to bind an object when we’re not going to use it anyway as ->call() is going to override it. For this reason, a third parameter is added to ::bind() and ->bindTo() which makes it produce an unbound, scoped closure rather than a static scoped closure if we don’t pass an object to be bound and we specify a scope. The need for the third parameter is really just backwards-compatibility. At the moment, if you pass NULL for the object to bind to and pass a class name for the scope, it’ll make a static closure. We could change this and make it produce an unbound closure and add some other mechanism to obtain a static closure, but that would break backwards-compatibility. For this reason, we instead add a third parameter to say, yes, we do want an unbound closure. The same thing is done internally too, with zend_create_closure_ex. On 17 Aug 2014, at 22:55, Stas Malyshev <smalyshev@sugarcrm.com> wrote:
> Hi! > >> I have a small clarification question on the RFC: you are adding >> another parameter to bindTo which defaults to false, but I didn't >> quite understand the reasoning. Can you try explaining that to me in a >> different way? > > Interestingly enough, the RFC doesn't even mention this change.
It does, but maybe you missed it. Under the Proposal section:
> To solve this, we relax the current invariant of scoped closures having to be bound, and add a new parameter to bind(To) to produce an unbound, scoped closure, like so:
-- Andrea Faulds http://ajf.me/

Stas Malyshev

12 years ago
Hi!
> It does, but maybe you missed it. Under the Proposal section: > >> To solve this, we relax the current invariant of scoped closures >> having to be bound, and add a new parameter to bind(To) to produce >> an unbound, scoped closure, like so:
Indeed, I missed it - I was looking for bindTo. I think it should be made more prominent, and I'm not sure what closure that is not static, but does not have a bound object, means. What happens if you call it? It sounds a bit strange concept - why would you need a closure that is not static, but is not bound to any object?
-- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/

Levi Morrison

12 years ago
On Sun, Aug 17, 2014 at 5:13 PM, Stas Malyshev <smalyshev@sugarcrm.com> wrote:
> Hi! > >> It does, but maybe you missed it. Under the Proposal section: >> >>> To solve this, we relax the current invariant of scoped closures >>> having to be bound, and add a new parameter to bind(To) to produce >>> an unbound, scoped closure, like so: > > Indeed, I missed it - I was looking for bindTo. I think it should be > made more prominent, and I'm not sure what closure that is not static, > but does not have a bound object, means. What happens if you call it? It > sounds a bit strange concept - why would you need a closure that is not > static, but is not bound to any object?
Hence the vote was cancelled while it is reworked.

Andrew Faulds

12 years ago
On 18 Aug 2014, at 00:40, Levi Morrison <levim@php.net> wrote:
> On Sun, Aug 17, 2014 at 5:13 PM, Stas Malyshev <smalyshev@sugarcrm.com> wrote: >> Hi! >> >>> It does, but maybe you missed it. Under the Proposal section: >>> >>>> To solve this, we relax the current invariant of scoped closures >>>> having to be bound, and add a new parameter to bind(To) to produce >>>> an unbound, scoped closure, like so: >> >> Indeed, I missed it - I was looking for bindTo. I think it should be >> made more prominent, and I'm not sure what closure that is not static, >> but does not have a bound object, means. What happens if you call it? It >> sounds a bit strange concept - why would you need a closure that is not >> static, but is not bound to any object? > > Hence the vote was cancelled while it is reworked.
To clarify: The RFC has been reworked now, I actually changed the RFC and patch just before I cancelled the vote. Review appreciated before vote is reopened.
-- Andrea Faulds http://ajf.me/

Nathan Bruer

12 years ago
I will +1 this as I have had to deal with some of these struggles, as a suggestion though: "Like the bind(To) methods, a static class cannot be bound (using →call will fail)" I would like to see this function work like Closure::bind()/Closure::bindTo() and give the option for the $newScope option.
> why would you need a closure that is not static, > but is not bound to any object?
I think I can answer this, I wrote a project which allows for "hooks" to be installed in areas of the code. I made it so each [static] method has a "before" and "after" which may be tied to it. This allows for things like: "beforeUpdate()" or "afterUpdate" or "afterCreate" exc... The framework handled the installation and execution of all hooks that a dev may have wished to install. If a method like this was available it would use much less resources and be faster in theory because the PHP engine would not need to create an entirely new object/closure every time I wished to execute the method. Simple example of what I spoke of above: https://gist.github.com/allada/b7e880104e3a7eb13a63 Notice how you don't need to create an entirely new object just to call a method inside a scope. This allows a dev to make their closure have access to $this just as if it was installed inside the function it's hooking into. On Mon, Aug 18, 2014 at 7:04 PM, Andrea Faulds <ajf@ajf.me> wrote:

Andrew Faulds

12 years ago
On 17 Aug 2014, at 20:33, Andrea Faulds <ajf@ajf.me> wrote:
> https://wiki.php.net/rfc/closure_apply#vote > > The vote ends 2014-08-17. The Function Referencing as Closures RFC is not yet being put to a vote.
I cancelled the vote as I’ve changed what the RFC does after some discussion. Instead of having unbound, scoped closures, I’ve instead just made ->call use whatever class the passed object has as its scope. I’ll reopen voting in 2 days as I think this is a rather uncontroversial change.
-- Andrea Faulds http://ajf.me/