<?php
// WARNING: this is just a way to experiment with short closures and you SHOULD NOT write code like this
echo '# PART 1 - Short closures may contain only 1 expression and nothing more'.PHP_EOL.PHP_EOL;
// Two expressions: Syntax error (not catchable in this branch)
// $test = fn($x) => { $y = 10; return $x + $y; };
function last(...$args) { // all expression results enter here
return end($args); // only last one is returned
}
// unlike JavaScript where the last expression is returned, PHP returns a boolean
$andOperator = fn($x) => ($y = 10) && $x + $y;
var_dump($andOperator(7));
// PHP also doesn't have a comma operator like JS. In JS "a, b" will return b
// $commaOperator = fn($x) => $y = 10, $x + $y; // Syntax error
// end() only accepts references, so no luck yet:
//$arrayEnd = fn($x) => end([$y = 10, $x + $y]); // Fatal error: Only variables can be passed by reference
$multipleLines = fn($x) => last(
$y = $x * 10,
$z = $y + 15,
$x + $y + $z // result of this line is returned from last()
);
var_dump($multipleLines(7));
$moreComplex = fn($x) => last(
$numbers = range(0, $x),
$y = array_map(fn($z) => strlen($z), $numbers),
array_sum($y) // result of this line is returned from last()
);
var_dump($moreComplex(7));
echo PHP_EOL;
echo '# PART 2 - Short closures bind by value, always'.PHP_EOL.PHP_EOL;
function walkThisWay(Closure $closure) { // just an example
$i = 0;
while ($word = $closure()) {
echo $word.PHP_EOL;
$i++;
if ($i > 3) { // length of $parameters
echo 'NAH! it seems it\'s not really a reference'.PHP_EOL;
break;
}
}
echo PHP_EOL;
}
echo "## TEST 1 - not a reference:".PHP_EOL;
$parameters = ['banana', 'terracotta', 'pie'];
// we want to change $parameters, but what we have is a copy of it, arrays behave this way
walkThisWay(fn() => array_shift($parameters));
echo "## TEST 2 - syntax error:".PHP_EOL;
$parameters = ['banana', 'terracotta', 'pie'];
// Error is not catchable in this branch
//walkThisWay(fn() use (&$parameters) => array_shift($parameters));
echo PHP_EOL;
echo "## TEST 3 - object:".PHP_EOL;
$parameters = ['banana', 'terracotta', 'pie'];
$wrapper = (object) ['parameters' => &$parameters];
// objects are not really references, but they know where all data is, a copy is not made
// You could also use ArayObject instead of $wrapper
walkThisWay(fn() => array_shift($wrapper->parameters));
echo "## TEST 4 - functional hack:".PHP_EOL;
$parameters = ['banana', 'terracotta', 'pie'];
function ref(&$reference, Closure $closure) {
return function (...$args) use ($closure, &$reference) {
$args[] = &$reference; // add a reference to $parameters in the arguments
return $closure(...$args);
};
}
walkThisWay(ref($parameters, fn(&$parameters) => array_shift($parameters)));
echo "## TEST 5 - good old functions (better use this version in real code):".PHP_EOL;
$parameters = ['banana', 'terracotta', 'pie'];
walkThisWay(function () use (&$parameters) { return array_shift($parameters); });