switch语句中的奇怪行为

Gor*_*onM 7 php switch-statement

我正在为可排序的表编写代码,其中单击标题中的链接会更改生成一组搜索结果时执行的ORDER BY(如果没有有效的顺序,则导致查询不按顺序运行然后按照数据库返回的顺序返回结果.这是设计的).代码是在我的雇主提供的框架内编写的.

要验证查询的ORDER BY部分,我通过以下验证函数运行输入.

<?php
function sortMode ($name)
{
    $mode   = '';
    switch ($name)
    {
        case 'resnum'   : $mode = 'b_resnum';            break;
        case 'state'    : $mode = 'st_id';               break;
        case 'name'     : $mode = 'lastname, firstname'; break;
        case 'phone'    : $mode = 'phone';               break;
        case 'email'    : $mode = 'email';               break;
        case 'opened'   : $mode = 'cs_created';          break;
        default         : $mode = '';                    break;
    }
    return ($mode);
}
?>
Run Code Online (Sandbox Code Playgroud)

在测试中,我发现如果没有提供参数,那么排序顺序将是resnum.经过一些实验,我发现框架中内置的过滤会导致请求未初始化的变量(如未设置的GET参数)返回整数0.如果上面的代码被输入一个0整数作为其输入,它将始终跟随第一个可用的执行路径.

作为一个实验,我尝试在switch语句中重新排列case的顺序,并发现如果该函数传递0,那么顶部的任何内容都将被执行.

该问题的解决方案是使用switch (strval($name))所以特定问题得到解决,但现在我很好奇PHP开关语句的一般行为.我亲眼目睹了PHP的正确行为吗?PHP中是否存在导致此问题的错误,或者我在我不知道的代码中出错?

rye*_*guy 12

这是因为php将字符串转换为int的方式.传入a时0,您要求它进行整数比较,因此它会将所有案例键转换为整数.当php将a转换为a stringint,它会在字符串的开头查找实际数字,然后将数字吞噬,直到它达到非数字为止.由于字符串"resnum"没有数字,因此返回0.请参见此处:

php > echo (int)"100";
100
php > echo (int)"300 dogs";
300
php > echo (int)"resnum";
0
php > echo (int)"resnum 100";
0
Run Code Online (Sandbox Code Playgroud)

由于所有这些字符串转换为0,第一种情况将评估为true0 == 0.

资源:
字符串转换为数字
类型比较表


Nitpick时间.当您执行将字符串映射到字符串的简单case语句时,请使用数组.它更清晰,实际上更快:

function sortMode ($name)
{
    $modeMap = array(
        'resnum'   => 'b_resnum',
        'state'    => 'st_id',
        'name'     => 'lastname, firstname',
        'phone'    => 'phone',
        'email'    => 'email',
        'opened'   => 'cs_created'
    );

    return isset($modeMap[$name]) ? $modeMap[$name] : '';
}
Run Code Online (Sandbox Code Playgroud)

如果$name在映射中设置了,则返回键映射到的值.否则,我们返回一个空字符串,取代default案例.

作为奖励,如果您使用上述方法,您会更早地注意到该错误,因为它会尝试访问$modeMap[0]并且会返回您的默认情况.