Edit report at https://bugs.php.net/bug.php?id=53104&edit=1

 ID:                 53104
 Updated by:         yohg...@php.net
 Reported by:        frase at cs dot wisc dot edu
 Summary:            min() and max() treat NULL and BOOL differently
 Status:             Analyzed
 Type:               Bug
 Package:            Scripting Engine problem
 Operating System:   any
 PHP Version:        any
 Block user comment: N
 Private report:     N

 New Comment:

I forgot to edit values. So BOOL works some what but it does not compared as 
operators.

[yohgaki@dev php-5.5]$ php -r "var_dump(min([2, 3, false]));"
bool(false)
[yohgaki@dev php-5.5]$ php -r "var_dump(min([-2, -3, false]));"
bool(false)
[yohgaki@dev php-5.5]$ php -r "var_dump(-3 < false);"
bool(false)

[yohgaki@dev php-5.5]$ php -r "var_dump(min([2, 3, true]));"
int(2)
[yohgaki@dev php-5.5]$ php -r "var_dump(max([2, 3, true]));"
int(3)
[yohgaki@dev php-5.5]$ php -r "var_dump(max(-2, -3, true));"
int(-2)

It seems "false" is evaluated as the smallest and "true" is ignored.

We have serious mess here.
Since min()/max() supports array type, we cannot convert NULL/BOOL parameter to 
INT as it would returns different results for array parameter. For the same 
reason, black listing NULL/BOOL parameters do not work.

Anyone has clever idea?

Corrected test code
-------------
<?php

echo "min(-1,null) = "; var_dump(min(-1,null)); echo "\n"; /* NULL    */
echo "min( 1,null) = "; var_dump(min( 1,null)); echo "\n"; /* NULL    */
echo "max(-1,null) = "; var_dump(max(-1,null)); echo "\n"; /* int(-1) */
echo "max( 1,null) = "; var_dump(max( 1,null)); echo "\n"; /* int(1)  */

echo "min(-1,false) = "; var_dump(min(-1,null)); echo "\n"; /* NULL    */
echo "min( 1,false) = "; var_dump(min( 1,null)); echo "\n"; /* NULL    */
echo "max(-1,false) = "; var_dump(max(-1,null)); echo "\n"; /* int(-1) */
echo "max( 1,false) = "; var_dump(max( 1,null)); echo "\n"; /* int(1)  */

echo "min(-1,true) = "; var_dump(min(-1,null)); echo "\n"; /* NULL    */
echo "min( 1,true) = "; var_dump(min( 1,null)); echo "\n"; /* NULL    */
echo "max(-1,true) = "; var_dump(max(-1,null)); echo "\n"; /* int(-1) */
echo "max( 1,true) = "; var_dump(max( 1,null)); echo "\n"; /* int(1)  */

echo "min(null,-1) = "; var_dump(min(null,-1)); echo "\n"; /* NULL    */
echo "min(null, 1) = "; var_dump(min(null, 1)); echo "\n"; /* NULL    */
echo "max(null,-1) = "; var_dump(max(null,-1)); echo "\n"; /* int(-1) */
echo "max(null, 1) = "; var_dump(max(null, 1)); echo "\n"; /* int(1)  */

echo "min(false,-1) = "; var_dump(min(null,-1)); echo "\n"; /* NULL    */
echo "min(false, 1) = "; var_dump(min(null, 1)); echo "\n"; /* NULL    */
echo "max(false,-1) = "; var_dump(max(null,-1)); echo "\n"; /* int(-1) */
echo "max(false, 1) = "; var_dump(max(null, 1)); echo "\n"; /* int(1)  */

echo "min(true,-1) = "; var_dump(min(null,-1)); echo "\n"; /* NULL    */
echo "min(true, 1) = "; var_dump(min(null, 1)); echo "\n"; /* NULL    */
echo "max(true,-1) = "; var_dump(max(null,-1)); echo "\n"; /* int(-1) */
echo "max(true, 1) = "; var_dump(max(null, 1)); echo "\n"; /* int(1)  */

echo "min(10,-1,null) = "; var_dump(min(10,-1,null)); echo "\n"; /* NULL    */
echo "min(10, 1,null) = "; var_dump(min(10, 1,null)); echo "\n"; /* NULL    */
echo "max(10,-1,null) = "; var_dump(max(10,-1,null)); echo "\n"; /* int(10) */
echo "max(10, 1,null) = "; var_dump(max(10, 1,null)); echo "\n"; /* int(10)  */

echo "min(10,-1,false) = "; var_dump(min(10,-1,false)); echo "\n"; /* false    
*/
echo "min(10, 1,false) = "; var_dump(min(10, 1,false)); echo "\n"; /* false    
*/
echo "max(10,-1,false) = "; var_dump(max(10,-1,false)); echo "\n"; /* int(10) */
echo "max(10, 1,false) = "; var_dump(max(10, 1,false)); echo "\n"; /* int(10)  
*/

