phpiteratorphpunittraversable

How to return instance of Traversable to meet following assertion code?


Here I have a challenging php function that should return an instanceof Traversable (iterator) and also need to meet other assertions that test this function.

Function has no errors, it computes Fibonacci numbers. The function can be modified, it is specifically constructed this way to challenge others. But there is a restriction, only piece labeled as !!! (triple exclamation mark) can be changed.

public function getFibonacci($n) {
        $n2 = -($n1 = 1);
        while ($n --> -1) {
            $r = $n1 += $n2 and 0 or !!![$n + 1 => $n1];
            $n2 = $n1 - $n2;
        }
        return $r;
    }

and here is a phpunit code that will test getFibonacci function

assertTrue(
    ($res = (getFibonacci(8))
    && ($res instanceof \Traversable)
    && count($arr = iterator_to_array($res)) === 9
    && array_keys($arr) == range(8, 0, -1)
    && array_values($arr) == [0, 1, 1, 2, 3, 5, 8, 13, 21]
);

So expected to add some code instead of !!! (triple exclamation mark) so that assertion will pass.


Solution

  • It's a generator function

    Generator delegation via yield from

    In PHP 7, generator delegation allows you to yield values from another generator, Traversable object, or array by using the yield from keyword. The outer generator will then yield all values from the inner generator, object, or array until that is no longer valid, after which execution will continue in the outer generator.

    If a generator is used with yield from, the yield from expression will also return any value returned by the inner generator.

    $r = $n1 += $n2 and 0 or !!![$n + 1 => $n1];
    

    PS: In PHP, logical operators have the lowest priority. Therefore, this string is equivalent to

    $r = $n1 += $n2;
    !!![$n + 1 => $n1];