rfc:closurefromcallable
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:closurefromcallable [2015/09/28 14:44] – created danack | rfc:closurefromcallable [2016/05/15 17:16] – updated to latest PR danack | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Closure from callable function ====== | ====== PHP RFC: Closure from callable function ====== | ||
- | * Version: 0.9 | + | * Version: 0.95 |
- | * 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 | ||
+ | ... | ||
+ | } | ||
</ | </ | ||
- | The function will check whether the callable is actually callable in the current scope, and will only return a closure if it is callable | + | The function will check whether the callable is actually callable in the current scope. It will return a closure if it is callable, otherwise throw a TypeError. For example trying to create a closure to a private method of an object from the global scope would fail. Trying to create a closure to a private method of an object from within the object would succeed. |
==== Why would you use this? ==== | ==== Why would you use this? ==== | ||
- | There are three uses for converting callables into Clousures: | + | 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 == ' | ||
- | | + | |
} | } | ||
| | ||
- | | + | |
} | } | ||
- | | + | |
- | 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 98: | Line 102: | ||
// more code here. | // more code here. | ||
//... | //... | ||
- | $callback(); | + | $callback(); |
</ | </ | ||
Line 107: | Line 111: | ||
function getCallback() { | function getCallback() { | ||
- | return | + | return |
} | } | ||
Line 122: | Line 126: | ||
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 130: | Line 133: | ||
| | ||
gives the number of operations to be: | gives the number of operations to be: | ||
- | |||
- | Callable: 112,311,913 | ||
- | Closure: | ||
- | | ||
- | Difference: | ||
- | Which is a difference of over 1000 operations per loop. | + | ^ ^ Operations |
+ | | Callable | 114,465,014 | | ||
+ | | Closure | 95,522,330 | | ||
+ | | Difference | 18,942,684 | | ||
+ | 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 |
- | ==== 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 | + | there are downsides that make that be a poor choice. |
+ | |||
+ | It clutters up the root namespace, which in general is bad practice. Making | ||
+ | |||
+ | 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: | ||
<code php> | <code php> | ||
- | $fn1 = new closure(' | + | function fn(callable $callable) : Closure { |
- | $fn2 = new closure(' | + | |
+ | } | ||
</ | </ | ||
- | |||
- | Having two new statements return the same object is very high on the surprise factor. | ||
- | |||
- | 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. | ||
- | |||
- | If you think that this should be implemented as the constructor of Closure rather than a function, please can you articulate the reason for that, other than ' | ||
Line 178: | Line 176: | ||
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 186: | Line 184: | ||
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. | ||
- | ## Appendix | + | ===== Appendix |
- | ### Code for performance test. | + | ==== Code for performance test ==== |
<code php> | <code php> | ||
Line 244: | Line 242: | ||
function getCallable($foo) : Closure | function getCallable($foo) : Closure | ||
{ | { | ||
- | return | + | return |
} | } | ||
Line 258: | Line 256: | ||
</ | </ | ||
- | |||
- | |||
rfc/closurefromcallable.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1