技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 源码分析 --> PHP empty和isset源码分析

PHP empty和isset源码分析

浏览:1164次  出处信息

被问到php的empty(0)、empty(0.0)、empty('0')、empty('0.0')和empty('00')分别返回什么,对于正常的empty()手册里描述自己也是非常清楚了:

""、0、"0"、NULL、FALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果 var 为空,则返回 TRUE。

但就在empty('00')的时候疑惑了一下,因为在我的理解体系里,empty()把'0'转换成数字判断了,所以会返回true,那'00'也会转换吗?在没有实践的情况下,当时就机智的自己思考了一下觉得'00'返回是false,理由是'00'不会转换成数字,又是非空字符串,所以为false。

因为不确定,搜了一下google也没人研究这个简单的问题,只能自己扒了。先写了一个php

<?php
empty($a);
isset($a);

发现opcode:

2 0 E > ISSET_ISEMPTY_VAR 293601280 RES[ IS_TMP_VAR ~0 ] OP1[ IS_CV !0 ] OP2[ IS_UNUSED ]
1 FREE OP1[ IS_TMP_VAR ~0 ]
3 2 ISSET_ISEMPTY_VAR 310378496 RES[ IS_TMP_VAR ~1 ] OP1[ IS_CV !0 ] OP2[ IS_UNUSED ]
3 FREE OP1[ IS_TMP_VAR ~1 ]
4 4 > RETURN OP1[ IS_CONST (128414056) 1 ]

均调用了:ISSET_ISEMPTY_VAR , 然后去zend源码顺藤摸瓜的找到这个op执行的是ZEND_ISSET_ISEMPTY_VAR(zend_vm_opcodes.c),
然后找到ZEND_ISSET_ISEMPTY_VAR实际到execute的时候执行的是ZEND_ISSET_ISEMPTY_VAR_xxx(zend_vm_execute.h)等一系列函数,通过源码阅读发现判断变量是否为空的最终执行函数是:i_zend_is_true(),
最终找到定义的地方:zend_execute.h:static zend_always_inline int i_zend_is_true(zval *op);
具体代码如下:

static zend_always_inline int i_zend_is_true(zval *op)
{
        int result;
   
        switch (Z_TYPE_P(op)) {
                case IS_NULL:
                        result = 0;
                        break;
                case IS_LONG:
                case IS_BOOL:
                case IS_RESOURCE:
                        result = (Z_LVAL_P(op)?1:0);
                        break;
                case IS_DOUBLE:
                        result = (Z_DVAL_P(op) ? 1 : 0);
                        break;
                case IS_STRING:
                        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:
                        result = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
                        break;
                case IS_OBJECT:
                        if(IS_ZEND_STD_OBJECT(*op)) {
                                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_ptr_dtor(&tmp);
                                                break;
                                        }
                                }
                        }
                        result = 1;
                        break;
                default:
                        result = 0;
                        break;
        }
        return result;
}


很简单的代码,这下清楚了,empty()对检测值没有进行任何转换,只是在检测string的时候多了一个“补丁”操作(我理解的):

empty()在判断字符串的时候首先判断长度是否为0,是则返回0,否则判断是否长度为1且该字符为'0',是则返回0;其他情况返回1;

至于isset(),在判断出变量未赋值时就返回了,也没执行到i_zend_is_true()函数。

建议继续学习:

  1. empty 和 isset的区别和联系    (阅读:2025)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1