PHP中“===”和“==”
写过PHP的都知道,PHP中的比较操作符“===” 和 “==”是有区别的。不过大多数人只知道: “===”既比较变量的值,又比较变量的类型;而“==”之比较变量的值。
性能
这个说法看似正确,其实是有问题的。PHP中所有的变量都依托于一个叫做zval的结构体。这个结构体的构造大致如下:
typedef struct _zval_struct zval;
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct { /* string type */
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
};
这个结构体,由值、类型、是否有引用和引用计数器构成。那我大致可以推测出,PHP在做值比较的时候,如果是“===”则只比较zval中的value;如果是“==”则除了比较value之外,还要考虑是不是可以做type的转换,并且比较转换后的值。这样一来,实际上“==”的开销会大于“===”的开销,也就是性能较低。那么此时,我们会过去看““===”既比较变量的值,又比较变量的类型;而“==”之比较变量的值。”这句话,其实“==”才是比较了类型(甚至转换了类型),而“===”并不关注类型(或者说只是比较类型是不是一致,不会尝试做转换)。为了证明这一点,我写了如下测试代码:
function compare($num) {
$baseMemory = memory_get_usage();
$now = time();
for ($i = 0; $i < 5 * 10000 * 10000; $i++) {
$num($i);
}
var_dump('==');
var_dump(memory_get_usage() - $baseMemory);
var_dump(time() - $now);
}
function compare2($i) {
$count = 0;
if ($i == true) {
$count++;
}
}
function compare3($i) {
$count = 0;
if ($i == true) {
$count++;
}
}
compare('compare2');
compare('compare3');
// 输出
string(2) "=="
int(176)
int(152)
string(3) "==="
int(144)
int(129)
虽然差距不大,不过确实是‘===’的性能比较好,所以在大的for循环里面,还是比较推荐使用“===”。
坏处
我们在使用“==”的时候,最担心的其实就是如果不比较类型,那么会造成哪些比较奇葩的后果,于是我又找了一些特殊的值来做了比较,这里贴一下代码:
error_reporting(0);
$a = array();
$true_arr = array(
'-1' => -1,
'1' => 1,
'2' => 2
);
$false_arr = array(
'null' => null,
'空字符串' => '',
'下标不存在' => $a['xx'],
'数字0' => 0,
'字符0' => '0',
'空数组' => array(),
'0为除数' => (10 / 0)
);
$zero_arr = array(
'null' => null,
'下标不存在' => $a['xx'],
'空字符串' => ''
);
$one_arr = array(
'浮点1.0' => 1.0,
'字符1.0' => '1.0'
);
out($true_arr, true);
out($false_arr, false);
out($zero_arr, 0);
out($one_arr, 1);
function out($arr, $target) {
echo $target."\r\n\r\n";
foreach ($arr as $key => $v) {
echo $key . ': ';
var_dump($v == $target);
}
echo "=================\r\n\r\n";
}
// 输出
1
-1: bool(true)
1: bool(true)
2: bool(true)
=================
null: bool(true)
空字符串: bool(true)
下标不存在: bool(true)
数字0: bool(true)
字符0: bool(true)
空数组: bool(true)
0为除数: bool(true)
=================
0
null: bool(true)
下标不存在: bool(true)
空字符串: bool(true)
=================
1
浮点1.0: bool(true)
字符1.0: bool(true)
=================
从这个例子,我们可以大致看到,“==”会把数字类型、字符串类型、特殊类型(null等)的变量混在一起,很容易造成与预期不符的结果。