rfc:callable-interfaces

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:callable-interfaces [2016/04/06 11:20] ocramiusrfc:callable-interfaces [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 4: Line 4:
   * Author: Ben Scholzen, mail@dasprids.de   * Author: Ben Scholzen, mail@dasprids.de
   * Author: Marco Pivetta, ocramius@gmail.com   * Author: Marco Pivetta, ocramius@gmail.com
-  * Status: Draft+  * Status: Retired
   * First Published at: http://wiki.php.net/rfc/callable-interfaces   * First Published at: http://wiki.php.net/rfc/callable-interfaces
  
Line 15: Line 15:
 ===== Proposal ===== ===== Proposal =====
  
-PHP already has a way to define objects that act as functions. That mechanism is the <code>__invoke</code> magic method, which is widely used in libraries and frameworks. In addition to that, <code>Closure</code> already implements <code>__invoke</code>.+PHP already has a way to define objects that act as functions. That mechanism is the **_****_invoke** magic method, which is widely used in libraries and frameworks. In addition to that, **Closure** already implements **_****_****invoke**.
  
-<code>__invoke</code> already works quite well: with this proposal, generic <code>callable</code> arrays, functions and objects will be usable as if they implemented a matching interface:+**_****_****invoke** already works quite well: with this proposal, generic *callablearrays, functions and objects will be usable as if they implemented a matching interface:
  
 <code php> <code php>
-interface RegisterUser +interface RegisterUser {
-{+
     public function __invoke(Username $username) : UserRegistration;     public function __invoke(Username $username) : UserRegistration;
 } }
 </code> </code>
  
-We can now implicitly implement this interface by just defining any <code>callable</code> that matches this interface:+We can now implicitly implement this interface by just defining any *callablethat matches this interface:
  
  
Line 52: Line 51:
  
 <code php> <code php>
-class Register +class Register {
-{+
     public static function register(Username $username) : UserRegistration {     public static function register(Username $username) : UserRegistration {
         // ... domain logic here ...         // ... domain logic here ...
Line 67: Line 65:
  
 <code php> <code php>
-class Register +class Register {
-{+
     public function register(Username $username) : UserRegistration {     public function register(Username $username) : UserRegistration {
         // ... domain logic here ...         // ... domain logic here ...
Line 89: Line 86:
 </code> </code>
  
-In order for this to work, any implicitly defined callable should be cast to a <code>Closure</code> at call-time.+In order for this to work, any implicitly defined callable should be cast to a *Closure* at call-time. 
 + 
 +In pseudo-code, this would look like following, under the hood: 
 + 
 +<code php> 
 +function passAParameterToAPhpFunction(callable $callable, $expectedParameterInterface) { 
 +    if (! $expectedParameterInterface->isCallableInterface()) { 
 +        passParameter($callable); 
 +         
 +        return; 
 +    } 
 +     
 +    if (! $expectedParameterInterface->matches($callable)) { 
 +         throw new TypeError('Expected X, got Y'); 
 +    } 
 +     
 +    if (! is_object($callable)) { 
 +        $callable = wrapInCompatibleAnonymousClass($callable); 
 +    } 
 +     
 +    passParameter($callable); 
 +
 +</code> 
 + 
 +===== Still Open for Discussion ===== 
 + 
 +How will **instanceof** behave, when asked for a type-check against **callable**? 
 + 
 +<code php> 
 +interface RegisterUser { 
 +    public function __invoke(Username $username) : UserRegistration; 
 +
 + 
 +interface DeleteUserRegistration { 
 +    public function __invoke(Username $username) : UserRegistration; 
 +
 + 
 +$register = function (Username $username) : UserRegistration { 
 +    return new UserRegistration(...); 
 +}; 
 + 
 +var_dump($register instanceof DeleteUserRegistration); // true? false? possibly want to keep current semantics here. 
 +</code> 
 + 
 +===== Retired ===== 
 + 
 +This RFC has been retired. Reason for that is that PHP currently (Version 7.0~7.1) allows applying function semantics to objects via the **_****_invoke** magic methods. Allowing the opposite would mix the domain of functions and objects in ways that are very hard to disentangle, and it would needlessly complicate the language semantics. 
 + 
 +While it is unfortunate that migration to type-safe callables (https://wiki.php.net/rfc/typesafe-callable) would require some interface rewrites, that is indeed the correct solution, as it keeps the uni-directionality between object and function semantics.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
rfc/callable-interfaces.1459941633.txt.gz · Last modified: 2017/09/22 13:28 (external edit)