rfc:callable-types

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-types [2016/04/26 12:12] – return reference nikita2206rfc:callable-types [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
-====== PHP RFC: Callable Types ======+====== PHP RFC: Callable Prototypes ======
   * Version: 1.0   * Version: 1.0
   * Date: 2015-08-27   * Date: 2015-08-27
   * Authors: Nikita Nefedov <inefedor@gmail.com>, Márcio Almada <marcio3w@gmail.com>   * Authors: Nikita Nefedov <inefedor@gmail.com>, Márcio Almada <marcio3w@gmail.com>
-  * Status: Under Discussion+  * Status: Declined
   * First Published at: http://wiki.php.net/rfc/callable-types   * First Published at: http://wiki.php.net/rfc/callable-types
  
Line 43: Line 43:
 }); });
 // >>> // >>>
-// TypeError: Argument 3 passed to reduce() must be callable(int, int):int, callable($a, $b, $c) given...+// TypeError: Argument 3 passed to reduce() must be compliant with callable(int, int):int, incompatible callable($a, $b, $c) given...
 </code> </code>
  
Line 174: Line 174:
  
 foo(function (A $a) {}); // there's no variance in this case, A can be substituted by A foo(function (A $a) {}); // there's no variance in this case, A can be substituted by A
-foo(function (B $b) {}); // Uncaught TypeError: Argument 1 passed to foo() must be callable of compliant signature: callable(A), callable(B $b) given+foo(function (B $b) {}); // Uncaught TypeError: Argument 1 passed to foo() must be compliant with callable(A), incompatible callable(B $b) given
 bar(function (A $a) {}); // callable(A) > callable(B) - we can substitute callable(B) with callable(A) because the latter has a wider input than the latter bar(function (A $a) {}); // callable(A) > callable(B) - we can substitute callable(B) with callable(A) because the latter has a wider input than the latter
 </code> </code>
Line 195: Line 195:
 </code> </code>
  
-Optional arguments count just like any other arguments:+Optional parameters count just like any other parameters if they are typed:
 <code php> <code php>
 function foo(callable() $cb) { } function foo(callable() $cb) { }
Line 205: Line 205:
 // And callable(A $a) < callable(), so the call to foo() will fail here // And callable(A $a) < callable(), so the call to foo() will fail here
 </code> </code>
 +
 +Otherwise they can pass type check boundaries even if they are not defined in the callable type:
 +<code php>
 +function foo(callable() $cb) { }
 +foo(function ($a = 123) { }); // valid as it won't have a problem explained above
 +</code>
 +The same goes for variadics as they are a special kind of optional parameters.
  
 When callable type is nested (when you have ''callable(callable(A))'') variance has to be inversed with each nesting level. So if we have ''callable(A) > callable(B)'' then ''callable(callable(A)) < callable(callable(B))''. When callable type is nested (when you have ''callable(callable(A))'') variance has to be inversed with each nesting level. So if we have ''callable(A) > callable(B)'' then ''callable(callable(A)) < callable(callable(B))''.
Line 217: Line 224:
  
 foo(function (&$bar) { }); // valid foo(function (&$bar) { }); // valid
-foo(function ($bar) { }); // TypeError: Argument 1 passed to foo() must be callable of compliant signature: callable(&$byref), callable($bar) given+foo(function ($bar) { }); // TypeError: Argument 1 passed to foo() must be compliant with callable(&$byref), incompatible callable($bar) given
  
 function bar(callable($byval) $cb) { } function bar(callable($byval) $cb) { }
  
-bar(function (&$bar) { }); // TypeError: Argument 1 passed to bar() must be callable of compliant signature: callable($byval), callable(&$bar) given+bar(function (&$bar) { }); // TypeError: Argument 1 passed to bar() must be compliant with callable($byval), incompatible callable(&$bar) given
 </code> </code>
  
Line 232: Line 239:
 </code> </code>
  
-There's no way to declare that you expect a callable that returns reference due to syntax problems.+There's no way to declare that you expect a callable that returns reference due to syntax limitations. 
 + 
 +==== Parameters with default values ==== 
 + 
 +It's not possible to declare default value of a parameter in a callable prototype. Because currently PHP doesn't consider parameter's default values in signature validation (their invariance is not enforced in overridden methods in classes).
  
 ==== Syntax Choices ==== ==== Syntax Choices ====
Line 324: Line 335:
 function foo(callable($a, $b):void $callback) { function foo(callable($a, $b):void $callback) {
   //...   //...
 +}
 +</code>
 +
 +===== Reflection =====
 +
 +There are no BC-breaking changes in Reflection.
 +
 +Here are the changes needed for reflection:
 +
 +`ReflectionParameter::getType()` can now return instance of `ReflectionCallableType` which extends `ReflectionType`:
 +
 +<code php>
 +class ReflectionCallableType extends ReflectionType
 +{
 +    /**
 +     * Tells whether it's just a `callable` hint or if it has a prototype `callable(something): something`
 +     */
 +    public function hasPrototype(): bool;
 +
 +    /**
 +     * Returns a number of parameters required by a callable prototype
 +     */
 +    public function getArity(): bool;
 +
 +    /**
 +     * Returns an array of ReflectionCallableParameter instances
 +     */
 +    public function getParameters(): array;
 +
 +    /**
 +     * Tells whether the prototype has return type defined
 +     */
 +    public function hasReturnType(): bool;
 +
 +    /**
 +     * Returns return type of the callable prototype
 +     */
 +    public function getReturnType(): ReflectionType;
 +
 +    /**
 +     * Tells whether $value has compatible callable prototype. This is the easiest way
 +     * to implement runtime-error-free compatibility checks at this point...
 +     * Later we could implement it in the form of `instanceof`
 +     */
 +    public function isA($value);
 +}
 +
 +class ReflectionCallableParameter
 +{
 +    /**
 +     * Tells whether this callable parameter has a type
 +     */
 +    public function hasType(): bool;
 +
 +    /**
 +     * Returns a type of this callable parameter
 +     */
 +    public function getType(): ReflectionType;
 +
 +    /**
 +     * Tells whether callable parameter is named or not (e.g. callable(Foo $foo) vs callable(Foo))
 +     */
 +    public function hasName(): bool;
 +
 +    /**
 +     * Returns name of the callable parameter
 +     */
 +    public function getName(): string;
 +
 +    /**
 +     * Whether this is by-val or by-ref parameter
 +     */
 +    public function isPassedByReference(): bool;
 +    
 +    /**
 +     * Whether this is a variadic parameter
 +     */
 +    public function isVariadic(): bool;
 } }
 </code> </code>
Line 378: Line 467:
 while PHP lacks first class packages. while PHP lacks first class packages.
  
-==== Reflection API ====+===== Votes =====
  
-An extension to the reflection API will be proposed in case the RFC is approved. +This RFC requires a 2/3 majority to pass. Vote started on May 23, 2016, ends June 6, 2016.
- +
-===== Votes =====+
  
-This RFC requires a 2/3 majority to pass.+<doodle title="Accept callable prototypes?" auth="nikita2206" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle>
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
Line 416: Line 506:
     - Scala     - Scala
     - Swift https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html     - Swift https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html
- 
rfc/callable-types.1461672724.txt.gz · Last modified: 2017/09/22 13:28 (external edit)