Home  >  Article  >  Backend Development  >  Detailed explanation of in-depth examples of PHP custom function return values

Detailed explanation of in-depth examples of PHP custom function return values

伊谢尔伦
伊谢尔伦Original
2017-06-26 13:32:031176browse

The return value of the function

The functions in PHP all have return values, and no return returns null

(1)return statement

From Zend It can be confirmed in the /zend_language_parser.y file that the intermediate code generated calls the zend_do_return function.

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);
}
/* }}} */

The generated intermediate code is ZEND_RETURN. When the return value is an available expression, the type of the first operand is the operation type of the expression, otherwise the type is IS_CONST. This is useful when subsequent calculations execute intermediate code functions. Depending on the operands, the ZEND_RETURN intermediate code will execute ZEND_RETURN_SPEC_CONST_HANDLER, ZEND_RETURN_SPEC_TMP_HANDLER or ZEND_RETURN_SPEC_TMP_HANDLER. The execution flows of these three functions are basically similar, including the handling of some errors. Here we take ZEND_RETURN_SPEC_CONST_HANDLER as an example to illustrate the execution process of the function return value:

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);   //  Ǔ
ǔĉˆșʒ
}

The return value of the function is stored in *EG(return_value_ptr_ptr) when the program is executed. The ZEND kernel makes a distinction between value return and reference return, and on this basis, constants, temporary variables and other types of variables are treated differently when returned. After return is executed, the ZEND kernel clears the variables used inside the function by calling the zend_leave_helper_SPEC function. This is one of the reasons why the ZEND kernel automatically adds NULL returns to functions.

The above is the detailed content of Detailed explanation of in-depth examples of PHP custom function return values. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn