twigphp / Twig

Twig, the flexible, fast, and secure template language for PHP
https://twig.symfony.com/
BSD 3-Clause "New" or "Revised" License
8.18k stars 1.25k forks source link

Fix behaviour of `cycle` function & mappings ? #4158

Closed smnandre closed 2 months ago

smnandre commented 3 months ago

I have a couple questions about the "cycle" function...

I'm not sure what is really expected in some scenarios (mainly "what to do with mappings"), and the documentation uses "mapping" "sequence" and "list" terms.

I'll gladly open a PR, but i'm not sure what to do here :)


Current code of the cycle function here

```php /** * Cycles over a value. * * @param \ArrayAccess|array $values * @param int $position The cycle position * * @return string The next value in the cycle * * @internal */ public static function cycle($values, $position): string { if (!\is_array($values) && !$values instanceof \ArrayAccess) { return $values; } if (!\count($values)) { throw new RuntimeError('The "cycle" function does not work on empty sequences/mappings.'); } return $values[$position % \count($values)]; } ```


ArrayAccess ?

If $values implements ArrayAccess but not Countable, depending on the PHP version the effects can be a simple warning or ... a DivisionByZeroError

Sequences / Mappings

There is nothing explicit in the docblock, and the exception is about "sequences/mappings" but .. in reality this method does only works with lists (sequences) of strings.

stof commented 2 months ago

I would suggest removing the return type, as there is no reason to restrict it to strings (we could want to cycle over a list of booleans).

I would suggest documenting that this function expects a sequence and a non-negative position (not sure whether we need runtime checks for those, I will let @fabpot decide).

We should indeed forbid passing a non-countable ArrayAccess (with a deprecation first).

If $values implements ArrayAccess but not Countable, depending on the PHP version the effects can be a simple warning or ... a DivisionByZeroError

you cannot get a DivisionByZeroError as computing the count to 0 will throw a RuntimeError before reaching the modulo.

fabpot commented 2 months ago

I would suggest removing the return type, as there is no reason to restrict it to strings (we could want to cycle over a list of booleans).

Agreed

I would suggest documenting that this function expects a sequence and a non-negative position (not sure whether we need runtime checks for those, I will let @fabpot decide).

Agreed to document that (without runtime checks)

We should indeed forbid passing a non-countable ArrayAccess (with a deprecation first).

Agreed

fabpot commented 2 months ago

@smnandre Do you want to work on a PR?

smnandre commented 2 months ago

Yep :)