On Sun, Jan 22, 2023, at 11:45 AM, Ollie Read wrote:
> Hello all,
>
> I've created a feature request issue on GitHub (here: 
> https://github.com/php/php-src/issues/10414), but I have been advised 
> that it's best to post here.
>
> What I would like to introduce/suggest, is the ability to create a 
> closure from a method using the first-class-callable syntax (eg: 
> MyClass::aMethod(...)), for a non-static method, statically. 
>
> Currently, the following code causes an error.
>
> ```
> class Test {
>     public function test(): string { return 'test'; }
> }
> 
> $closure = Test::test(...);
> ```
>
> I understand why the error is thrown, but, and I'm unsure of the 
> specifics regarding this, I think we could delay the error until the 
> closure was called. The reason for this, is that closures can be bound, 
> so if you followed on from the code above, you could do the following:
>
> ```
> $closure->bindTo(new Test);
> $closure();
> ```
>
> The above would bind the closure in $closure to the scope of an object, 
> which in this case, is the class that the method belongs to.
>
> The best example I can think, for this, would be when filter a 
> collection of instances. If you were using a collection library, you 
> would currently have something like the following:
>
> ```
> $collection->filter(function (Str $string) {
>     return !$string->empty();
> });
> ```
>
> Whereas it would be much nicer to have the following:
>
> ```
> $collection->filter(Str::empty(...));
> ```
>
> In this situation, the collection library would be responsible for 
> binding the closure to the value it is iterating.

So you'd implement this yourself elsewhere?

class Str {
  public function empty(): bool { ... }
}

I don't see in this example how this is any better than what is already 
currently possible:

class Str {
  public static function empty(Str $s): bool { ... }
}

$collection->filter(Str::empty(...));

> I have limited experience with PHPs source, and C in general, but my 
> understanding would be that if we were creating a closure, we would 
> skip the check for the static method. The code responsible for handling 
> the closure call would most require some additional functionality to 
> check if it was bound to a valid instance, returning an error if it 
> isn't, and then returning an error if it isn't bound at all and the 
> method isn't static.
>
> The more I think about it, the more I think this may require a new type 
> of Closure, or at least a runtime applied interface, to help developers 
> determine whether a closure was created using first-class-callable 
> syntax.

This is, I think, the important part here, and would be a prerequisite.  Right 
now there's no way (as far as I know) to differentiate a closure that is 
callable from one that would be callable if it were bound to an object.  That's 
generally not a huge deal in practice as unbound closures are not often used, 
but what you're suggesting would make them much more likely.  Also, a static 
closure cannot be bound, so you cannot just blindly bind whatever callable 
you're passed to $this, in your example.  (Besides, blindly binding a closure 
to $this sounds like a great security hole.)

So for some variant of this to work, I think you'd first need to think through 
how to (easily and without dipping into reflection) determine if a closure 
object is bindable (static or not) and if it's already bound.  Once that's 
figured out, then we can see what, if any, short-hand way to make a 
not-yet-bound closure makes sense.  (Which could be FCC syntax or not, I don't 
know.)

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to