Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP max() and min() weird behavior with different types

Tags:

php

comparison

I have been scratching my head for the past two hours over this behavior:

echo 'max(1, "a", "2"   ) : '; var_dump( max( 1, 'a', '2' ) );
echo 'max(1, "2", "a"   ) : '; var_dump( max( 1, '2', 'a' ) );
echo 'max(   "a", "2", 1) : '; var_dump( max( 'a', '2', 1 ) );
echo 'max(   "2", "a", 1) : '; var_dump( max( '2', 'a', 1 ) );
echo "\n";
echo 'min(1, "a", "2"   ) : '; var_dump( min( 1, 'a', '2' ) );
echo 'min(1, "2", "a"   ) : '; var_dump( min( 1, '2', 'a' ) );
echo 'min(   "a", "2", 1) : '; var_dump( min( 'a', '2', 1 ) );
echo 'min(   "2", "a", 1) : '; var_dump( min( '2', 'a', 1 ) );

Which prints out:

max(1, "a", "2"   ) : string(1) "2"
max(1, "2", "a"   ) : string(1) "a"
max(   "a", "2", 1) : int(1)
max(   "2", "a", 1) : int(1)

min(1, "a", "2"   ) : string(1) "2"
min(1, "2", "a"   ) : string(1) "a"
min(   "a", "2", 1) : int(1)
min(   "2", "a", 1) : int(1)

When I was expecting:

max(1, "a", "2"   ) : string(1) "2"
max(1, "2", "a"   ) : string(1) "2"
max(   "a", "2", 1) : string(1) "2"
max(   "2", "a", 1) : string(1) "2"

min(1, "a", "2"   ) : string(1) "a"
min(1, "2", "a"   ) : string(1) "a"
min(   "a", "2", 1) : string(1) "a"
min(   "2", "a", 1) : string(1) "a"

Note that the values given to max() and min() functions are always the same, but the order is different.

Also, according to the documentation, strings not started with numerical characters are evaluated as integer 0 when compared to integers, but multiple string values are compared alphanumerically. Source:

  • http://php.net/manual/en/function.max.php
  • http://php.net/manual/en/function.min.php

How could this output be explained?

like image 933
AndreCunha Avatar asked Apr 27 '16 18:04

AndreCunha


1 Answers

The comparison in min() and max() is done sequentially as this can be seen in the source code:

min() source code:

//...
min = &args[0];

for (i = 1; i < argc; i++) {
    is_smaller_function(&result, &args[i], min);
    if (Z_TYPE(result) == IS_TRUE) {
        min = &args[i];
    }
}
//...

max() source code:

//...
max = &args[0];

for (i = 1; i < argc; i++) {
    is_smaller_or_equal_function(&result, &args[i], max);
    if (Z_TYPE(result) == IS_FALSE) {
        max = &args[i];
    }
}
//...

So you can see that the function goes through the array and checks if the next value is smaller/bigger than the previous smallest/biggest saved value.


To understand how you get these results you also have to know that the comparison of the values is done after PHP type juggling.

So let's look at two example to see how the functions work:

Example 1

max ( 1 , 'a' , '2' )
      │    │     │
      1 > 'a'    │
        │        │
        1    <  '2'
             │
             └ Result: '2'
  1. Comparing 1 and 'a', numerical context means 'a' gets converted to 0, 1 is greater than 0.
    → int 1 returned

  2. Comparing 1 and '2', numerical string means '2' gets converted to 2, 2 is greater than 1.
    → string '2' returned

  • Result: string '2'

Example 2

max ( 1 , '2' , 'a' )
      │    │     │
      1 < '2'    │
        │        │
       '2'   <  'a'
             │
             └ Result: 'a'
  1. Comparing 1 and '2', numerical string means '2' gets converted to 2, 2 is greater than 1.
    → string '2' returned

  2. Comparing '2' and 'a', both strings means string comparison, 'a' is greater than '2' just compared with the ASCII values.
    → string 'a' returned

  • Result: string 'a'

And the same rules apply for all of the other examples.

like image 172
u_mulder Avatar answered Oct 02 '22 14:10

u_mulder