我正在编写可排序表的代码,其中单击标题中的链接会更改生成一组搜索结果时执行的ORDER BY(如果没有有效顺序,则导致查询无法运行)使用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);
}
?>
在测试中,我发现如果没有提供参数,那么排序顺序将是resnum。经过一些实验,我发现框架中内置的过滤会导致请求未初始化的变量(如未设置的GET参数)返回整数0.如果上面的代码被输入一个0整数作为其输入,它将始终跟随第一个可用的执行路径。
作为一个实验,我尝试在switch语句中重新排列案例的顺序,并发现如果此函数传递了0,那么顶部的任何内容都将被执行。
问题的解决方案是使用switch (strval($name))
因此解决了特定问题,但现在我对PHP switch语句的一般行为感到好奇。我亲眼目睹了PHP的正确行为吗? PHP中是否存在导致此问题的错误,或者我在我不知道的代码中出错?
答案 0 :(得分:12)
这是因为php将字符串转换为int的方式。传入0
时,您要求它进行整数比较,因此它会将所有案例键转换为整数。当php将string
强制转换为int
时,它会在字符串的开头查找实际数字,然后吞噬该数字直到它遇到非数字。由于字符串“resnum”没有数字,因此返回0.请参见此处:
php > echo (int)"100";
100
php > echo (int)"300 dogs";
300
php > echo (int)"resnum";
0
php > echo (int)"resnum 100";
0
由于所有这些字符串都被强制转换为0,因此第一种情况将从true
开始评估为0 == 0
。
<强>资源:强>
String conversion to numbers
Type comparison tables
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] : '';
}
如果在地图中设置了$name
,我们将返回键映射到的值。否则,我们返回一个空字符串,取代default
case。
作为奖励,如果您使用上述方法,您会早先注意到该错误,因为它会尝试访问$modeMap[0]
并且会返回您的默认情况。
答案 1 :(得分:0)
关键是switch()语句执行参数和标签之间的比较。这意味着您必须处理PHP比较和类型转换规则。只看一些例子:
<?php
var_dump( ''==0 ); // bool(true)
var_dump( 'foo'==0 ); // bool(true)
var_dump( '0'==0 ); // bool(true)
var_dump( '0m'==0 ); // bool(true)
var_dump( '01'==0 ); // bool(false)
参考资料可在以下网址找到:
将未设置的GET参数初始化为0是一个非常奇怪的设计决策。您应该以单独的方式处理该特定情况,以明确这是一种特殊情况:
if( $name===0 ){
return '';
}
switch($name){
// ...
}