技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> PHP --> PHP数据类型隐性转换的陷阱

PHP数据类型隐性转换的陷阱

浏览:2828次  出处信息

之前写过一篇《PHP的动态特性》总结了部分PHP的特性,因为动态语言的特性,我们使用PHP时倍感便利,但是便利的同时会引来一些陷阱,不得不防。

我这里说的是php5+上跑的,php4的请飘过。

先把错误报告打开,以防看不到错误信息
<?php
error_reporting(E_ALL);
ini_set('display_errors', true);
?>

根据php manual 中 http://www.php.net/manual/zh/language.operators.comparison.php
“Comparison Operators” 一章的说明可知,number 和string进行比较的时候,会先将string类
型首先转化为number,然后再进行比较操作。

1.类型自动转换为数组
当我们把一个非数组的变量当做数组来调用的时候,该变量在调用时数据类型临时自动转换成数组。
例如如下代码:
<?php
$str = 'string';
var_dump($str['aaa']);  // string(1) "s"
var_dump($str);  // string(6) "string"

if($str['aaa'] === $str[0]) {
    print "===";
}
?>

如下例子可以明显的看出下标类型自动转换在发生。
<?php 
$link = '<a href="http://yulans.cn">yulans</a>'
$key = '1-10'; 
echo "$link[$key]\n";  // 同 $link[1]
echo "{$link[$key]}\n";  // 同 $link[1]
//echo "$link['$key']\n";  // 报错
echo "{$link['$key']}\n";  // 同 $link[0]
?> 

这里字符串在 var_dump($str['aaa']) 被临时转换成了数组 array('s','t','r','i', 'n','g'),而用关联数组方式
$str['aaa']读取索引数组的值,关联数组的下标'aaa'将被转换成整形下标,
因而在这里的$str['aaa']全等于$str[0]。

其他数据类型隐性转换成数组也隐藏有陷阱,一般都不是报出undefined index错误。举例如下代码:
<?php
/**
 * 测试变量隐性转换成数组
 *
 * @param mixed $param
 */
function test2Arr($param) {
    var_dump($param['abc']);
}

test2Arr(false); // NULL
test2Arr(123); // NULL
test2Arr(123.456); // NULL
test2Arr('string'); // string(1) "s"
test2Arr(array('abc'=>'text'));  // string(4) text
test2Arr(new ArrayObject()); // Notice: undefined index: abc

?>

解决办法:
函数参数数据类型是数组的时候,防止用户输入字符串导致错误
如下例子,当添加用户的时候,我们要求用户必须输入用户名。没有哪个SB把要求是数组的参数传入
字符串,但是防人之心不可无,说不定我连续工作超过十几个小时后一不小心就成那个SB了,又或许
某人想绕过代码执行操作。
<?php
/**
 * 添加用户(错误的写法)
 *
 * @param array $user
 */
function addUser($user) {
    if(empty($user['name'])) {  // 这里当输入类型是不为空的字符串的时候会出错,
        echo "用户名必填\n";
        return false;
    }

    // do sth.

    echo "测试\n";

    return true;
}

/**
 * 添加用户(正确的写法)
 *
 * @param array $user
 */
function addUser2($user) {
    if(!is_array($user) || empty($user['name'])) {
        echo "用户名必填\n";
        return false;
    }

    // do sth.

    echo "测试\n";

    return true;
}

$user = 'xiaoxiao';
addUser($user);
addUser2($user);


?>


2.纯数字字符串比较时自动转换成整形超过范围时发生溢出
<?php
$x1 = '111111111111111111';
$x2 = '111111111111111112';

echo ($x1 === $x2) ? "true" : "false";  // false 如我们所愿,这两个字符串确实不一样。
echo ($x1 == $x2) ? "true" : "false";    // true 这里被偷偷的转换类型了,
                                                           // 成了 echo (intval($x1) == intval($x2)) ? "true" : "false"; 整形溢出

?>


3、整形和字符串比较时数据类型隐性转换有可能发生问题
<?php
$number = 0;
$string = 'text';

if($number == $string) {
    print "true";
} else {
    print "false";
}

?>

很遗憾这里输出的是 true
我们知道 $number === $string 肯定是false,手册上说 === 是比较值&&数据类型,而用 == 只是比较值,
$number == $string 这里不是比较值吗? '0' 和 'text' 明显不一样啊。小心了,这里的$string是
先被秘密转成和$number一样的整形再比较的,$number == (int)$string的确是true


4. in_array 小陷阱
<?php

var_dump(in_array(0, array('s')));  // true

?>
因为in_array会将0 和's' 进行比较,0是number类型,'s'是string类型, 's'转化为number的结果为0,
而0 == 0 的结果是true,所以in_array(0, array('s', 'ss'))的结果也是true

如果把in_array 的第三个参数strict设置为 true,比较的时候 就会判断值和类型是否都相当。
如果都相当的话,才会返回true,否则返回false.

建议继续学习:

  1. STRUTS2类型转换错误导致OGNL表达式注入漏洞分析    (阅读:8904)
  2. JavaScript性能陷阱    (阅读:3092)
  3. Java陷阱(2010版)    (阅读:3005)
  4. javascript运算/转换技巧    (阅读:2668)
  5. 移动互联网系统架构十大陷阱    (阅读:2575)
  6. JavaScript ( (__ = !$ + $)[+$] + ({} + $)[_/_] +({} + $)[_/_] )    (阅读:2549)
  7. 编写安全代码:再论整数类型转换    (阅读:2498)
  8. 类型转换-无处不在的陷阱    (阅读:2135)
  9. 弱类型?C语言参数提升带来的一个陷阱    (阅读:2104)
  10. PHP类型转换相关的一个Bug    (阅读:1918)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1