Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions Zend/tests/closure_composition/basic-composition.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
Basic composition
--FILE--
<?php

// Basic case.
$fn = strtolower(...) + str_rot13(...);
var_dump($fn("Hello World"));

// Inline closures work.
$fn = strtolower(...) + str_rot13(...) + (fn($x) => "A fine $x");
var_dump($fn("Hello World"));

// Inline invocation works, even if you'd rarely want to.
var_dump((strtolower(...) + str_rot13(...) + (fn($x) => "A fine $x"))("Hello World"));

// Order is left-to-right.
$fn = strtolower(...) + (fn($x) => "A fine $x") + str_rot13(...);
var_dump($fn("Hello World"));

class Capitalize {
public function __invoke(string $x): string {
return strtoupper($x);
}
}
$capitalizer = new Capitalize();

// Invokables work as a second element.
$fn = strtolower(...) + $capitalizer;
var_dump($fn("Hello World"));

// Invokables work as a first element.
$fn = $capitalizer + strtolower(...);
var_dump($fn("Hello World"));

--EXPECT--
string(13) "uryyb jbeyq"
string(18) "A fine uryyb jbeyq"
string(18) "A fine uryyb jbeyq"
string(18) "N svar uryyb jbeyq"
string(13) "HELLO WORLD"
string(13) "hello world"
39 changes: 39 additions & 0 deletions Zend/tests/closure_composition/compose-append.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
--TEST--
Appending composition
--FILE--
<?php

// Basic case.
$fn = strtolower(...);
$fn += str_rot13(...);
var_dump($fn("Hello World"));

// Multiple appends work
$fn = strtolower(...);
$fn += str_rot13(...);
$fn += (fn($x) => "A fine $x");
var_dump($fn("Hello World"));

class Capitalize {
public function __invoke(string $x): string {
return strtoupper($x);
}
}
$capitalizer = new Capitalize();

// Can append an invokable.
$fn = strtolower(...);
$fn += $capitalizer;
var_dump($fn("Hello World"));

// Can append an FCC.
$fn = $capitalizer;
$fn += strtolower(...);
var_dump($fn("Hello World"));

--EXPECT--
string(13) "uryyb jbeyq"
string(18) "A fine uryyb jbeyq"
string(18) "N svar uryyb jbeyq"
string(13) "HELLO WORLD"
string(13) "hello world"
22 changes: 22 additions & 0 deletions Zend/tests/closure_composition/compose-inline.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Composition inline with function calls
--FILE--
<?php

$a = [
'Hello',
'PHP',
'World',
];

var_dump(array_map(strtolower(...) + strrev(...), $a));

--EXPECT--
array(3) {
[0]=>
string(5) "olleh"
[1]=>
string(3) "php"
[2]=>
string(5) "dlrow"
}
25 changes: 25 additions & 0 deletions Zend/tests/closure_composition/compose-pipes.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
Composing with pipes.
--FILE--
<?php

// Can pipe into a composed closure.
$fn = strtolower(...) + str_rot13(...);
var_dump("Hello World" |> $fn);

function add3(int $x): int {
return $x = 3;
}

function div4(int $x): float {
return $x / 4;
}

// Can embed a composed closure within a pipe.
// The precedence here should compose first, then pipe.
// If it doesn't, it will be an error as adding 2 to a closure is undefined.
var_dump(8 |> div4(...) + add3(...));

--EXPECT--
string(13) "uryyb jbeyq"
int(5)
10 changes: 10 additions & 0 deletions Zend/zend_closures.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "zend.h"
#include "zend_API.h"
#include "zend_closures.h"
#include "zend_composed_callable.h"
#include "zend_exceptions.h"
#include "zend_interfaces.h"
#include "zend_objects.h"
Expand Down Expand Up @@ -705,6 +706,14 @@ ZEND_COLD ZEND_METHOD(Closure, __construct)
}
/* }}} */

static zend_result zend_closure_do_operation(uint8_t opcode, zval *result, zval *op1, zval *op2) {
if (opcode != ZEND_ADD) {
return FAILURE;
}

return zend_composed_callable_new_from_pair(result, op1, op2);
}

void zend_register_closure_ce(void) /* {{{ */
{
zend_ce_closure = register_class_Closure();
Expand All @@ -720,6 +729,7 @@ void zend_register_closure_ce(void) /* {{{ */
closure_handlers.get_debug_info = zend_closure_get_debug_info;
closure_handlers.get_closure = zend_closure_get_closure;
closure_handlers.get_gc = zend_closure_get_gc;
closure_handlers.do_operation = zend_closure_do_operation;
}
/* }}} */

Expand Down
Loading