Description
Symfony version(s) affected
5.0.0 and more
Description
Because the formBuilder use name as key, and because php is casting int-string like '0'
to int, we sometimes ends with form name which is integer and this cannot be directly used by method like FormInterface::remove
.
How to reproduce
The following code
foreach ($form as $name => $child) {
$form->remove($name);
}
is not working when the form was build this way
$formBuilder->add('0', ...)
Because the name is casted to an int when used as an array key here:
https://github.com/symfony/symfony/blob/6.2/src/Symfony/Component/Form/FormBuilder.php#L71-L72
There are some situation in the Symfony code where the form names can be int and passed to method expecting string. One of them is the ChoiceType
with expanded option.
https://github.com/symfony/form/blob/6.1/Extension/Core/Type/ChoiceType.php#L407-L419
So far this code is working because declare(strict_types=1);
is not used.
But for my first example
foreach ($form as $name => $child) {
$form->remove($name);
}
if it's written in the userland with strict_types, it won't work even if all the phpdoc make believe it will:
- FormInterface is a
\Traversable<string, FormInterface>
- remove accepts
string
Possible Solution
I see at least four solutions here:
- Changing some of the typehint in https://github.com/symfony/symfony/blob/6.1/src/Symfony/Component/Form/FormInterface.php to accepts
int|string
(since it's a BC-break, this might wait for 7.0) - Changing the phpdoc to
\Traversable<int|string, FormInterface>
with some comments; at least static-analysis user will be warned. - Deprecating passing an integer-as-string as a form name ; this might be the smoother solution. Instead of
$formBuilder->add('0')
it should be$formBuilder->add('prefix_0')
. And in SF 7.0, this will throw an exception. - Doing nothing
Additional Context
No response