Development

PHP array_search implicit cast of search term

There is an error in the values that array_search returns when searching on an array that has a mix of numeric values (123) and alpha-numeric mixed strings that start with the same and follow with alpha characters (‘123a’).

The results are actually kind of bizarre, but explainable by a bug in PHP’s equivalence test. When testing for equivalence (using ==) PHP determines that 123 == ‘123xyz’. PHP casts the string to an integer when doing the comparison (so ‘123xyz’ becomes 123). This is documented in bugs.php.net (http://bugs.php.net/bug.php?id=23110) – but this leads to problems: both switch and array_search use == for comparison.

So, using:

$one = array (
  'abc',
  'abc1',
  111,
  '111b',
  2,
  '2xyz',
  '123a',
  123
);
$two = $one;

foreach($one as $val)
{
  $key = array_search($val, $two);
  if ($key !== false) {
    echo "$val == {$two[$key]} \n";
    if (strcmp(strval($val), strval($two[$key])) == 0) {
      echo "strcmp returns true";
    } else {
      echo "strcmp returns false";
    }
  } else {
    echo "$val not found \n";
  }
}

results in:

abc == abc -- strcmp returns true
abc1 == abc1 -- strcmp returns true
111 == 111 -- strcmp returns true
111b == 111 -- strcmp returns false
2 == 2 -- strcmp returns true
2xyz == 2 -- strcmp returns false
123a == 123a -- strcmp returns true
123 == 123a -- strcmp returns false

This becomes a real problem when you can’t be sure that the values in an array are all of the same type. However, if you are sure that all the values in the array are of type string then array_search works flawlessly.

I am still unsure how to work around this, however, I think having a version of array_search that doesn’t do an implicit cast on the search value would be of great use.

3 comments PHP array_search implicit cast of search term

Can you help me figure out a little bit more about your results?

For example, I ran this:
[code]
C:\Documents and Settings\Aaron>php -r “var_dump(strcmp(123, ‘123a’));”
int(-1)
[/code]

Which I believe is what your last comparison would have been, right? Your results says true/false – but really the results are -1, 0 and 1. Your if statement checks for 0 – which would mean they are equal. In this case, strcmp is saying that 123 is less than 123a… which to me is accurate. It is not returning false, but it is returning -1.

If you flipped them around:
[code]
C:\Documents and Settings\Aaron>php -r “var_dump(strcmp(‘123a’, 123));”
int(1)
[/code]

You receive a positive – but still not ‘true’ answer. – but not false either.

From the functions description in the php manual, to me it seems like this is the desired action. It IS called str (string) not valcmp or something else – so one would assume it would be converted to strings.

Can you help explain further? Thanks!

Could’nt you just specify the third parameter in array_search to be ‘true’. That should turn on strict mode will check the type as well. So ‘111a’ and 111 would return false since one is a string and the other is an int.

mixed array_search ( mixed $needle , array $haystack [, bool $strict ] )

James,

You could easily add the third value for array_search to force a strict comparison. However, you can’t do that in switch which still remains problematic.

There are 2 ways I can see around the switch issue: The first is to preface every value (and the value you are passing to switch) with an alpha character to force them all to strings. The second is to take a more common approach to switch (in many of the strongly typed languages) which is to only switch on integers.

Comments are closed.