登录  /  注册

php自定义函数返回值的深入实例详解

伊谢尔伦
发布: 2017-06-26 13:32:03
原创
1045人浏览过

函数的返回值

PHP中函数都有返回值,没return返回null

(1)return语句

从Zend/zend_language_parser.y文件中可以确认其生成中间代码调用的是zend_do_return函数。

void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
{
    zend_op *opline;
    int start_op_number, end_op_number;
 if (do_end_vparse) {
        if (CG(active_op_array)->return_reference
                && !zend_is_function_or_method_call(expr)) {
            zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);/* 处理返回引用 */
        } else {
            zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC);/* 处理常规变量返回 */
        }
    }
 
   ...// 省略,取其他中间代码操作
 
    opline->opcode = ZEND_RETURN;
 
    if (expr) {
        opline->op1 = *expr;
 
        if (do_end_vparse && zend_is_function_or_method_call(expr)) {
            opline->extended_value = ZEND_RETURNS_FUNCTION;
        }
    } else {
        opline->op1.op_type = IS_CONST;
        INIT_ZVAL(opline->op1.u.constant);
    }
 
    SET_UNUSED(opline->op2);
}
/* }}} */
登录后复制

生成中间代码为ZEND_RETURN。第一个操作数的类型在返回值为可用的表达式时,其类型为表达式的操作类型,否则类型为IS_CONST。这在后续计算执行中间代码函数时有用到。根据操作数的不同,ZEND_RETURN中间代码会执行ZEND_RETURN_SPEC_CONST_HANDLER,ZEND_RETURN_SPEC_TMP_HANDLER或ZEND_RETURN_SPEC_TMP_HANDLER。这三个函数的执行流程基本类似,包括对一些错误的处理。这里我们以ZEND_RETURN_SPEC_CONST_HANDLER为例说明函数返回值的执行过程:

static int ZEND_FASTCALL  
ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    zend_op *opline = EX(opline);
    zval *retval_ptr;
    zval **retval_ptr_ptr;
 
 
    if (EG(active_op_array)->return_reference == ZEND_RETURN_REF) {
 
        //  ǓǔŷsÁ\ɁƶMļ@ɗÁĻļ
        if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {   
            /* Not supposed to happen, but we'll allow it */
            zend_error(E_NOTICE, "Only variable references \
                should be returned by reference");
            goto return_by_value;
        }
 
        retval_ptr_ptr = NULL;  //  ǓǔŔ
 
        if (IS_CONST == IS_VAR && !retval_ptr_ptr) {
            zend_error_noreturn(E_ERROR, "Cannot return string offsets by 
reference");
        }
 if (IS_CONST == IS_VAR && !Z_ISREF_PP(retval_ptr_ptr)) {
            if (opline->extended_value == ZEND_RETURNS_FUNCTION &&
                EX_T(opline->op1.u.var).var.fcall_returned_reference) {
            } else if (EX_T(opline->op1.u.var).var.ptr_ptr ==
                    &EX_T(opline->op1.u.var).var.ptr) {
                if (IS_CONST == IS_VAR && !0) {
                      /* undo the effect of get_zval_ptr_ptr() */
                    PZVAL_LOCK(*retval_ptr_ptr);
                }
                zend_error(E_NOTICE, "Only variable references \
                 should be returned by reference");
                goto return_by_value;
            }
        }
 
        if (EG(return_value_ptr_ptr)) { //  Ǔǔŷs
            SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);   //  is_refgcőęŒ
            Z_ADDREF_PP(retval_ptr_ptr);    //  refcountgcŒď×1
 
            (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr);
        }
    } else {
return_by_value:
 
        retval_ptr = &opline->op1.u.constant;
 
        if (!EG(return_value_ptr_ptr)) {
            if (IS_CONST == IS_TMP_VAR) {
 
            }
        } else if (!0) { /* Not a temp var */
            if (IS_CONST == IS_CONST ||
                EG(active_op_array)->return_reference == ZEND_RETURN_REF ||
                (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) {
                zval *ret;
 
                ALLOC_ZVAL(ret);
                INIT_PZVAL_COPY(ret, retval_ptr);   //  Ł™ͿʍǓǔŔ 
                zval_copy_ctor(ret);
                *EG(return_value_ptr_ptr) = ret;
            } else {
                *EG(return_value_ptr_ptr) = retval_ptr; //  ħ6ɶŔ
                Z_ADDREF_P(retval_ptr);
            }
        } else {
            zval *ret;
 
            ALLOC_ZVAL(ret);
            INIT_PZVAL_COPY(ret, retval_ptr);    //  Ł™ͿʍǓǔŔ 
            *EG(return_value_ptr_ptr) = ret;    
        }
    }
 
    return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);   //  Ǔ
ǔĉˆșʒ
}
登录后复制

函数的返回值在程序执行时存储在*EG(return_value_ptr_ptr)。ZEND内核对值返回和引用返回作了区别,并且在此基础上对常量,临时变量和其他类型的变量在返回时作了不同的处理。在return执行完之后,ZEND内核通过调用zend_leave_helper_SPEC函数,清除函数内部使用的变量等。这也是ZEND内核自动给函数加上NULL返回的原因之一。

以上就是php自定义函数返回值的深入实例详解的详细内容,更多请关注php中文网其它相关文章!

智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
关于CSS思维导图的课件在哪? 课件
凡人来自于2024-04-16 10:10:18
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2024 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号