Maison  >  Article  >  développement back-end  >  Explication détaillée d'exemples approfondis de valeurs de retour de fonctions personnalisées PHP

Explication détaillée d'exemples approfondis de valeurs de retour de fonctions personnalisées PHP

伊谢尔伦
伊谢尔伦original
2017-06-26 13:32:031176parcourir

La valeur de retour de la fonction

Les fonctions en PHP ont toutes des valeurs de retour, et aucun retour ne renvoie null

(1) instruction de retour

Depuis Zend Il peut être confirmé dans le fichier /zend_lingual_parser.y que le code intermédiaire généré appelle la fonction 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);
}
/* }}} */

Le code intermédiaire généré est ZEND_RETURN. Le type du premier opérande est le type d'opération de l'expression lorsque la valeur de retour est une expression utilisable, sinon le type est IS_CONST. Ceci est utile lorsque les calculs ultérieurs exécutent des fonctions de code intermédiaires. Selon les opérandes, le code intermédiaire ZEND_RETURN exécutera ZEND_RETURN_SPEC_CONST_HANDLER, ZEND_RETURN_SPEC_TMP_HANDLER ou ZEND_RETURN_SPEC_TMP_HANDLER. Les flux d’exécution de ces trois fonctions sont fondamentalement similaires, y compris la gestion de certaines erreurs. Ici, nous prenons ZEND_RETURN_SPEC_CONST_HANDLER comme exemple pour illustrer le processus d'exécution de la valeur de retour de la fonction :

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

La valeur de retour de la fonction est stockée dans *EG(return_value_ptr_ptr) lorsque le programme est exécuté. Le noyau ZEND fait une distinction entre le retour de valeur et le retour de référence, et sur cette base, les constantes, variables temporaires et autres types de variables sont traitées différemment lorsqu'elles sont renvoyées. Une fois return exécuté, le noyau ZEND efface les variables utilisées dans la fonction en appelant la fonction zend_leave_helper_SPEC. C'est l'une des raisons pour lesquelles le noyau ZEND ajoute automatiquement des retours NULL aux fonctions.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn