rfc:callable-types
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:callable-types [2016/04/23 12:33] – nikita2206 | rfc:callable-types [2017/09/22 13:28] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== PHP RFC: Callable | + | ====== PHP RFC: Callable |
* Version: 1.0 | * Version: 1.0 | ||
* Date: 2015-08-27 | * Date: 2015-08-27 | ||
* Authors: Nikita Nefedov < | * Authors: Nikita Nefedov < | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
Line 43: | Line 43: | ||
}); | }); | ||
// >>> | // >>> | ||
- | // TypeError: Argument 3 passed to reduce() must be callable(int, | + | // TypeError: Argument 3 passed to reduce() must be compliant with callable(int, |
</ | </ | ||
Line 174: | Line 174: | ||
foo(function (A $a) {}); // there' | foo(function (A $a) {}); // there' | ||
- | foo(function (B $b) {}); // Uncaught TypeError: Argument 1 passed to foo() must be callable of compliant | + | foo(function (B $b) {}); // Uncaught TypeError: Argument 1 passed to foo() must be compliant |
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 | ||
</ | </ | ||
Line 195: | Line 195: | ||
</ | </ | ||
- | Optional | + | Optional |
<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 | ||
</ | </ | ||
+ | |||
+ | 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 | ||
+ | </ | ||
+ | The same goes for variadics as they are a special kind of optional parameters. | ||
When callable type is nested (when you have '' | When callable type is nested (when you have '' | ||
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 | + | foo(function ($bar) { }); // TypeError: Argument 1 passed to foo() must be compliant |
function bar(callable($byval) $cb) { } | function bar(callable($byval) $cb) { } | ||
- | bar(function (&$bar) { }); // TypeError: Argument 1 passed to bar() must be callable of compliant | + | bar(function (&$bar) { }); // TypeError: Argument 1 passed to bar() must be compliant |
</ | </ | ||
- | Functions returning a reference are not different from functions returning a value in PHP, for the caller, hence both are interchangeable: | + | Functions returning a reference are compatible with functions returning a value for caller, hence both are interchangeable: |
<code php> | <code php> | ||
function foo(callable(): | function foo(callable(): | ||
Line 231: | Line 238: | ||
foo(function &(): A { static $a; $a = $a ?: new A; return $a; }); // both would pass the boundaries of a type check | foo(function &(): A { static $a; $a = $a ?: new A; return $a; }); // both would pass the boundaries of a type check | ||
</ | </ | ||
+ | |||
+ | There' | ||
+ | |||
+ | ==== Parameters with default values ==== | ||
+ | |||
+ | It's not possible to declare default value of a parameter in a callable prototype. Because currently PHP doesn' | ||
==== Syntax Choices ==== | ==== Syntax Choices ==== | ||
Line 322: | Line 335: | ||
function foo(callable($a, | function foo(callable($a, | ||
//... | //... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Reflection ===== | ||
+ | |||
+ | There are no BC-breaking changes in Reflection. | ||
+ | |||
+ | Here are the changes needed for reflection: | ||
+ | |||
+ | `ReflectionParameter:: | ||
+ | |||
+ | <code php> | ||
+ | class ReflectionCallableType extends ReflectionType | ||
+ | { | ||
+ | /** | ||
+ | * Tells whether it's just a `callable` hint or if it has a prototype `callable(something): | ||
+ | */ | ||
+ | public function hasPrototype(): | ||
+ | |||
+ | /** | ||
+ | * Returns a number of parameters required by a callable prototype | ||
+ | */ | ||
+ | public function getArity(): bool; | ||
+ | |||
+ | /** | ||
+ | * Returns an array of ReflectionCallableParameter instances | ||
+ | */ | ||
+ | public function getParameters(): | ||
+ | |||
+ | /** | ||
+ | * Tells whether the prototype has return type defined | ||
+ | */ | ||
+ | public function hasReturnType(): | ||
+ | |||
+ | /** | ||
+ | * Returns return type of the callable prototype | ||
+ | */ | ||
+ | public function getReturnType(): | ||
+ | |||
+ | /** | ||
+ | * 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(): | ||
+ | | ||
+ | /** | ||
+ | * Whether this is a variadic parameter | ||
+ | */ | ||
+ | public function isVariadic(): | ||
} | } | ||
</ | </ | ||
Line 376: | 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=" |
+ | * Yes | ||
+ | * No | ||
+ | </doodle> | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 414: | Line 506: | ||
- Scala | - Scala | ||
- Swift https:// | - Swift https:// | ||
- |
rfc/callable-types.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1