Initially I started creating a general post about PHP Generators, a feature introduced in PHP 5.5. However since I keep failing to come up with good examples for some cool ways to use Generators, I decided to do this mini post focusing on one such cool usage.
PHPUnit data providers
A commonly used PHPUnit feature is data providers. In a data provider you specify a list of argument lists, and the test methods that use the data provider get called once for each argument list.
Often data providers are created with an array variable in which the argument lists get stuffed. Example (including poor naming):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/** * @dataProvider provideUserInfo */ function testSomeStuff( string $userName, int $userAge ) {} function provideUserInfo() { $return = []; $return[] = [ 'Such Name', 42 ]; $return[] = [ 'Very Name', 23 ]; $return['Named parameter set'] = [ 'So Name', 1337 ]; return $return; } |
The not so nice thing here is that you have a variable (explicit state) and you modify it (mutable state). A more functional approach is to just return an array that holds the argument lists directly. However if your argument list creation is more complex than in this example, requiring state, this might not work. And when such state is required, you end up with more complexity and a higher chance that the $return
variable will bite you.
Using yield
What you might not have realized is that data providers do not need to return an array. They need to return an iterable
, so they can also return an Iterator
, and by extension, a Generator
. This means you can write the above data provider as follows:
1 2 3 4 5 |
function provideUserInfo() { yield [ 'Such Name', 42 ]; yield [ 'Very Name', 23 ]; yield 'Named parameter set' => [ 'So Name', 1337 ]; } |
No explicit state to be seen!
Update: my Introduction to Iterators and Generators in PHP is now live 🙂
See also: 5 ways to write better mocks
1 thought on “Yield in PHPUnit data providers”