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
Next revisionBoth sides next revision
rfc:callable-interfaces [2016/04/06 11:27] ocramiusrfc:callable-interfaces [2016/04/06 12:00] ocramius
Line 15: Line 15:
 ===== Proposal ===== ===== Proposal =====
  
-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**.+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**.
  
-**_**_****invoke** already works quite well: with this proposal, generic *callable* arrays, functions and objects will be usable as if they implemented a matching interface:+**_****_****invoke** already works quite well: with this proposal, generic *callable* arrays, 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;
 } }
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 90: Line 87:
  
 In order for this to work, any implicitly defined callable should be cast to a *Closure* 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>
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
rfc/callable-interfaces.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1