-
-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ArrayUtils::inArray should use strict in_array? #5
Comments
@adamlundrigan would everything be ok if you passed Originally posted by @Ocramius at zendframework/zend-stdlib#41 (comment) |
I should have included a link to the source there for context. If I simply change this line to add Originally posted by @adamlundrigan at zendframework/zend-stdlib#41 (comment) |
@Ocramius Originally posted by @Maks3w at zendframework/zend-stdlib#41 (comment) |
I'll do the logical question. Why not <?php
$needle = '1.10';
$haystack = ['1.1'];
assert(ArrayUtils::inArray($needle, $haystack, **true**) === false); Originally posted by @Maks3w at zendframework/zend-stdlib#41 (comment) |
Sorry I wrote wrong the example. I've edited Originally posted by @Maks3w at zendframework/zend-stdlib#41 (comment) |
Marco asked same question above: zendframework/zend-stdlib#41 (comment) It breaks an existing test in FormSelect. The Originally posted by @adamlundrigan at zendframework/zend-stdlib#41 (comment) |
Sorry I'm not able to understand why I've missing something in your answer. Originally posted by @Maks3w at zendframework/zend-stdlib#41 (comment) |
/**
* 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 Originally posted by @adamlundrigan at zendframework/zend-stdlib#41 (comment) |
I understand the issue now. Well, I see
My (abstract) proposal:
Originally posted by @Maks3w at zendframework/zend-stdlib#41 (comment) |
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 Originally posted by @adamlundrigan at zendframework/zend-stdlib#41 (comment) |
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?
Originally posted by @adamlundrigan at zendframework/zend-stdlib#41
The text was updated successfully, but these errors were encountered: