Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.
https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
cheers
Dan
Ack
Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
+1, I'm not sure it belongs into ext/reflection, though?
--
Regards,
Mike
+1 on the concept, I tried to argue it belongs in /Zend too ... still think
it does ...
Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
+1, I'm not sure it belongs into ext/reflection, though?
--
Regards,
Mike
+1, I'm not sure it belongs into ext/reflection, though?
+1 on the concept, I tried to argue it belongs in /Zend too ... still think
Sure I'll move it to there when I finish off the patch with the slight
improvements in the error messages that are needed.
cheers
Dan
Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
+1 I like this a lot
Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
cheers
Dan
Ack--
I fixed a formatting error in
https://wiki.php.net/rfc/closurefromcallable#other_languages
Overall it looks good. I have a small quibble with:
However this RFC takes the position that it is inappropriate to have a separate function per type.
But that wouldn't make me vote no. I think it's valuable to have both
(just not with Hack's names… those are awful).
Hi Dan,
Dan Ackroyd wrote:
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
I've wanted something like this for a long time. All that being said,
though, I'm not sure a function is the way to do it. In C I can just use
the name of a function to get a function pointer, couldn't we do this in
PHP somehow? That is, array_map(strlen, ["foo", "foobar", "elePHPant"]);
rather than array_map(closure('strlen'), ...)
.
I realise this would be a bit difficult to do, but I think it's a nicer
approach.
Thanks.
--
Andrea Faulds
http://ajf.me/
On Tue, Sep 29, 2015 at 10:23 AM, Dan Ackroyd danack@basereality.com
wrote:
Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
Yes, but with one question: should it be named "reflection_closure"?
(I don't like that, but:) the user-land rules 1 say it will begin with
the extension name, and the coding standards 2 say it will if it's part
of a parent set.
Maybe put it in core instead of reflection extension. Or, since
ext/reflection doesn't have any functions, we can bypass it.
Hi Dan,
Dan Ackroyd wrote:
Here's some further thoughts on this RFC.
I don't like that it's a function. Closure is a class, classes can have
static and instance methods, and closure() looks like something that
should be a method on Closure. In fact, it creates a closure, which a
constructor would usually do. If we want to make it avoid duplication,
okay, then it could be a static method. But I'm unconvinced it should be
a function. Constructors go in their classes, we don't leave them lying
around as global functions. That's messy and inconsistent.
You say that it being a function would mean we could make it a language
construct to improve performance. But making it a language construct
means making Closure a reserved word, and probably break things, right?
We don't need to use a language construct for performance, though. Zend
Engine III lets us inline certain commonly-used functions (strlen and
is_int, for example). This requires that function references be absolute
with no ambiguity, which means prefixed with a backslash or being used
in non-namespaced code... but in practice few people type \ before root
namespace functions. Thing is, this ambiguity doesn't exist for classes.
Any usage of, say, \Closure::from (if we were to call it that) would be
inlineable, unless the programmer uses variable variables. So, I don't
buy that we should use a function for potential future performance with
a language construct, since we can do inlining with no breakage right
now if we use a static method.
If we were to make it a language construct, we should do it properly
and use proper syntax. No closure("foo") or closure(array("SomeClass",
"methodName")), instead closure(foo) or closure(SomeClass::methodName).
And in that case, we'd probably use the existing reserved word for this:
callable.
By the way, as proposed, closure() has a performance penalty. You're
calling a function to convert a callable into a closure, but that's
almost always unnecessary. You could simply use the callable directly.
closure(), as proposed, could also be done quite simply in userland, and
even optimised. Why should it be added to PHP core?
So, I think this proposal needs considerable work.
Thanks.
--
Andrea Faulds
http://ajf.me/
If we want to make it avoid duplication,
okay, then it could be a static method.
Okay, I'll update the RFC to be Closure::fromCallable()
rather than
a function.
I was hoping to have something less verbose than that, but you're
probably right when you say we ought to do that properly with it's own
syntax rather than just a function.
Oh using a static method will rule out being able to alias the
function with the use function syntax.
use function closure as _; //can work
use function Closure::fromCallable as _; //doesn't work
Which is slightly annoying but ¯_(ツ)_/¯
Additionally, I linked to the wrong branch in the RFC. It should be:
https://github.com/php/php-src/compare/master...Danack:closureSimpler
cheers
Dan
Hi!
I don't like that it's a function. Closure is a class, classes can have
static and instance methods, and closure() looks like something that
should be a method on Closure. In fact, it creates a closure, which a
constructor would usually do. If we want to make it avoid duplication,
okay, then it could be a static method. But I'm unconvinced it should be
a function. Constructors go in their classes, we don't leave them lying
around as global functions. That's messy and inconsistent.
Agree. Closure::fromCallable sounds like a good option.
That being said, I'm not sure how much need is for this - i.e. you can
always make a closure by just doing function() { return $this->blah(); }
if you need it. But the bigger question would be why you need more
specific type (Closure) instead of more generic (callable) and aren't
you overspecifying in that case?
And if we're into performance optimization - which should almost never
be done on language construct level, because performance considerations
vary and language constructs are forever - then it would be much better
to look into tail call optimizations. That would solve the barrier
between [$this, "foo"] and function() { return $this->foo(); } in many
practical cases.
--
Stas Malyshev
smalyshev@gmail.com
Hi!
I don't like that it's a function. Closure is a class, classes can have
static and instance methods, and closure() looks like something that
should be a method on Closure. In fact, it creates a closure, which a
constructor would usually do. If we want to make it avoid duplication,
okay, then it could be a static method. But I'm unconvinced it should be
a function. Constructors go in their classes, we don't leave them lying
around as global functions. That's messy and inconsistent.Agree. Closure::fromCallable sounds like a good option.
That being said, I'm not sure how much need is for this - i.e. you can
always make a closure by just doing function() { return $this->blah(); }
if you need it. But the bigger question would be why you need more
specific type (Closure) instead of more generic (callable) and aren't
you overspecifying in that case?And if we're into performance optimization - which should almost never
be done on language construct level, because performance considerations
vary and language constructs are forever - then it would be much better
to look into tail call optimizations. That would solve the barrier
between [$this, "foo"] and function() { return $this->foo(); } in many
practical cases.
I think the origin of this intention is, that calling a callable just by
$callable()
does not work consistently -- see the othe RFC by Dan -- and
that call_user_func()
suffers from a (mythical?) performance issue.
Hi!
I think the origin of this intention is, that calling a callable just
by$callable()
does not work consistently -- see the other RFC by
Dan --
Maybe we should fix $callable() then? :) I see no reason why $()
shouldn't work on all callables. That's why they are "callable" after all.
and that
call_user_func()
suffers from a (mythical?) performance
issue.
Fixing performance issues in a specific functions by introducing a
language-level constructs does not sound like the best option to me. I
would first ensure the issue exists and then look into how it can be
fixed with this specific function.
Stas Malyshev
smalyshev@gmail.com
Hi!
That being said, I'm not sure how much need is for this - i.e. you can
always make a closure by just doing function() { return $this->blah(); }
if you need it.
As I said before (and as the RFC says), there are ways to work around
not having it. But having to duplicate code and keep it in sync is a
pain and indicates that something is missing from the language.
And if we're into performance optimization
We're not. The performance stuff is nice side benefit, but it's not
the main aim of the RFC which is to make life easier for people who
want to create closures in PHP.
But the bigger question would be why you need more
specific type (Closure) instead of more generic (callable)
IMO it's actually the other way round; closures are more generic than callables.
To get the parameters of a closure via inspection you only ever need
to use ReflectionFunction. To get the parameters of a callable, you
need to figure out first what type of callable it is, and then either
use ReflectionFunction or ReflectionClass + ReflectionMethod as
appropriate.
And also callables are just a bit insane currently:
Maybe we should fix $callable() then? :)
Maybe we should!
I announced a draft RFC a week ago:
http://news.php.net/php.internals/88545 Only one person (off list) has
given any feedback on it so far. I invite more feedback! Even if it's
just "that's an amazing RFC Dan, you've covered every possible aspect
of the changes that need to be discussed." that would still be good
feedback to get.
But as that RFC could only be introduced for PHP 8 at the earliest,
and callable still won't be as easy to work with as closures, the
feedback I have received is that people would very much appreciate
having this RFC for 7.1
cheers
Dan
Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
Your first example on the page is a little weird to me. You claim that
one currently needs to have the callback method public, although you can
easily work around that. Instead of doing this, as in your example:
return [$this, 'genericValidation']
you could just do this:
return function ($data) { return $this->genericValidation($data); }
and keep the actual callback method private/protected.
--
Ben Scholzen 'DASPRiD'
Community Review Team Member | mail@dasprids.de
Zend Framework | http://www.dasprids.de
you could just do this:
return function ($data) { return $this->genericValidation($data); }
you could just do this:
return function ($data) { return $this->genericValidation($data); }
Yes, there are workarounds possible that don't need anything new i.e.
either implementing the closure generation function in userland or
doing a programmer generated closure.
The downside to writing the closure by hand is more obvious when the
parameters and return value is typed:
class Validator
{
private function genericValidation(callable $foo, string bar,
UserData $userData) : string {...}
public function getValidatorCallback($validationType) {
//...
return function (callable $foo, string bar, UserData
$userData) : string {
return $this->genericValidation($data);
};
}
}
All of the type checking has to be repeated in the programmer
generated closure, which is annoying as it means you have to keep code
in different places synchronized.
Additionally PHP is kindof slow in function calling. Wrapping the
method to be called in a userland land function makes calling it be
much slower than using an internally generated closure. In addition to
the function call overhead, all of the paramters and return type will
have their type checked twice; once when they're pased to the closure
and once when they're passed to the method.
cheers
Dan
As mentioned already by Andrea: why not just a named constructor on the
closure class, like Closure::fromCallable(callable $callable)
?
Much simpler, easier to find, etc etc...
Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
cheers
Dan
Ack
As mentioned already by Andrea: why not just a named constructor on the
closure class, likeClosure::fromCallable(callable $callable)
?
Much simpler, easier to find, etc etc...Hello internals,
I'd like to start a discussion of a proposal to allow closures to be
created in user-land without having to use a whole lot of reflection
code.https://wiki.php.net/rfc/closurefromcallable
Thanks to Joe and Bob for the assistance in the patch.
cheers
Dan
Ack--
Hello,
and what about changing the empty ctor of Closure to
__construct(callable $callable)?
And the usage would be new Closure([$this, 'abc']);?
Regards
Pavel Kouřil
Hi Pavel,
and what about changing the empty ctor of Closure to
__construct(callable $callable)?And the usage would be new Closure([$this, 'abc']);?
I'm going to change the RFC to use the 'named constructor'
Closure::fromCallable which should address the naming concerns.
IMO, default constructors are bad and I encourage people to stop using
them. In this case they are bad as they can't be passed as a callable.
Either 'closure' or 'Closure::fromCallable can be passed as a
callable:
function createClosure($callable, $name) {
// do stuff
return $callable($name);
}
foo('closure', 'bar');
foo([Closure::class, 'fromCallable'], 'bar');
foo('librarySpecificClosureGenerator', 'bar');
In addition, it's inappropriate to use default constructors in a class
where it is even slightly likely that you are going to have more than
one way of constructing that object, as you then have to hack around
the fact that you want to create other named constructors that don't
call the default constructor.
cheers
Dan