非常不合逻辑的php值比较

时间:2010-07-18 04:27:18

标签: php

我偶然发现了一些非常奇怪的PHP代码。有人可以解释为什么会这样吗? *****奖励积分*****如果你能告诉我为什么这是有用的。

<?php
if(0=='a'){
    print ord(0)." should NEVER equal ".ord('a')."<br>";
}
if(false==0){
       print "false==0<br>";
}
if('a'==false){
       print "a==false<br>";
}
?>

结果输出:

48 should NEVER equal 97
false==0

8 个答案:

答案 0 :(得分:33)

在PHP中,'a'不是ASCII字符a,而是字符串a。在数值上下文中,它等于0.例如intval('a')导致值0

这很有用,因为PHP主要用于处理文本,有人可能想尝试测试(123 =='123'),这是真的。并且考虑到单引号(或双引号)中的数字被视为数字,没有数字值的字符串被视为除0以外的任何值都没有意义。

噢,是的,还有一件事。布尔上下文中的'a'为true,而不是false。我相信这使得某些类型的文本处理更加自然,但老实说,我不能在这么晚的时候想到一个例子。

答案 1 :(得分:8)

嗯,这总是PHP type cheat sheet

答案 2 :(得分:7)

这是弱/动态类型语言的基本原则,称为type juggling。在某些情况下,类型将转换为其他类型。将字符串与数字进行比较时,字符串将被转换为数字。将任何东西与布尔值进行比较时,该值将被强制转换为布尔值。

There are rules for every type关于如何将其转换为其他类型或其如何{{3}其他类型。 'a'恰好在转换为数字时转换为0(唯一合乎逻辑的选择,真的)。要避免使用此类型转换,请使用等于运算符==进行测试,但使用compares ===进行测试。

作为identity operator,这很有用,因为PHP会处理真正数字的字符串。例如,即使值是数字,HTML表单也只提交字符串。它还允许一些非常简洁的代码,例如:

$result = someOperation();
if (!$result) {
    // $result may be null, false, 0, '' or array(),
    // all of which we're not interested in
    error();
}

这也意味着你必须非常小心在什么情况下检查什么,因为一个值可能会意外地转换成其他东西。诚然,'a' == 0本身就是类型杂耍的一个陷阱,而不是有用的。这是您必须小心并像if (is_numeric($var) && $var == 0)一样进行测试的情况之一。

答案 3 :(得分:3)

ord()包含字符,因此PHP将0转换为'0'0等于false,即使它不相同(===)。

答案 4 :(得分:1)

从手册中查看PHP type comparison tables。这是一个非常方便的事情,直到你内化它,并且对我理解什么将评估真实和什么时候非常有价值。

其他人已经回答了问题的核心,但我认为重要的是要声明在PHP中,唯一一个不使用==运算符求值为“true”的非空字符串是“0”,因为PHP对待任何只包含数字作为整数或浮点数的字符串。

这个的基本原理是PHP的类型相当松散,并试图允许整数,字符串,浮点数和布尔值可以互换。一个现实世界的非常常见的例子是,如果您使用的是mysql或PDO函数,则会为所有返回字符串,即使基础列是整数。

考虑以下sql:

CREATE TABLE `test`.`pants` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`some_other_int` INT NOT NULL
) ENGINE = InnoDB;

INSERT INTO `test`.`pants` (`id`, `some_other_int`)
VALUES ('1', '1'), ('2', '0');

以下代码:

<?php

$c = mysql_connect('127.0.0.1', 'user', 'password');
mysql_select_db('test', $c);
$r = mysql_query('SELECT * FROM pants', $c);

while ($row = mysql_fetch_assoc($r)) {
    var_dump($row);
    foreach($row as $k=>$v) {
        if (!is_string($v))
            echo "field {$v} was not a string!\n";
    }
}

“字段x不是字符串!”即使数据库中的每一列都是整数,也不会永远打印消息。假设您想要实际使用该表中的第二行。

<?php
$id = 2;
$r = mysql_query(sprintf('SELECT * FROM pants WHERE id=%s', mysql_real_esacpe_string($id)), $c);
$row = mysql_fetch_assoc($r);

// this is the important bit
if (0 == $row['some_other_int']) {
    echo "It was zero!";
}

如果字符串“0”未被视为比较的整数0,则上述代码将永远不会打印“它为零!”。程序员将被要求负责处理从数据库中出来的值的类型。对于松散类型的语言,这是不可取的。

严格的平等包括类型使用“真的,真的,诚实的上帝等于”运算符进行测试,运算符由符号“===”表示。

答案 5 :(得分:1)

  

我不知道('a'== 0)是如何有用的

$var = '123abc';

if (123 == $var)
{
    echo 'Whoda thunk it?';
}

归结为PHP的隐式转换规则。

我没有想到一个实际的例子,但这就是你看到这种行为的基本原因。

扩展:

在您的示例中,'a'被转换为0(零),用于比较。想象一下,为了进行比较,它相当于'0a'。 (这是数字零,而不是字母'o。')

进一步扩展:

我认为手册中有一个很好的示例用例,但我找不到它。我所遇到的应该有助于揭示这种“不合逻辑”的情况。

  

PHP首先是一个Web   语言,而不是通用目的   脚本语言。因为网络是   没有输入,一切都是字符串,   我不得不做一些事情   不同的早期做PHP   人们的期望。特别,   “123”== 123需要按顺序为真   不必每次都输入   数字用户输入。

http://bugs.php.net/bug.php?id=48012

这并没有完全回答这个问题,但它指的是大方向。

答案 6 :(得分:1)

PHP是一种松散类型的语言,允许您比较不同类型的值而不会抛出错误,这使得它非常易于使用,但是您发现它可能会导致一些奇怪但合乎逻辑的输出。

你的第一个例子:

if(0=='a'){
    print ord(0)." should NEVER equal ".ord('a')."<br>";
}

当比较两种不同类型的值时,首先通过演员将一个值转换为与另一个相同的类型,然后进行比较。在Int和String的示例中,字符串被转换为Int。当PHP将一个字母变成一个字符串时,它会占用所有第一个数字字符,然后是其余的字符串:即'123123afraa'变为123123,'9a9'变为9.如果字符串不以数字开头,则赋值为0

因此你的例子真的是:0 ===(字符串)'a'实际上是0 === 0因为'a'不是以数字开头的。我认为你期望PHP在ASCII中返回'a'的值,但它没有!这对于清理字符串非常有用,php很少需要处理ascii值,因为它太高了。 (它用于制作网站!)

当将字符串与布尔值进行比较时,值''或'0'为false,则所有其他值均为true。这很有用,因此您可以检查值是否为“空”:

url http://domain.com/?foo=

if($ _GET ['foo']))    {       // 做一点事    }

当一个整数与布尔值比较时,0的值为false,其他值为true,这是非常标准的。

因此,总而言之,您需要了解将不同类型的变量与==运算符进行比较时会发生什么。也许明智的做法是认识到==几乎不是你想要的,使用===(不会对你的值进行类型转换)更安全。

答案 7 :(得分:0)

代码似乎来自单元测试,目的是捕获失败,因此看似奇怪的比较。同样,可以为主单元测试做准备,以确认==运算符是否正常工作 - 应该如此。