开发者

If statement giving a wrong answer

I've long used assignment inside long if statements to simplify things. But in this case, it's not working as intended. Here's what I've got:

$Employee = GetEmployee开发者_开发百科Name($Record['employee_id']);
echo 'First name: '.$Employee['first_name'];
echo 'Last name: '.$Employee['last_name'];
echo 'Record first name: '.$Record['first_name'];
echo 'Record last name: '.$Record['last_name'];

echo 'Comparing first name: ';
var_dump(strcasecmp($Employee['first_name'], $Record['first_name']));

echo 'Comparing last name: ';
var_dump(strcasecmp($Employee['last_name'], $Record['last_name']));

echo 'Comparing both together: ';
var_dump(strcasecmp($Employee['first_name'], $Record['first_name']) 
         || strcasecmp($Employee['last_name'], $Record['last_name']));

echo 'All together now: ';
var_dump($Foo = GetEmployeeName($Record['employee_id']) 
         && (strcasecmp($Foo['first_name'], $Record['first_name']) 
             || strcasecmp($Foo['last_name'], $Record['last_name'])));

Here's the results:

First name: ZACHARY
Last name: TAYLOR
Record first name: Zachary
Record last name: Taylor
Comparing first name: int(0)
Comparing last name: int(0)
Comparing both together: bool(false)
All together now: bool(true)

This makes no sense. Comparing the first name resolves as 0 (false); comparing the last name resolves as 0 (false); comparing them together resolves as false. Yet when I add the assignment into the if, it suddenly resolves as true. I've been assigning variables in ifs for a long time and I've never seen this happen. The weird thing is, if I assign outside the if, it works fine. So I could do that, but at this point it's about the principle of finding out what's going wrong so I can improve my knowledge of the language.

Assignment in this case gives true, as you can see by the fact that $Employee is populated. So, the final var_dump is essentially "true && false", which should resolve as false. Right?


The boolean operator && has a higher precedence than the assignment operator =. So this:

$Foo = GetEmployeeName($Record['employee_id']) 
     && (strcasecmp($Foo['first_name'], $Record['first_name']) 
         || strcasecmp($Foo['last_name'], $Record['last_name']))

Is equivalent to:

$Foo = (GetEmployeeName($Record['employee_id']) 
     && (strcasecmp($Foo['first_name'], $Record['first_name']) 
         || strcasecmp($Foo['last_name'], $Record['last_name'])))

Put the parentheses around the assignment and it works:

($Foo = GetEmployeeName($Record['employee_id'])) 
     && (strcasecmp($Foo['first_name'], $Record['first_name']) 
         || strcasecmp($Foo['last_name'], $Record['last_name']))


I've just spent a fair while figuring out the problem with this, and have finally hit on the problem.

My test code:

var_dump($Foo = array('first_name' => 'ZACHARY', 'last_name' => 'TAYLOR') 
     && (strcasecmp($Foo['first_name'], 'Zachary') 
         || strcasecmp($Foo['last_name'], 'Taylor')));

Gives the output:

PHP Notice:  Undefined variable: Foo in /home/sam/test.php on line 6
PHP Stack trace:
PHP   1. {main}() /home/lday/test.php:0
bool(true)

The problem is that $Foo is only assigned after all the action on the right of the = operator has happened. So when you call strcasecmp($Foo['first_name'], 'Zachary'), you are actually doing strcasecmp('', 'Zachary'), which evaluates to -7 (boolean true). So your code evaluates like this:

$Foo = true && (-7 || -7);

Which is obviously true.

As shown elsewhere, the solution is to put $Foo in brackets, so it is evaluated first:

var_dump(($Foo = array('first_name' => 'ZACHARY', 'last_name' => 'TAYLOR'))  
     && (strcasecmp($Foo['first_name'], 'Zachary') 
         || strcasecmp($Foo['last_name'], 'Taylor')));


because of the operator precedence, your code is interpreted as follows:

first, the result of:

GetEmployeeName($Record['employee_id']) && (strcasecmp($Foo['first_name'],
$Record['first_name']) || strcasecmp($Foo['last_name'],
$Record['last_name']))

if checked

after this the result is asignet to $Foo - and if just checks if this assignment was successful.

to avoid this, use braces to group the parts of your camparision correctly.


strcasecmp :

Returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.

so the return of zero means they equal each other not false

// This is the example code form the PHP site itself

<?php
   $var1 = "Hello";
   $var2 = "hello";
   if (strcasecmp($var1, $var2) == 0) {
      echo '$var1 is equal to $var2 in a case-insensitive string comparison';
   }
?>

As you have stated in your comments above, these should both return the same results. Please execute the example code and you will see they do not.

<?php

if(strcasecmp("ZACHARY", "Zachary") == 0) {
    echo "We have a match with a zero (int) return\n"; // this returns 0
}

echo !strcasecmp("ZACHARY", "Zachary")."\n"; // this will return 1

?>

How you're using var_dump to compare int(0) returns will return a bool(false)

// returns int(0)
var_dump(strcasecmp("ZACHARY", "Zachary")); 

// will return bool(false) as it's comparing int(0) || int(0)
var_dump((strcasecmp("ZACHARY", "Zachary")) || (strcasecmp("ZACHARY", "Zachary")));
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