echo "min(10,-1,true) = "; var_dump(min(10,-1,true)); echo "\n"; /* -1    */
echo "min(10, 1,true) = "; var_dump(min(10, 1,true)); echo "\n"; /* 1    */
echo "max(10,-1,true) = "; var_dump(max(10,-1,true)); echo "\n"; /* int(10) */
echo "max(10, 1,true) = "; var_dump(max(10, 1,true)); echo "\n"; /* int(10)  */

echo "min([10,-1,null]) = "; var_dump([min(10,-1,null)]); echo "\n"; /* [NULL]  
  */
echo "min([10, 1,null]) = "; var_dump([min(10, 1,null)]); echo "\n"; /* [NULL]  
  */
echo "max([10,-1,null]) = "; var_dump([max(10,-1,null)]); echo "\n"; /* 
[int(10)] */
echo "max([10, 1,null]) = "; var_dump([max(10, 1,null)]); echo "\n"; /* 
[int(10)]  */

echo "min([10,-1,false]) = "; var_dump([min(10,-1,null)]); echo "\n"; /* [NULL] 
   */
echo "min([10, 1,false]) = "; var_dump([min(10, 1,null)]); echo "\n"; /* [NULL] 
   */
echo "max([10,-1,false]) = "; var_dump([max(10,-1,null)]); echo "\n"; /* 
[int(10)] */
echo "max([10, 1,false]) = "; var_dump([max(10, 1,null)]); echo "\n"; /* 
[int(10)]  */

echo "min([10,-1,true]) = "; var_dump([min(10,-1,null)]); echo "\n"; /* [NULL]  
  */
echo "min([10, 1,true]) = "; var_dump([min(10, 1,null)]); echo "\n"; /* [NULL]  
  */
echo "max([10,-1,true]) = "; var_dump([max(10,-1,null)]); echo "\n"; /* 
[int(10)] */
echo "max([10, 1,true]) = "; var_dump([max(10, 1,null)]); echo "\n"; /* 
[int(10)]  */


Previous Comments:
------------------------------------------------------------------------
[2013-10-23 07:46:49] yohg...@php.net

The comparison is done by compare_function() in zend_operators.c Not only NULL, 
but also BOOL type also has the same problem. I haven't check fully for ARRAY, 
but it seems NULL and BOOL break comparison.

We have inconsistency with comparison operators.

$ php -r "var_dump(-1 > NULL);"
bool(true)
$ php -r "var_dump(-1 < NULL);"
bool(false)
$ php -r "var_dump(min(-1,NULL));"
NULL
$ php -r "var_dump(min(NULL, -1));"
NULL

Comparison operators evaluate comparison as PHP users expect, but min() does 
not. This behavior is not intuitive.

We may fix this issue or document this unexpected behavior in min() manual. (+ 
other functions if there are affected)

I think this is better to be fixed even if there is BC issue at some point.
Any comments?


Test code
-----------------------------
<?php

echo "min(-1,null) = "; var_dump(min(-1,null)); echo "\n"; /* NULL    */
echo "min( 1,null) = "; var_dump(min( 1,null)); echo "\n"; /* NULL    */
echo "max(-1,null) = "; var_dump(max(-1,null)); echo "\n"; /* int(-1) */
echo "max( 1,null) = "; var_dump(max( 1,null)); echo "\n"; /* int(1)  */

echo "min(-1,false) = "; var_dump(min(-1,null)); echo "\n"; /* NULL    */
echo "min( 1,false) = "; var_dump(min( 1,null)); echo "\n"; /* NULL    */
echo "max(-1,false) = "; var_dump(max(-1,null)); echo "\n"; /* int(-1) */
echo "max( 1,false) = "; var_dump(max( 1,null)); echo "\n"; /* int(1)  */

echo "min(-1,true) = "; var_dump(min(-1,null)); echo "\n"; /* NULL    */
echo "min( 1,true) = "; var_dump(min( 1,null)); echo "\n"; /* NULL    */
echo "max(-1,true) = "; var_dump(max(-1,null)); echo "\n"; /* int(-1) */
echo "max( 1,true) = "; var_dump(max( 1,null)); echo "\n"; /* int(1)  */

echo "min(null,-1) = "; var_dump(min(null,-1)); echo "\n"; /* NULL    */
echo "min(null, 1) = "; var_dump(min(null, 1)); echo "\n"; /* NULL    */
echo "max(null,-1) = "; var_dump(max(null,-1)); echo "\n"; /* int(-1) */
echo "max(null, 1) = "; var_dump(max(null, 1)); echo "\n"; /* int(1)  */

echo "min(false,-1) = "; var_dump(min(null,-1)); echo "\n"; /* NULL    */
echo "min(false, 1) = "; var_dump(min(null, 1)); echo "\n"; /* NULL    */
echo "max(false,-1) = "; var_dump(max(null,-1)); echo "\n"; /* int(-1) */
echo "max(false, 1) = "; var_dump(max(null, 1)); echo "\n"; /* int(1)  */

