-
Notifications
You must be signed in to change notification settings - Fork 75
ArrayUtils::inArray should use strict in_array? #41
Comments
@adamlundrigan would everything be ok if you passed |
I should have included a link to the source there for context. If I simply change this line to add |
@Ocramius |
I'll do the logical question. Why not <?php
$needle = '1.10';
$haystack = ['1.1'];
assert(ArrayUtils::inArray($needle, $haystack, **true**) === false); |
Sorry I wrote wrong the example. I've edited |
Marco asked same question above: #41 (comment) It breaks an existing test in FormSelect. The |
Sorry I'm not able to understand why I've missing something in your answer. |
/**
* Checks if a value exists in an array.
*
* Due to "foo" == 0 === TRUE with in_array when strict = false, an option
* has been added to prevent this. When $strict = 0/false, the most secure
* non-strict check is implemented. if $strict = -1, the default in_array
* non-strict behaviour is used.
*
* @param mixed $needle
* @param array $haystack
* @param int|bool $strict
* @return bool
*/
public static function inArray($needle, array $haystack, $strict = false)
{
if (!$strict) {
if (is_int($needle) || is_float($needle)) {
$needle = (string) $needle;
}
if (is_string($needle)) {
foreach ($haystack as &$h) {
if (is_int($h) || is_float($h)) {
$h = (string) $h;
}
}
}
}
return in_array($needle, $haystack, $strict);
} We need that, or else FormSelect view helper will blow up if you set value_options with integer keys, like this: $element = new SelectElement('foo');
$element->setValueOptions([
0 => 'label0',
1 => 'label1',
]);
// Pretend this value came from POST and we're re-displaying the form
$element->setValue("0"); That's a valid use case. FormSelect view helper will take that and output something like this: <!-- snip -->
<option value="0" selected="selected">label0</option>
<option value="1" selected="selected">label1</option>
<!-- / snip --> The types don't match so However, PHP has another thing we need to work around: var_dump('1.1' == '1.10');
// bool(true) Which means that $element = new SelectElement('foo');
$element->setValueOptions([
'1.1' => 'label 1.1',
'1.10' => 'label 1.10',
'1.2' => 'label 1.2',
'1.20' => 'label 1.20',
]);
// Pretend this value came from POST and we're re-displaying the form
$element->setValue("1.1"); We'll end up with both "1.1" and "1.10" selected when we render to HTML because in PHP's bizarro world "1.1" == "1.10". Basically, we need a check that's strict on value (so "1.1" != "1.10") but not strict type (so "int 0" == "string 0"), and that's what sending |
I understand the issue now. Well, I see
My (abstract) proposal:
|
I think it could be distilled down to a single generic "recursively cast array keys and non-array values to string" which would cover both the needle and haystack transforms. Regardless, it doesn't feel like the right solution. The intention of |
This repository has been closed and moved to laminas/laminas-stdlib; a new issue has been opened at laminas/laminas-stdlib#5. |
Related: zendframework/zend-form#18
In
Zend\Form\View\Helper\FormSelect
ArrayUtils::inArray
is called with the strict parameterfalse
. This causes an issue with string matching ('1.1' and '1.10' treated equivalent):(3v4l: https://3v4l.org/HKM8Q)
Simply changing FormSelect to use strict=true breaks an existing test which uses integer keys in the value options array.
Since
ArrayUtils::inArray
uses string casting to work aroundin_array
's wonky non-strict behaviour, shouldn't the call toin_array
always have strict=true?I've tested this change here (all tests pass) and against
zend-form
(where it fixes the reported issue).What's the protocol for testing changes to packages which may have knock-on effects on other packages? Pull every repo that has a dependency on stdlib, apply the patch, and run the tests?
The text was updated successfully, but these errors were encountered: