代码之家  ›  专栏  ›  技术社区  ›  rook

非常不合逻辑的php值比较

php
  •  12
  • rook  · 技术社区  · 14 年前

    <?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 回复  |  直到 14 年前
        1
  •  33
  •   rook    14 年前

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

    这很有用,因为PHP主要用于处理文本,可能需要尝试测试(123=='123'),这是正确的。如果将单引号(或双引号)中的数字视为数字,则将没有数值的字符串视为0以外的任何值是没有意义的。

    哦,是的,还有一件事布尔上下文中的“a”是true,而不是false。我相信这会使某些类型的文本处理更自然,但老实说,我想不出一个例子在这么晚的时间。

        2
  •  8
  •   Jacob Relkin    14 年前

    嗯,总有 PHP type cheat sheet 为了这个!

        3
  •  7
  •   Community dbr    7 年前

    这是称为 type juggling

    There are rules for every type 至于它将如何被铸造成另一种类型 compares 其他类型。 'a' 0 == identity operator === .

    作为 James pointed out ,这是很有用的,因为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) .

        4
  •  3
  •   Ignacio Vazquez-Abrams    14 年前

    ord() 接受字符,所以PHP 0 '0' . 以及 0 false ,即使它不完全相同( === ).

        5
  •  1
  •   Shabbyrobe    14 年前

    看看PHP type comparison tables

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

    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,则上面的代码将永远不会打印“It was zero!”。程序员需要负责处理从数据库中输出的值的类型。对于松散类型的语言,这是不可取的。

    包括类型在内的严格相等是使用“is really,truely,town to god equals to”操作符进行测试的,该操作符由符号“==”表示。

        6
  •  1
  •   George Marian    14 年前

    我看不出('a'==0)有什么帮助

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

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

    扩展:

    进一步扩展:

    我以为手册中有一个很好的例子,但是我没有找到它。我所看到的应该有助于阐明这种“不合逻辑”的情况。

    PHP首先是一个Web 语言,不是通用的 我不得不做些小事 人们所期待的。明确地, “123”==123需要依次为真 不必把每一个字都打出来 数字用户输入。

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

    这并不能完全回答问题,但它指向了大方向。

        7
  •  1
  •   Michael Parkin    14 年前

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

    你的第一个例子:

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

    因此,您的示例实际上是:0===(字符串)“a”,实际上是0===0,因为“a”不是以数字开头的。我认为您希望PHP以ASCII格式返回'a'的值,而实际情况并非如此!这对于清理字符串非常有用,php很少需要处理ascii值,因为它的级别太高了(它是用来制作网站的!)

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

    网址 http://domain.com/?foo=

    如果($\u GET['foo'])) { //做点什么

    当一个整数与一个布尔值比较时,0的值为假,其他值为真,这是相当标准的。

    所以,总而言之,您需要了解当不同类型的变量与==运算符进行比较时会发生什么。另外,明智的做法可能是意识到==几乎从来不是您想要的,使用===(它不会对您的值进行类型转换)更安全。

        8
  •  0
  •   bcosca    14 年前

    密码似乎来自一个 为了抓住失败,于是出现了看似怪异的比较。同样的道理,它也可以在主单元测试前进行准备,以确认==操作符正常工作。