echo "min(true,-1) = "; var_dump(min(null,-1)); echo "\n"; /* NULL    */
echo "min(true, 1) = "; var_dump(min(null, 1)); echo "\n"; /* NULL    */
echo "max(true,-1) = "; var_dump(max(null,-1)); echo "\n"; /* int(-1) */
echo "max(true, 1) = "; var_dump(max(null, 1)); echo "\n"; /* int(1)  */

echo "min(10,-1,null) = "; var_dump(min(10,-1,null)); echo "\n"; /* NULL    */
echo "min(10, 1,null) = "; var_dump(min(10, 1,null)); echo "\n"; /* NULL    */
echo "max(10,-1,null) = "; var_dump(max(10,-1,null)); echo "\n"; /* int(10) */
echo "max(10, 1,null) = "; var_dump(max(10, 1,null)); echo "\n"; /* int(10)  */

echo "min(10,-1,false) = "; var_dump(min(10,-1,null)); echo "\n"; /* NULL    */
echo "min(10, 1,false) = "; var_dump(min(10, 1,null)); echo "\n"; /* NULL    */
echo "max(10,-1,false) = "; var_dump(max(10,-1,null)); echo "\n"; /* int(10) */
echo "max(10, 1,false) = "; var_dump(max(10, 1,null)); echo "\n"; /* int(10)  */

echo "min(10,-1,true) = "; var_dump(min(10,-1,null)); echo "\n"; /* NULL    */
echo "min(10, 1,true) = "; var_dump(min(10, 1,null)); echo "\n"; /* NULL    */
echo "max(10,-1,true) = "; var_dump(max(10,-1,null)); echo "\n"; /* int(10) */
echo "max(10, 1,true) = "; var_dump(max(10, 1,null)); echo "\n"; /* int(10)  */

echo "min([10,-1,null]) = "; var_dump([min(10,-1,null)]); echo "\n"; /* [NULL]  
  */
echo "min([10, 1,null]) = "; var_dump([min(10, 1,null)]); echo "\n"; /* [NULL]  
  */
echo "max([10,-1,null]) = "; var_dump([max(10,-1,null)]); echo "\n"; /* 
[int(10)] */
echo "max([10, 1,null]) = "; var_dump([max(10, 1,null)]); echo "\n"; /* 
[int(10)]  */

echo "min([10,-1,false]) = "; var_dump([min(10,-1,null)]); echo "\n"; /* [NULL] 
   */
echo "min([10, 1,false]) = "; var_dump([min(10, 1,null)]); echo "\n"; /* [NULL] 
   */
echo "max([10,-1,false]) = "; var_dump([max(10,-1,null)]); echo "\n"; /* 
[int(10)] */
echo "max([10, 1,false]) = "; var_dump([max(10, 1,null)]); echo "\n"; /* 
[int(10)]  */

echo "min([10,-1,true]) = "; var_dump([min(10,-1,null)]); echo "\n"; /* [NULL]  
  */
echo "min([10, 1,true]) = "; var_dump([min(10, 1,null)]); echo "\n"; /* [NULL]  
  */
echo "max([10,-1,true]) = "; var_dump([max(10,-1,null)]); echo "\n"; /* 
[int(10)] */
echo "max([10, 1,true]) = "; var_dump([max(10, 1,null)]); echo "\n"; /* 
[int(10)]  */

-------------------

------------------------------------------------------------------------
[2012-04-26 20:52:28] roeitell at gmail dot com

Actually changing behavior might cause serious bc issues for some users 
possibly 
relying on this; but attached is a patch which generates E_WARNING for min/max 
receiving a NULL parameter.

------------------------------------------------------------------------
[2010-10-19 19:39:43] frase at cs dot wisc dot edu

Description:
------------
The min() and max() functions treat null values as "negative infinity", which 
is not documented or (to me) particularly intuitive.  I would expect null to 
either be treated as 0 (as "(int)null" does), or ignore it entirely (which 
min() does not, but max() does by virtue of any value being greater than 
negative infinity).

Test script:
---------------
echo "min(-1,null) = "; var_dump(min(-1,null)); echo "\n"; /* NULL    */
echo "min( 1,null) = "; var_dump(min( 1,null)); echo "\n"; /* NULL    */
echo "max(-1,null) = "; var_dump(max(-1,null)); echo "\n"; /* int(-1) */
echo "max( 1,null) = "; var_dump(max( 1,null)); echo "\n"; /* int(1)  */


Expected result:
----------------
min(-1,null) = int(-1)
min( 1,null) = int(1 or 0)
max(-1,null) = int(-1 or 0)
max( 1,null) = int(1)


Actual result:
--------------
min(-1,null) = NULL
min( 1,null) = NULL
max(-1,null) = int(-1)
max( 1,null) = int(1)



------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=53104&edit=1

Reply via email to