PHP开发中常见的坑
PHP开发中常见的坑
1、switch/case
使用 switch 语句可以避免冗长的 if..elseif..else 代码块。但是一不小心,就会掉坑里。
1)当case为一个范围时
使用 0 < $num < 50,这种方式是不可以的,所以要用 0 < $num && $num < 50的方式,拆开写才可以
1 <?php 2 $a = 89; 3 switch ($a) { 4 case ($a < 60): 5 echo '不及格'; 6 break; 7 case ($a < 80): 8 echo '中等'; 9 break; 10 case ($a < 90): 11 echo '良'; 12 break; 13 default: 14 echo '优秀'; 15 break; 16 } 17 18 // 输出结果 19 // 良
2)当switch表达式中的值为0
1 <?php 2 $a = 0; 3 switch ($a) { 4 case ($a < 60): 5 echo '不及格'; 6 break; 7 case ($a < 80): 8 echo '中等'; 9 break; 10 case ($a < 90): 11 echo '良'; 12 break; 13 default: 14 echo '优秀'; 15 break; 16 } 17 // 输出结果 18 // 优秀
这个地方,如果按照if...else的思维,满足第一个case语句,然后直接输出:不及格。但是实际情况输出的是:优秀
分析:switch/case跟if...else条件语句的区别是,switch表达式的值是与case语句中的值作匹配的,并不是像if条件中的只要是true就执行
php里面的switch会转换case类型,使用的时候一定要注意。
3)switch/case作的是松散比较
1 <?php 2 $string = "2string"; 3 4 switch ($string) { 5 case 1: 6 echo "this is 1"; 7 break; 8 case 2: 9 echo "this is 2"; 10 break; 11 case '2string': 12 echo "this is a string"; 13 break; 14 } 15 16 // 输出结果 17 // this is 2
注意:
1) switch中使用“==”进行比较的时候,尤其是string和int值比较时,会将字符串强转为int类型
2) 在使用switch的时候,应该保证比较值和每个case的类型一致,否则就可能出现不可预计的错误
2、in_array
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
说明:在 haystack 中搜索 needle,如果没有设置 strict 则使用 宽松 的比较。如果第三个参数 strict 的值为 true,则 in_array 函数还会检查 needle 的 类型 是否和 haystack 中的相同。
1 <?php 2 3 $arr = [0, 1]; 4 $a = '1test'; 5 if (in_array($a, $arr)) { 6 echo 111; 7 } else { 8 echo 222; 9 } 10 11 // 输出结果 12 // 111
可以看到,这里$a = ‘1test’,在校验过程中,$a由字符串转成了int类型,绕过了in_array中的校验。
解决方法有三种:
1)将参数$a类型转换成整型: $a=(int)$a;
2)in_array中的数组内value改成字符串类型:in_array($a,['1','2'])
3)in_array中第三个参数 strict 的值设为 true:in_array($a,[1,2],true)
1 <?php 2 3 $arr = [0, 1]; 4 $a = '1a'; 5 if (in_array($a, $arr,true)) { 6 echo 111; 7 } else { 8 echo 222; 9 } 10 11 // 输出结果 12 // 222
另外,补充一下,关于字符串/字符和数字进行大小比较时,会将字符串转成数字,
1)PHP 8.0 之前,首先系统尝试将此字符串/字符转换为整型/浮点型,然后进行比较,如'12bsd'转型为12,'a'转型为0
2)PHP 8.0 比较数字字符串(numeric string)时,会按数字进行比较。 不是数字字符串时,将数字转化为字符串,按字符串比较。
1 <?php 2 3 // PHP 7 4 0 == 'foobar'; // true 5 6 // PHP 8 7 0 == 'foobar';// false
3、关于if else容易迷惑的问题
1 <?php 2 $a = true; 3 if ($a) { 4 echo "true".PHP_EOL; 5 } else label: { 6 echo "false"; 7 } 8 9 // 输出结果 10 // true 11 // false
在zend_language_parser.y中:
1 statement: 2 ... 3 | T_DO statement T_WHILE '(' expr ')' ';' {...} 4 | T_SWITCH '(' expr ')' switch_case_list {...} 5 | T_STRING ‘:’ { $$ = zend_ast_create(ZEND_AST_LABEL, $1); }
这里可以看到,do while, switch 都会联合他们的body归约为statement(语句),但标签(label)有点不同,”label :”本身会归约为一条statement, 这就导致了这个看起来比较迷惑的问题的出现,他本质上就变成了:
1 <?php 2 $a = true; 3 if ($a) { 4 echo "true".PHP_EOL; 5 } else { 6 label: ; //单独的一条语句 7 } 8 echo "false"; 9 10 // 输出结果 11 // true 12 // false
参考链接:https://www.laruence.com/2020/07/09/6015.html