rfc:pipe-operator
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:pipe-operator [2016/05/12 18:26] – Add twitter poll results. pollita | rfc:pipe-operator [2017/09/06 02:36] – Small typo fix haskellcamargo | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Pipe Operator ====== | ====== PHP RFC: Pipe Operator ====== | ||
- | * Version: 0.1 | + | * Version: 0.2 |
* Date: 2016-04-29 | * Date: 2016-04-29 | ||
* Author: Sara Golemon < | * Author: Sara Golemon < | ||
Line 8: | Line 8: | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | Complex nested expressions can become progressively difficult to read the deeper they go with function returns leading | + | A common PHP OOP pattern is the use of method chaining, or what is also known as " |
+ | |||
+ | For example, the following shows a SQL query expression built out of component pieces, then executed: | ||
+ | |||
+ | $rs = $db | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | |||
+ | This works well enough for OOP classes | ||
+ | |||
+ | While decomposing these expressions to make use of multiple variables is an option, this can lead to reduced readability, | ||
+ | |||
+ | $config = loadConfig(); | ||
+ | $dic = buildDic($config); | ||
+ | $app = getApp($dic); | ||
+ | $router = getRouter($app); | ||
+ | $dispatcher = getDispatcher($router, | ||
+ | $logic = dispatchBusinessLogic($dispatcher, | ||
+ | $render = renderResponse($logic); | ||
+ | $psr7 = buildPsr7Response($render); | ||
+ | $response =emit($psr7); | ||
+ | |||
+ | Or: | ||
+ | |||
+ | $x = loadConfig(); | ||
+ | $x = buildDic($x); | ||
+ | $x = getApp($x); | ||
+ | $x = getRouter($x); | ||
+ | $x = getDispatcher($x, | ||
+ | $x = dispatchBusinessLogic($x, | ||
+ | $x = renderResponse($x); | ||
+ | $x = buildPsr7Response($x); | ||
+ | $response =emit($x); | ||
+ | |||
+ | These sorts of chains could also, conceivably, | ||
+ | |||
+ | $dispatcher = getDispatcher(getRouter(getApp(buildDic(loadConfig()))), | ||
+ | $response = emit(buildPsr7Response(renderResponse(dispatchBusinessLogic($dispatcher, | ||
+ | |||
+ | This RFC aims to improve code readability by bringing fluent | ||
===== Proposal ===== | ===== Proposal ===== | ||
- | Introduce the "Pipe Operator" | + | Introduce the "Pipe Operator" |
This feature is being culled from HackLang 3.13 and the manual page for it may be referenced at: https:// | This feature is being culled from HackLang 3.13 and the manual page for it may be referenced at: https:// | ||
Line 18: | Line 60: | ||
==== PSR7 Example ==== | ==== PSR7 Example ==== | ||
- | Here's the pseudo-code for a typical request/ | + | Here's the equivalent chain of function calls as demonstrated in the intro section above: |
- | + | ||
- | $request = getGlobals() | + | |
- | |> parseRequest($$) | + | |
- | |> buildPsr7Request($$); | + | |
$response = loadConfig() | $response = loadConfig() | ||
Line 32: | Line 70: | ||
|> renderResponse($$) | |> renderResponse($$) | ||
|> buildPsr7Response($$) | |> buildPsr7Response($$) | ||
- | |> emit($$); | ||
- | |||
- | Here's what it would look like with a separate approach (more business-oriented): | ||
- | |||
- | buildRequest() // (basically the first part of the previous example here) | ||
- | |> validate($$) | ||
- | |> convertToCommand($$) | ||
- | |> execute($$) | ||
- | |> convertToViewModel($$) | ||
- | |> render($$) | ||
- | |> convertToHttpResponse($$) | ||
|> emit($$); | |> emit($$); | ||
==== File collection Example ==== | ==== File collection Example ==== | ||
- | As an example, consider the following real block of code I wrote while creating a test importer (to migrate HHVM format tests into PHPT format): | + | As an example, consider the following real block of code I wrote while creating a test importer (to migrate HHVM format tests into PHPT format). Please try not to get hung up into whether or not it's " |
$ret = | $ret = | ||
Line 75: | Line 102: | ||
This clearly, and unambiguously shows `scandir()` as the initial source of data, that it goes through an `array_filter` to avoid recursion, an `array_map` to requalify the paths, some local function, and finally a merge to combine the result with a collector variable. | This clearly, and unambiguously shows `scandir()` as the initial source of data, that it goes through an `array_filter` to avoid recursion, an `array_map` to requalify the paths, some local function, and finally a merge to combine the result with a collector variable. | ||
+ | |||
+ | ==== FBShipIt Example ==== | ||
+ | |||
+ | Also consider [[https:// | ||
+ | |||
+ | return $changeset | ||
+ | |> self:: | ||
+ | |> self:: | ||
+ | $$, | ||
+ | $config[' | ||
+ | ) | ||
+ | |> self:: | ||
+ | |> self:: | ||
+ | |> self:: | ||
+ | |> self:: | ||
+ | |> ShipItUserFilters:: | ||
+ | $$, | ||
+ | FBToGitHubUserInfo:: | ||
+ | ) | ||
+ | |> self:: | ||
+ | $$, | ||
+ | $config[' | ||
+ | ?? self:: | ||
+ | ) | ||
+ | |> self:: | ||
+ | |> self:: | ||
+ | |> self:: | ||
+ | |||
+ | This presents every step taken by the common filter chain in an easy to follow list of actions. | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 86: | Line 142: | ||
// Actual: Use of $$ outside of a pipe expression | // Actual: Use of $$ outside of a pipe expression | ||
- | This particular quirk of the parser (allowing comments in the middle of a variable-variable-brace-expression) is doubtlessly a rare occurance | + | This particular quirk of the parser (allowing comments in the middle of a variable-variable-brace-expression) is doubtlessly a rare occurrence |
Potential resolutions: | Potential resolutions: | ||
Line 127: | Line 183: | ||
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | Adopt the PIpe Operator yes/ | + | Adopt the Pipe Operator yes/ |
===== Patches and Tests ===== | ===== Patches and Tests ===== |
rfc/pipe-operator.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1