故事背景:某天,我在帮另一名同事合并整理代码时候,发现他做了如下操作:
<?php if (!empty($nearCitys = $nearCitys['linkList'])){
//todo
}
?>
这么多年了,我第一次见到这样的写法,或许是自己本身没系统的学习过php的语法和特性,所以猛的一看,以为是有问题的。我的理解是:empty里面是赋值语句,按道理赋值操作一定是true的。会不会实际上程序执行时候变成了如下代码逻辑:
<?php if (!empty(true)){
//todo
}
?>
如果是上面的代码,那empty就失去了判空的意义。当时为了确认这个问题,让同事编写了demo进行试验,发现事实上是我错了。demo如下:
运行结果如下:
通过试验,我们发现实际上变量赋值操作执行之后,empty只是对该变量进行判空,而非是赋值这个操作判空。后来晚上自己仔细回想,觉得自己是白痴了。我们都知道empty现在都是可以判断函数调用返回值了,同样会存在先调用函数,而且函数调用100%成功的问题。想到此,大概就明白了empty里其实,括号里是遵循任何php的优先级特性的。
我们优先把empty这块核心源码贴给大家:
static inline int i_zend_is_true(zval *op)
{
int result;
switch (Z_TYPE_P(op)) {
case IS_NULL:
result = 0; //如果为NULL 返回0
break;
case IS_LONG:
case IS_BOOL:
case IS_RESOURCE:
result = (Z_LVAL_P(op)?1:0); //LONG,BOOL,RESOURCE的值不为空,返回真
break;
case IS_DOUBLE:
result = (Z_DVAL_P(op) ? 1 : 0); //浮点数的值为真 返回真
break;
case IS_STRING://字符型:长度为0或者长度等于一且首地址等于0 返回假
if (Z_STRLEN_P(op) == 0
|| (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) {
result = 0;
} else {
result = 1;
}
break;
case IS_ARRAY://数组:如果数组的个数大于0则为真
result = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
break;
case IS_OBJECT://对象
if(IS_ZEND_STD_OBJECT(*op)) { //是OBJECT
TSRMLS_FETCH();
if (Z_OBJ_HT_P(op)->cast_object) {
zval tmp;
if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_BOOL TSRMLS_CC) == SUCCESS) {
result = Z_LVAL(tmp);
break;
}
} else if (Z_OBJ_HT_P(op)->get) {
zval *tmp = Z_OBJ_HT_P(op)->get(op TSRMLS_CC);
if(Z_TYPE_P(tmp) != IS_OBJECT) {
/* for safety - avoid loop */
convert_to_boolean(tmp);
result = Z_LVAL_P(tmp);
zval_pt