Recently, I wanted to create an anonymous generator. The good news is that it is possible, the syntax is not the most obvious one, though.
You need to use a technique called "immediately invoked function expression" mostly known from JavaScript of the jQuery era.
Here it is:
$iterable = (function (): Generator {
yield 42; // yield any number of values
})();
Explanation:
- the anonymous function itself is not a generator, it's just a callable and can not be iterated over
- the function is invoked immediately after it is created and must be enclosed in parentheses
(function(){ ... })()
if we want to invoke it right away - the invocation results in a Generator, which can be iterated over
$func = function(): Generator { yield 42; };
$iterable = $func(); // this is when the generator is created
foreach($func as $item){ } // error, $foo is not iterable
foreach($iterable as $item){ } // iterates over the generator
Generators have been in PHP since version 5.5
. I have since used them rarely, but they are good for solving some edge cases, like generating a sequence of unknown length.
A generator can be used to replace code like the one below. Yeah, for two items it might be useless, but for multiple such extractors it does make sense. Especially when you know only the first extractor will be used in 99% of cases.
function getDefaultExtractors(
string $headerName,
string $cookieName
): iterable {
#< code here >#
return $extractors;
}
Code with if
s and array push:
$extractors = [];
if ($headerName !== null) {
$extractors[] = Make::headerExtractor($headerName);
}
if ($cookieName !== null) {
$extractors[] = Make::cookieExtractor($cookieName);
}
Code with array_filter
and ternaries:
$extractors = array_filter([
$headerName !== null ? Make::headerExtractor($headerName) : null,
$cookieName !== null ? Make::cookieExtractor($cookieName) : null,
]);
Code using a generator:
$extractors = (function () use ($headerName, $cookieName): Generator {
$headerName !== null && yield Make::headerExtractor($headerName);
$cookieName !== null && yield Make::cookieExtractor($cookieName);
})(),
The key idea behind the generators is that the execution is actually paused on each yield
statement, until the next iteration is initiated. For cases where the iteration is interrupted before all of the generated items are consumed, this saves some computation resources.
Top comments (0)