在foreach中切换的bug

时间:2013-12-30 14:11:02

标签: php foreach switch-statement

这是我遇到问题的代码 - 简单的foreach迭代数组。有时来自数组的元素可以具有键“mailto” - 在这种情况下它应该执行一些任务。但由于某种原因,带有“0”键的第一个元素也会进入“mailto”案例。

<?php
    foreach (
        array(
            " this shouldnt appear, it's without mailto as key - 1",
            " this shouldnt appear, it's without mailto as key - 2",
            "mailto" => " this should appear ",
            " this shouldnt appear, it's without mailto as key - 3",
        ) as $type => $text
    ) {
        echo "#$type#\n";
        switch ($type) {
            case "mailto":
                echo ">$type< $text\n";

                break;

            default:
                break;
        }

    }

输出:

#0#
>0<  this shouldnt appear, it's without mailto as key - 1
#1#
#mailto#
>mailto<  this should appear 
#2#

为什么会出现第一个元素?

5 个答案:

答案 0 :(得分:5)

正如其他答案所指出的那样:switch按值进行比较,它不会进行类型&amp;价值比较。字符串常量== 0计算结果为true的事实只是PHP奇怪/怪癖中的一个,我猜。这就是说:您可以使用“真实”,硬编码密钥,也可以使用演员:

foreach($theArray as $type => $text)
{
    echo "#$type#\n";
    switch ((string) $type)
    {//cast key to string
        case "mailto":
            echo ">$type< $text\n";
            break;
        default:
            break;
    }
}

完成工作。
也就是说,你真的不需要连接你回声的字符串。事实上,it's better not to。我只是将值作为逗号分隔的常量+变量回显:

echo '#', $type, '#', PHP_EOL;// use X-platform constant
switch ((string) $type)
{
    case 'mailto':
        echo '>', $type, '< ', $text, PHP_EOL;
        break;
}

略微更快

答案 1 :(得分:2)

您的switch语句正在进行==比较,这意味着php将字符串mailto类型转换为等于0的整数。因此case语句的计算结果为true。

由于您只使用一个值,请将其更改为if语句并使用严格比较===

答案 2 :(得分:1)

使用switch/case相等运算符实现==构造。

现在,如果你试试这个:

>> "mailto" == 0
true
>> "mailto" == 1
false
>>

你可以看到PHP是如何做错的 对于相等性测试,“mailto”被转换为整数值0。

答案 3 :(得分:0)

通过在switch语句中添加另一个案例,似乎可以很容易地修复它,如下所示:

switch ($type) 
{
    case 0:
        break;
    case 'mailto':
        echo ">$type< $text\n";
        break;
    default:
        break;
}

我怀疑将0与'mailto'进行比较的问题正确与PHP的松散类型比较有关。当您将整数与PHP中的字符串进行比较时只有两个等号(==)时,它将返回true。

强制比较作为字符串完成的另一个修复,因此避免添加这个额外的情况是将$ type转换为字符串,如下所示:

switch ((string) $type) 
{
    case 'mailto':
        echo ">$type< $text\n";
        break;
    default:
        break;
}

答案 4 :(得分:0)

问题是==switch()的非类型比较导致0=="mailto"为真。

如果您需要添加其他case语句并希望保留原始结构,则可以强制第一个键为1,并避免出现问题。

foreach (
    array(
        1=>" this shouldnt appear, it's without mailto as key - 1", 
        " this shouldnt appear, it's without mailto as key - 2",
        "mailto" => " this should appear ",
        " this shouldnt appear, it's without mailto as key - 3",
    ) as $type => $text
) {

否则,只需使用严格比较===

切换到简单
foreach (
    array(
        " this shouldnt appear, it's without mailto as key - 1",
        " this shouldnt appear, it's without mailto as key - 2",
        "mailto" => " this should appear ",
        " this shouldnt appear, it's without mailto as key - 3",
    ) as $type => $text
) {
    echo "#$type#\n";
    if($type === 'mailto'){
            echo ">$type< $text\n";
    }
}