rfc:closurefromcallable
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:closurefromcallable [2015/09/28 15:54] – clarified error thrown danack | rfc:closurefromcallable [2017/09/22 13:28] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Closure from callable function ====== | ====== PHP RFC: Closure from callable function ====== | ||
- | * Version: | + | * Version: |
- | * Date: 2015-09-28 | + | * Date: 2016-04-23 |
* Author: Dan Ackroyd, Danack@php.net | * Author: Dan Ackroyd, Danack@php.net | ||
- | * Status: | + | * Status: |
* First Published at: https:// | * First Published at: https:// | ||
Line 11: | Line 11: | ||
PHP lacks a simple function to convert callables into a closure directly. Although it is possible to do this in userland, it is slow compared to what is possible with a built-in function, due to the number of reflection functions needed to be called, as well needing to create intermediary reflection objects. | PHP lacks a simple function to convert callables into a closure directly. Although it is possible to do this in userland, it is slow compared to what is possible with a built-in function, due to the number of reflection functions needed to be called, as well needing to create intermediary reflection objects. | ||
- | This RFC proposes adding the function `closure` to PHP's Reflection extension, to allow people to convert | + | This RFC proposes adding |
<code php> | <code php> | ||
- | function | + | class Closure { |
+ | ... | ||
+ | public static | ||
+ | ... | ||
+ | } | ||
</ | </ | ||
Line 24: | Line 28: | ||
There are three uses for converting callables into closures: | There are three uses for converting callables into closures: | ||
- | * Better API control for classes | + | |
- | * Easier error detection and static analysis | + | |
- | * Performance | + | |
Line 47: | Line 51: | ||
} | } | ||
| | ||
- | public function emailValidation() {...} | + | public function emailValidation($userData) {...} |
| | ||
- | public function genericValidation() {...} | + | public function genericValidation($userData) {...} |
} | } | ||
$validator = new Validator(); | $validator = new Validator(); | ||
- | $callback = $validator-> | + | $callback = $validator-> |
$callback($userData); | $callback($userData); | ||
</ | </ | ||
- | With the closure() function, the class can easily return a closure that closes over private functions, which means those functions are no longer part of the public API. | + | With the Closure:: |
<code php> | <code php> | ||
Line 65: | Line 69: | ||
| | ||
if ($validationType == ' | if ($validationType == ' | ||
- | return | + | return |
} | } | ||
| | ||
- | return | + | return |
} | } | ||
- | | + | |
- | private function emailValidation() {...} | + | private function emailValidation($userData) {...} |
- | + | ||
- | private function genericValidation() {...} | + | private function genericValidation($userData) {...} |
} | } | ||
$validator = new Validator(); | $validator = new Validator(); | ||
- | $callback = $validator-> | + | $callback = $validator-> |
$callback($userData); | $callback($userData); | ||
Line 107: | Line 111: | ||
function getCallback() { | function getCallback() { | ||
- | return | + | return |
} | } | ||
Line 121: | Line 125: | ||
==== Performance gain ==== | ==== Performance gain ==== | ||
- | Although PHP has a ' | + | Although PHP has a ' |
- | + | ||
- | + | ||
Below are two files that call a function 10,000 times which calls itself recursively 8 times. One version has a callable type for the parameter, the other has Closure as the type. Measuring the number of operations with | Below are two files that call a function 10,000 times which calls itself recursively 8 times. One version has a callable type for the parameter, the other has Closure as the type. Measuring the number of operations with | ||
Line 132: | Line 135: | ||
^ ^ Operations | ^ ^ Operations | ||
- | | Callable | 112,311,913 | | + | | Callable | 114,465,014 | |
| Closure | 95,522,330 | | | Closure | 95,522,330 | | ||
- | | Difference | 16,789,583 | | + | | Difference | 18,942,684 | |
- | Which is a difference of over 1000 operations per loop. | + | Which is saving 16% of the operations, or a difference of 1,894 operations per loop or about 230 operations per function call where the callable is passed.. |
==== Patches and Tests ==== | ==== Patches and Tests ==== | ||
- | The function has been implemented in this branch: https:// | + | The function has been implemented in this PR: https:// |
==== Proposed Voting Choices ==== | ==== Proposed Voting Choices ==== | ||
- | As this is a simple function addition with no langauages | + | As this is a simple function addition with no language |
+ | |||
+ | |||
+ | Voting will close at 9pm UTC on the 29th of May 2016. | ||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
- | ==== Why a function? ==== | + | ==== Why the long name? ==== |
- | Some people have asked why a function | + | Although I would prefer to implement this as a short function e.g. |
- | + | ||
- | e.g. in cases where the same function is turned into a closure twice: | + | |
<code php> | <code php> | ||
- | $fn1 = closure(' | + | function fn(callable |
- | $fn2 = closure(' | + | |
</ | </ | ||
- | with the implementation being a function it is perfectly acceptable for $fn1 and $fn2 to be the same object. If instead the implementation was as a constructor for the closure class: | + | there are downsides that make that be a poor choice. |
- | <code php> | + | It clutters up the root namespace, which in general is bad practice. Making the implementation be a static method of the Closure class avoids this problem, as well as avoid clashing with future needs. For example Hack has specific separate implementations for converting strings, instance methods to closures. We may wish to add these in the future. Using a static method with a descriptive name avoids clashing with those names in the future. |
- | $fn1 = new closure(' | + | |
- | $fn2 = new closure(' | + | |
- | </ | + | |
- | Having two new statements return the same object is very high on the surprise factor. | + | If anyone wants to use a short name for this functionality in their application or library they can do so easily, by defining a function: |
- | Additionally having it be just a function, would make it easier in the future to implement it as a language construct, which might be desired for performance reasons. | + | <code php> |
- | + | | |
- | If you think that this should be implemented as the constructor of Closure | + | |
+ | } | ||
+ | </ | ||
Line 177: | Line 183: | ||
Hack has a similar functionality, | Hack has a similar functionality, | ||
- | * Strings which should be a function: | + | |
- | * Instance and method name: http:// | + | * Instance and method name: http:// |
- | * Class name and method name: http:// | + | * Class name and method name: http:// |
They have included these to allow programs to be easier to reason about, and allows their type-checker to statically analyze the hack programs. | They have included these to allow programs to be easier to reason about, and allows their type-checker to statically analyze the hack programs. | ||
Line 185: | Line 191: | ||
However this RFC takes the position that it is inappropriate to have a separate function per type. Instead having a single function that takes any callable parameter is more powerful, and easier for users to use. | However this RFC takes the position that it is inappropriate to have a separate function per type. Instead having a single function that takes any callable parameter is more powerful, and easier for users to use. | ||
+ | ===== Implementation ===== | ||
+ | |||
+ | Merged into php-src for PHP 7.1: https:// | ||
+ | |||
+ | After the project is implemented, | ||
+ | - a link to the PHP manual entry for the feature | ||
+ | |||
===== Appendix ===== | ===== Appendix ===== | ||
Line 243: | Line 256: | ||
function getCallable($foo) : Closure | function getCallable($foo) : Closure | ||
{ | { | ||
- | return | + | return |
} | } | ||
Line 257: | Line 270: | ||
</ | </ | ||
- | |||
- | |||
rfc/closurefromcallable.1443455646.txt.gz · Last modified: 2017/09/22 13:28 (external edit)