Morning Internals,
Please review the following RFC:
https://wiki.php.net/rfc/functional-interfaces
An implementation is provided, and is testable on 3v4l.
Review of the implementation from those of you that do that would be
good :)
Cheers
Joe
Joe Watkins wrote on 18/04/2016 11:22:
Please review the following RFC: https://wiki.php.net/rfc/functional-interfaces An implementation is provided, and is testable on 3v4l.
This sounds like a really nice feature. As well as using functions to
implement existing interfaces, it gives a nice way of typehinting the
requirements of a callback without forcing users to create an object.
I must admit to being a bit confused by the term "functional interface"
at first, though, because "functional" has so many different meanings -
is this a term used elsewhere, or is it up for debate?
In particular, the error message "Fatal error: cannot implement non
functional interface IFoo" makes me wonder what's "non-functional" about
the interface. It would be clearer to me if it was more specific and
avoided the jargon, e.g. "Anonymous function cannot implement interface
with more than one method".
The error "functional interface cannot implement self" also seems
inconsistent with the others - here "functional interface" refers to the
implementation, not the interface. It might be clearer to just say
"cannot implement non interface self" anyway - there's nothing actually
special about "self" here, it's just another example of trying to use a
class as an interface, which is illegal whatever the implementation.
These are of course minor details, and the rest of the feature as
described sounds great. :)
Regards,
Rowan Collins
[IMSoP]
> I must admit to being a bit confused by the term "functional
interface" at first, though,
> because "functional" has so many different meanings - is this a term
used elsewhere,
> or is it up for debate?
The terminology is borrowed, Java 8 uses lamdas to implement specially
annotated interfaces, it refers to them as functional interfaces.
The other term is SAM ... but it feels a bit strange to give code a people
name, right ? :)
Single Abstract Method Interface Implementations is just ... too much ...
I find it to be a pretty concise description, although the wording of the
errors is definitely flexible.
The "non thing" wording was only chosen because it's used elsewhere in the
core, "non static" and so on.
It just feels a bit strange to say or think "functional interface", but
once you get over that ...
As far as anyone who is not familiar with the workings of PHP is concerned,
what they have is a function that implements an interface, functional
interface is a pretty good description of that.
Cheers
Joe
On Mon, Apr 18, 2016 at 12:34 PM, Rowan Collins
wrote:
> Joe Watkins wrote on 18/04/2016 11:22:
>
>> Please review the following RFC:
>>
>> https://wiki.php.net/rfc/functional-interfaces
>>
>> An implementation is provided, and is testable on 3v4l.
>>
>
> This sounds like a really nice feature. As well as using functions to
> implement existing interfaces, it gives a nice way of typehinting the
> requirements of a callback without forcing users to create an object.
>
> I must admit to being a bit confused by the term "functional interface" at
> first, though, because "functional" has so many different meanings - is
> this a term used elsewhere, or is it up for debate?
>
> In particular, the error message "Fatal error: cannot implement non
> functional interface IFoo" makes me wonder what's "non-functional" about
> the interface. It would be clearer to me if it was more specific and
> avoided the jargon, e.g. "Anonymous function cannot implement interface
> with more than one method".
>
> The error "functional interface cannot implement self" also seems
> inconsistent with the others - here "functional interface" refers to the
> *implementation*, not the interface. It might be clearer to just say
> "cannot implement non interface self" anyway - there's nothing actually
> special about "self" here, it's just another example of trying to use a
> class as an interface, which is illegal whatever the implementation.
>
> These are of course minor details, and the rest of the feature as
> described sounds great. :)
>
> Regards,
> --
> Rowan Collins
> [IMSoP]
Joe Watkins wrote on 18/04/2016 12:53:
Morning,
> I must admit to being a bit confused by the term "functional
interface" at first, though,
> because "functional" has so many different meanings - is this a
term used elsewhere,
> or is it up for debate?The terminology is borrowed, Java 8 uses lamdas to implement specially
annotated interfaces, it refers to them as functional interfaces.
Thanks, I figured that was probably the case.
As far as anyone who is not familiar with the workings of PHP is
concerned, what they have is a function that implements an interface,
functional interface is a pretty good description of that.
I guess what's confusing is that the new feature happens entirely at the
implementation end, but the term describes the interface itself. What we
actually have is a functional implementation of a normal,
non-annotated interface; but the interface is implicitly functional
because of having only a single method. So when the error says you have
a "non functional interface", it's not clear what you need to do about it.
I like the implicit definition, though, because it reduces the need for
a forwards compatibility break (libraries can support old versions of
PHP, but their users still take advantage of the new feature if they
want). So I'm not really sure how to make the definition of "functional
interface" clearer, other than making sure we write some decent
documentation. :)
Regards,
Rowan Collins
[IMSoP]
+1 for the feature, very nice syntactic sugar to solve some edge cases.
I agree with Rowan, i also do not like the name and propose to call them
closure interfaces. There are already various synonyms for closures:
- anonymous function
- lambda function
- callback*
However, the strongest argument to call them closure is the fact that
the the class in PHP itself is actually called \Closure. I would even
go as far as saying that the documentation should be updated to always
use that word everywhere.* The fact that only closures can implement
such interfaces strengthens the reason to call them as proposed in my
opinion. Just because Java calls them /functional/ does not mean that we
should.
Regarding error messages:
Fatal error: cannot implement non functional interface IFoo in
/in/65W6i on line 7
Fatal error: cannot implement nonclosure interface IFoo in
/in/65W6i on line 7
Note on grammar:
http://www.chicagomanualofstyle.org/qanda/data/faq/topics/HyphensEnDashesEmDashes/faq0079.html
*) There is of course the situation of the various other ways to declare
the so called user functions (/call_user_func()/ and
/call_user_func_array()/) and those should always be referred to as
callback; imho.
--
Richard "Fleshgrinder" Fussenegger
Hi!
Please review the following RFC: https://wiki.php.net/rfc/functional-interfaces An implementation is provided, and is testable on 3v4l.
This looks like a rather narrow case already covered by anonymous
classes. Am I missing something? What is the added value of it that
can't be done now?
--
Stas Malyshev
smalyshev@gmail.com
Hi!
2016-04-18 15:17 GMT-04:00 Stanislav Malyshev smalyshev@gmail.com:
Hi!
Please review the following RFC: https://wiki.php.net/rfc/functional-interfaces An implementation is provided, and is testable on 3v4l.
This looks like a rather narrow case already covered by anonymous
classes. Am I missing something? What is the added value of it that
can't be done now?--
Stas Malyshev
smalyshev@gmail.com--
I haven't decided if I'm in favor of this feature yet but I asked the same
questions as you when the pull request landed. This gist served as a good
illustration of possible benefits
https://gist.github.com/marcioAlmada/12ef23038bcf5acaa2e2f6b808c968d3.
Boilerplate measuring apart, it seems logical that a closure should be able
to fulfill an interface with a single method.
About the applicability, I'm under the same impression as you, the use case
is probably narrow, perhaps because anonymous classes is a newly added
feature and wasn't explored enough.
Cheers.
Márcio Almada.
On Mon, Apr 18, 2016 at 12:17 PM, Stanislav Malyshev
smalyshev@gmail.com wrote:
Hi!
Please review the following RFC: https://wiki.php.net/rfc/functional-interfaces An implementation is provided, and is testable on 3v4l.
This looks like a rather narrow case already covered by anonymous
classes. Am I missing something? What is the added value of it that
can't be done now?
I thought Joe covered that question pretty thoroughly by his countable
examples. The version using anonymous classes certainly works, but
it's significantly more boilerplate code and has a higher cognitive
overhead compared to the functional interface example which is concise
and to the point.
That said, I'm not sure what I'd use it for, but as syntactic sugar
goes it's quite sleek.
-Sara
<?php
interface IFoo {
public function method() : int;
}
$cb1 = function () implements IFoo : int {
return 42;
};
$cb2 = new class implements IFoo {
function method() : int {
return 42;
}
};
?>
Are $cb1 and $cb2 going to be the same (do the same)?
Is this just a new syntax sugar, or a really new feature?
According to implementation, I think, you shouldn't extend "zend_closure" with "interface".
If this is a sugar, lets implement it as a sugar (without VM changes).
But may be I didn't understand the idea at all :)
Thanks. Dmitry.
Morning Dmitry,
In your example, they will do the same thing.
Anon classes don't have lexical scope, I have a patch for that, and an
RFC, I'm just tidying it.
Even when anon classes do have lexical scope, there is value in being
able to implement these kinds of interfaces using only a function.
The changes to the vm are restricted to a few lines, that's not seriously
a problem, is it !?
I don't see where I extend closure with an interface ...
zend_do_inheritance_ex(type, zend_ce_closure, 1); zend_class_implements(type, 1, interface);
Cheers
Joe
<?php
interface IFoo {
public function method() : int;
}$cb1 = function () implements IFoo : int {
return 42;
};$cb2 = new class implements IFoo {
function method() : int {
return 42;
}
};
?>Are $cb1 and $cb2 going to be the same (do the same)?
Is this just a new syntax sugar, or a really new feature?According to implementation, I think, you shouldn't extend "zend_closure"
with "interface".
If this is a sugar, lets implement it as a sugar (without VM changes).But may be I didn't understand the idea at all :)
Thanks. Dmitry.
From: Joe Watkins pthreads@pthreads.org
Sent: Monday, April 18, 2016 13:22
To: PHP internals
Subject: [PHP-DEV] RFC: Functional InterfacesMorning Internals,
Please review the following RFC: https://wiki.php.net/rfc/functional-interfaces An implementation is provided, and is testable on 3v4l. Review of the implementation from those of you that do that would be
good :)
Cheers
Joe
Oh, it's confusing text in the RFC, using the word "Interface" ... that's
meant as a placeholder for InterfaceName.
Cheers
Joe
Morning Dmitry,
In your example, they will do the same thing.
Anon classes don't have lexical scope, I have a patch for that, and an
RFC, I'm just tidying it.Even when anon classes do have lexical scope, there is value in being
able to implement these kinds of interfaces using only a function.The changes to the vm are restricted to a few lines, that's not
seriously a problem, is it !?I don't see where I extend closure with an interface ...
zend_do_inheritance_ex(type, zend_ce_closure, 1); zend_class_implements(type, 1, interface);
Cheers
Joe<?php
interface IFoo {
public function method() : int;
}$cb1 = function () implements IFoo : int {
return 42;
};$cb2 = new class implements IFoo {
function method() : int {
return 42;
}
};
?>Are $cb1 and $cb2 going to be the same (do the same)?
Is this just a new syntax sugar, or a really new feature?According to implementation, I think, you shouldn't extend "zend_closure"
with "interface".
If this is a sugar, lets implement it as a sugar (without VM changes).But may be I didn't understand the idea at all :)
Thanks. Dmitry.
From: Joe Watkins pthreads@pthreads.org
Sent: Monday, April 18, 2016 13:22
To: PHP internals
Subject: [PHP-DEV] RFC: Functional InterfacesMorning Internals,
Please review the following RFC: https://wiki.php.net/rfc/functional-interfaces An implementation is provided, and is testable on 3v4l. Review of the implementation from those of you that do that would be
good :)
Cheers
Joe
> Oh, it's confusing text in the RFC, using the word "Interface" ...
> that's meant as a placeholder for InterfaceName.
>
> Cheers
> Joe
>
> On Tue, Apr 19, 2016 at 1:50 PM, Joe Watkins
>
> Morning Dmitry,
>
> In your example, they will do the same thing.
>
> Anon classes don't have lexical scope, I have a patch for that,
> and an RFC, I'm just tidying it.
>
OK. so this is not just a syntax sugar, but if you implement lexical
scope for anonymous classes it's going to be sugar. Right?
May be it's better to start from classes first?
>
> Even when anon classes do have lexical scope, there is value in
> being able to implement these kinds of interfaces using only a
> function.
>
What value? just shorter syntax? or anything else?
>
> The changes to the vm are restricted to a few lines, that's not
> seriously a problem, is it !?
>
I hope no. I didn't understand all details of proposal and I didn't take
a deep look into the code.
>
> I don't see where I extend closure with an interface ...
>
I meant new field zend_execute_data *interface in zend_closure structure.
I thought the same might be implemented through anonymous classes.
Thanks. Dmitry.
>
> > zend_do_inheritance_ex(type, zend_ce_closure, 1);
> > zend_class_implements(type, 1, interface);
>
> Cheers
> Joe
>
> On Tue, Apr 19, 2016 at 1:01 PM, Dmitry Stogov
>
> <?php
> interface IFoo {
> public function method() : int;
> }
>
> $cb1 = function () implements IFoo : int {
> return 42;
> };
>
> $cb2 = new class implements IFoo {
> function method() : int {
> return 42;
> }
> };
> ?>
>
> Are $cb1 and $cb2 going to be the same (do the same)?
> Is this just a new syntax sugar, or a really new feature?
>
> According to implementation, I think, you shouldn't extend
> "zend_closure" with "interface".
> If this is a sugar, lets implement it as a sugar (without VM
> changes).
>
> But may be I didn't understand the idea at all :)
>
> Thanks. Dmitry.
>
>
> ________________________________________
> From: Joe Watkins
> Sent: Monday, April 18, 2016 13:22
> To: PHP internals
> Subject: [PHP-DEV] RFC: Functional Interfaces
>
> Morning Internals,
>
> Please review the following RFC:
>
> https://wiki.php.net/rfc/functional-interfaces
>
> An implementation is provided, and is testable on 3v4l.
>
> Review of the implementation from those of you that do
> that would be
> good :)
>
> Cheers
> Joe
What value?
Yes, shorter, more concise (from the programmers perspective) syntax.
Right now, if you do a lot of work with Closures, you have to verify their
interface, the value in having the engine do it for you seems really
obvious.
But also ...
I thought the same might be implemented through anonymous classes.
An anonymous class cannot be rebound, they are obviously not the same thing.
I didn't take a deep look into the code.
I'll wait until you have, I think :)
Cheers
Joe
Oh, it's confusing text in the RFC, using the word "Interface" ... that's
meant as a placeholder for InterfaceName.Cheers
JoeOn Tue, Apr 19, 2016 at 1:50 PM, Joe Watkins pthreads@pthreads.org
wrote:Morning Dmitry,
In your example, they will do the same thing.
Anon classes don't have lexical scope, I have a patch for that, and an
RFC, I'm just tidying it.OK. so this is not just a syntax sugar, but if you implement lexical scope
for anonymous classes it's going to be sugar. Right?
May be it's better to start from classes first?Even when anon classes do have lexical scope, there is value in being
able to implement these kinds of interfaces using only a function.What value? just shorter syntax? or anything else?
The changes to the vm are restricted to a few lines, that's not
seriously a problem, is it !?I hope no. I didn't understand all details of proposal and I didn't take a
deep look into the code.I don't see where I extend closure with an interface ...
I meant new field zend_execute_data *interface in zend_closure structure.
I thought the same might be implemented through anonymous classes.Thanks. Dmitry.
zend_do_inheritance_ex(type, zend_ce_closure, 1); zend_class_implements(type, 1, interface);
Cheers
JoeOn Tue, Apr 19, 2016 at 1:01 PM, Dmitry Stogov < dmitry@zend.com
dmitry@zend.com> wrote:<?php
interface IFoo {
public function method() : int;
}$cb1 = function () implements IFoo : int {
return 42;
};$cb2 = new class implements IFoo {
function method() : int {
return 42;
}
};
?>Are $cb1 and $cb2 going to be the same (do the same)?
Is this just a new syntax sugar, or a really new feature?According to implementation, I think, you shouldn't extend
"zend_closure" with "interface".
If this is a sugar, lets implement it as a sugar (without VM changes).But may be I didn't understand the idea at all :)
Thanks. Dmitry.
From: Joe Watkins pthreads@pthreads.org
Sent: Monday, April 18, 2016 13:22
To: PHP internals
Subject: [PHP-DEV] RFC: Functional InterfacesMorning Internals,
Please review the following RFC: https://wiki.php.net/rfc/functional-interfaces An implementation is provided, and is testable on 3v4l. Review of the implementation from those of you that do that would be
good :)
Cheers
Joe
I prefer intuitive concepts, that I may use without rereading manual
again and again.
For this one, I even can't imagine a natural (not over-designed) use case.
But this is my personal opinion, and I may be wrong :)
I'll review the code later.
Thanks. Dmitry.
> > What value?
>
> Yes, shorter, more concise (from the programmers perspective) syntax.
>
> Right now, if you do a lot of work with Closures, you have to verify
> their interface, the value in having the engine do it for you seems
> really obvious.
>
> But also ...
>
> > I thought the same might be implemented through anonymous classes.
>
> An anonymous class cannot be rebound, they are obviously not the same
> thing.
>
> > I didn't take a deep look into the code.
>
> I'll wait until you have, I think :)
>
> Cheers
> Joe
>
> On Tue, Apr 19, 2016 at 2:22 PM, Dmitry Stogov
>
>
>
>
>> Oh, it's confusing text in the RFC, using the word "Interface"
>> ... that's meant as a placeholder for InterfaceName.
>>
>> Cheers
>> Joe
>>
>> On Tue, Apr 19, 2016 at 1:50 PM, Joe Watkins
>>
>>
>> Morning Dmitry,
>>
>> In your example, they will do the same thing.
>>
>> Anon classes don't have lexical scope, I have a patch for
>> that, and an RFC, I'm just tidying it.
>>
>
> OK. so this is not just a syntax sugar, but if you implement
> lexical scope for anonymous classes it's going to be sugar. Right?
> May be it's better to start from classes first?
>
>>
>> Even when anon classes do have lexical scope, there is
>> value in being able to implement these kinds of interfaces
>> using only a function.
>>
>
> What value? just shorter syntax? or anything else?
>
>>
>> The changes to the vm are restricted to a few lines, that's
>> not seriously a problem, is it !?
>>
>
> I hope no. I didn't understand all details of proposal and I
> didn't take a deep look into the code.
>
>>
>> I don't see where I extend closure with an interface ...
>>
>
> I meant new field zend_execute_data *interface in zend_closure
> structure.
> I thought the same might be implemented through anonymous classes.
>
> Thanks. Dmitry.
>
>
>>
>> > zend_do_inheritance_ex(type, zend_ce_closure, 1);
>> > zend_class_implements(type, 1, interface);
>>
>> Cheers
>> Joe
>>
>> On Tue, Apr 19, 2016 at 1:01 PM, Dmitry Stogov
>>
>>
>> <?php
>> interface IFoo {
>> public function method() : int;
>> }
>>
>> $cb1 = function () implements IFoo : int {
>> return 42;
>> };
>>
>> $cb2 = new class implements IFoo {
>> function method() : int {
>> return 42;
>> }
>> };
>> ?>
>>
>> Are $cb1 and $cb2 going to be the same (do the same)?
>> Is this just a new syntax sugar, or a really new feature?
>>
>> According to implementation, I think, you shouldn't
>> extend "zend_closure" with "interface".
>> If this is a sugar, lets implement it as a sugar (without
>> VM changes).
>>
>> But may be I didn't understand the idea at all :)
>>
>> Thanks. Dmitry.
>>
>>
>> ________________________________________
>> From: Joe Watkins
>> Sent: Monday, April 18, 2016 13:22
>> To: PHP internals
>> Subject: [PHP-DEV] RFC: Functional Interfaces
>>
>> Morning Internals,
>>
>> Please review the following RFC:
>>
>> https://wiki.php.net/rfc/functional-interfaces
>>
>> An implementation is provided, and is testable on 3v4l.
>>
>> Review of the implementation from those of you that
>> do that would be
>> good :)
>>
>> Cheers
>> Joe
Dmitry Stogov wrote on 19/04/2016 15:12:
I prefer intuitive concepts, that I may use without rereading manual
again and again.
For this one, I even can't imagine a natural (not over-designed) use
case.
The use case that came to my mind is kind of the other way around from
"syntax sugar for anonymous classes" - providing a contract for what a
callback should look like. In essence, it's an alternative to specifying
closure type with a generic-like syntax, as proposed at
https://wiki.php.net/rfc/callable-types
Say you currently have this:
public function registerCallback(callable $callback) { ... }
You could instead specify what the callback needs to accept and return:
interface EventCallbackInterface {
public function __invoke(Event $event): boolean;
}
public function registerCallback(EventCallbackInterface $callback) { ... }
Using __invoke as the method name may or may not be a good idea, but it
interestingly means I don't need to change the code that runs the
callback, I can just use $callback($some_event); Then if someone wants
to use a complex object, they can; and if they just want to use a
closure, it has to meet the contract.
Regards,
Rowan Collins
[IMSoP]
Dmitry Stogov wrote on 19/04/2016 15:12:
I prefer intuitive concepts, that I may use without rereading manual
again and again.
For this one, I even can't imagine a natural (not over-designed) use
case.The use case that came to my mind is kind of the other way around from
"syntax sugar for anonymous classes" - providing a contract for what a
callback should look like. In essence, it's an alternative to
specifying closure type with a generic-like syntax, as proposed at
https://wiki.php.net/rfc/callable-typesSay you currently have this:
public function registerCallback(callable $callback) { ... }
You could instead specify what the callback needs to accept and return:
interface EventCallbackInterface {
public function __invoke(Event $event): boolean;
}
public function registerCallback(EventCallbackInterface $callback) {
... }Using __invoke as the method name may or may not be a good idea, but
it interestingly means I don't need to change the code that runs the
callback, I can just use $callback($some_event); Then if someone wants
to use a complex object, they can; and if they just want to use a
closure, it has to meet the contract.
callable-type is much simpler solution for this use-case.
Usage of Interfaces to check function prototypes is a bit tricky, but
yes, this is a possible use-case.
Do you like to work with framework, that use this trick for every callback?
Thanks. Dmitry.
Regards,
Dmitry Stogov wrote on 19/04/2016 15:48:
callable-type is much simpler solution for this use-case.
Usage of Interfaces to check function prototypes is a bit tricky, but
yes, this is a possible use-case.
Do you like to work with framework, that use this trick for every
callback?
If you don't use __invoke as the function name, you can have a single
class implement multiple contracts, e.g. to register for more than one
event type with different signatures.
I guess if you had callable-types and union types, you could get the
best of both worlds:
interface UserEventCallbackInterface {
public function handleUserEvent(UserEvent $event): boolean;
}
public function registerCallback(EventCallbackInterface|callable(Event):
boolean $handler) { ... }
The implementation has to be a bit fiddlier here, because you need to
sometimes call $handler->handleUserEvent($event) and sometimes
$handler($event); with a functional interface, the engine makes
$handler->handleUserEvent($event) work for you. The cost is that the
call site has to be a bit more verbose to specify the interface, rather
than implicitly meeting the contract.
Regards,
Rowan Collins
[IMSoP]
Dmitry Stogov wrote on 19/04/2016 15:48:
callable-type is much simpler solution for this use-case.
Usage of Interfaces to check function prototypes is a bit tricky, but
yes, this is a possible use-case.
Do you like to work with framework, that use this trick for every
callback?If you don't use __invoke as the function name, you can have a single
class implement multiple contracts, e.g. to register for more than one
event type with different signatures.I guess if you had callable-types and union types, you could get the
best of both worlds:interface UserEventCallbackInterface {
public function handleUserEvent(UserEvent $event): boolean;
}
public function
registerCallback(EventCallbackInterface|callable(Event): boolean
$handler) { ... }The implementation has to be a bit fiddlier here, because you need to
sometimes call $handler->handleUserEvent($event) and sometimes
$handler($event); with a functional interface, the engine makes
$handler->handleUserEvent($event) work for you. The cost is that the
call site has to be a bit more verbose to specify the interface,
rather than implicitly meeting the contract.Regards,
Which is why I'm not sure I like that approach, because the place I then
call $handler needs to have a conditional in it. There's another RFC
that was posted to Twitter but hasn't made it to the list yet that seems
to solve this better:
https://wiki.php.net/rfc/callable-types
(My apologies to the authors if they aren't done with it; it's on the
wiki so I'm assuming it's safe to mention in public.)
That allows just the callable-type syntax (which I presume is what
you're referencing), but you can then pass an object in using
[]-callable syntax: [$handler. 'handleUserEvent'], and then
registerCallback() doesn't care if it was a function, method, closure,
or whatever else. It can just () it.
--
--Larry Garfield
Hi!
2016-04-19 11:21 GMT-04:00 Larry Garfield larry@garfieldtech.com:
Dmitry Stogov wrote on 19/04/2016 15:48:
callable-type is much simpler solution for this use-case.
Usage of Interfaces to check function prototypes is a bit tricky, but
yes, this is a possible use-case.
Do you like to work with framework, that use this trick for every
callback?If you don't use __invoke as the function name, you can have a single
class implement multiple contracts, e.g. to register for more than one
event type with different signatures.I guess if you had callable-types and union types, you could get the
best of both worlds:interface UserEventCallbackInterface {
public function handleUserEvent(UserEvent $event): boolean;
}
public function registerCallback(EventCallbackInterface|callable(Event):
boolean $handler) { ... }The implementation has to be a bit fiddlier here, because you need to
sometimes call $handler->handleUserEvent($event) and sometimes
$handler($event); with a functional interface, the engine makes
$handler->handleUserEvent($event) work for you. The cost is that the call
site has to be a bit more verbose to specify the interface, rather than
implicitly meeting the contract.
I believe Joe has both $handler->handleUserEvent($event) and
$handler($event) cases covered already. This means that
$handler->handleUserEvent($event), $handler() and $handler->__invoke($event)
should be 100% equivalent.
Regards,
Which is why I'm not sure I like that approach, because the place I then
call $handler needs to have a conditional in it. There's another RFC that
was posted to Twitter but hasn't made it to the list yet that seems to
solve this better:https://wiki.php.net/rfc/callable-types
(My apologies to the authors if they aren't done with it; it's on the wiki
so I'm assuming it's safe to mention in public.)
Yes, it it's ok to mention the RFC. We are going to move it to discussion
phase ASAP some minor issues get a fix :)
That allows just the callable-type syntax (which I presume is what you're
referencing), but you can then pass an object in using []-callable syntax:
[$handler. 'handleUserEvent'], and then registerCallback() doesn't care if
it was a function, method, closure, or whatever else. It can just () it.--
--Larry Garfield
Larry Garfield wrote on 19/04/2016 16:21:
Which is why I'm not sure I like that approach, because the place I
then call $handler needs to have a conditional in it. There's another
RFC that was posted to Twitter but hasn't made it to the list yet that
seems to solve this better:
I'm not sure which approach you mean, but in Joe's proposal, you always
call $handler as though it was an object implementing the interface;
have a look at the ILog example in the RFC.
With a typed callable, you can always invoke as $handler(...) will work,
but the implementer can't create an object that meets more than one
contract, because they can only provide one __invoke method.
interface UserEventCallbackInterface {
public function handleUserEvent(UserEvent $event): boolean;
}
interface CommentEventCallbackInterface {
public function handleCommentEvent(CommentEvent $event): boolean;
}
class Logger implements UserEventCallbackInterface,
CommentEventCallbackInterface { ... }
$logger = new Logger;
$simple_user_handler = function(UserEvent $event) implements
UserEventCallbackInterface: boolean { ... }
In Joe's proposal, $logger and $simple_user_handler can be used
interchangeably by calling $handler->handleUserEvent(...); the receiving
code doesn't need to do anything special to accept the closure form,
because the engine transforms it into the required object.
Regards,
Rowan Collins
[IMSoP]