PHP中的两个等号与三个等号

源起

四脚猫每日一题里有这么一道题目:不运行,分析下以下PHP代码输出结果是多少? 为什么会这样?

1
2
3
4
$items = array(0=>1,"aa"=>2, 3, 4);
foreach($items as $key=>$val){
print($key == "aa" ? 5 : $val);
}

如果答案是1534的话就掉入陷阱了,关于该题的详细说明在http://blog.sijiaomao.com/?p=829已经有了,关键var_dump(0 == "aa");是true的,本文主要说明下null bool string number之间两个等号之间的关系。

提问

如果下面的问题回答都能回答正确的话,也就基本可以忽略这篇文章了。。

1
2
3
4
5
6
7
8
var_dump(null == false);
var_dump(false == '');
var_dump('' == 0);
var_dump(0 == null);
var_dump(1 == true);
var_dump(true == 'a');
var_dump(1 == 'a');

答案是前六个是true,最后一个是false。故意分成前四个和后三个是有原因的,前是个正好涉及到null bool string number 四种类型,并且看上去那四个值是等价的。后面三个1是和true相等的,true是和’a’相等的,但是1和’a’是不等的,之间是没有’传递律‘的。

1
2
3
4
5
6
7
8
var_dump(null == false);//bool(true)
var_dump(false == '');//bool(true)
var_dump('' == 0);//bool(true)
var_dump(0 == null);//bool(true)
var_dump(1 == true);//bool(true)
var_dump(true == 'a');//bool(true)
var_dump(1 == 'a');//bool(false)

详解

在PHP手册中有这么一张图,它比较清晰的展示了不同类型之间的比较运算。

图片

null PK string

var_dump(null == '') null转换为string类型中的空字符串”。

null PK number

var_dump(null == 0) 这时候null和0都要转为bool类型,都为false,所以是相等的。

string PK number

string与number进行等于号判断的时候,string转为number类型。空字符”串转换为数字0,’1′转为1,’1abc’转为1。’a’转为0,所以var_dump(1 == 'a')也就是false了。

null string number PK bool

等号的一边是bool类型时都会将另一边转换为bool类型,然后进行bool类型的判断。如null转为false,”或‘0’字符串转为false,数字0转为false。

经历

最近在修改防攀爬系统BUG中正好遇到了这样的问题,在模块管理的搜索页中,当下拉选择全部、心跳、故障、报警的时候都能够保持下拉状态,并且根据条件搜索出来的结果也是正确的,唯独“未知”出来的结果是全部的。这也就纳闷了,按照思路,从C到V,看到“最后联系事件”的<selest></select>下拉选项中all表示全部,0表示未知,1表示心跳,2表示故障,3表示报警。POST至controller中,调用model,看到原来在给变量赋值之前有一个if语句

1
2
3
4
5
6
if ($this->input->post('node_msg_type')) {
$this->session->set_userdata('node_msg_type', $this->input->post('node_msg_type'));
$msg_type = $this->input->post('node_msg_type');
} else{
$this->session->unset_userdata('node_msg_type');
}

正是这个if语句的问题,当下拉选择“未知”的时候,node_msg_type的值为数字0,这样的话if是不成立的,进入了else,也就导致了$msg_type变量未赋值,当然select出来的也就不是为0的了。

结语

由于PHP是弱类型语言,有的不同类型之间的比较是可以的,并不会给出类型不一致不能比较的错误。两个等号是判断两个变量的值是否相等,三个等号是值相等并且变量的类型也相等。其它也有一些需要注意的地方,比如PHP中的变量名是区分大小写的,而类名和函数名是不区分的。


参考资料:

Just a beginner.<br /><a href='https://github.com/yaoshanliang/about' target='_blank'>profile</a>