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等)的变量混在一起,很容易造成与预期不符的结果。

总结

引用最经典的一句话:别用“==”除非你知道你在做什么。


附上代码