Maison  >  Article  >  développement back-end  >  Explication détaillée de l'utilisation de l'instruction de retour de la valeur de retour PHP

Explication détaillée de l'utilisation de l'instruction de retour de la valeur de retour PHP

伊谢尔伦
伊谢尔伦original
2017-06-27 09:32:264459parcourir

Dans le langage de programmation , une fonction ou une méthode renvoie généralement une valeur, mais il existe également des situations où elle ne renvoie pas de valeur. À l'heure actuelle, ces fonctions ne traitent que certaines transactions et ne le font pas. return, ou en d'autres termes Il n'y a pas de valeur de retour explicite, il a une procédure de mot-clé propriétaire en langage Pascal. En PHP, les fonctions ont des valeurs de retour, qui peuvent être divisées en deux situations : utiliser une instruction return pour renvoyer explicitement et renvoyer NULL sans instruction return.

instruction return

Lors de l'utilisation de l'instruction return, PHP renvoie une variable du type spécifié à la fonction définie par l'utilisateur. De la même manière que nous visualisons le code source, après avoir effectué une analyse lexicale et une analyse syntaxique sur le mot-clé return, nous générons du code intermédiaire. A partir du fichier Zend/zend_lingual_parser.y, il peut être confirmé 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) {         //  返回引用时不允许常量和临时变量
       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)) { //  返回引用
           SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);   //  is_refgc设置为1
           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; //  直接赋值
               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 ZE fait la distinction entre le retour de valeur et le retour de référence, et sur cette base, les constantes, les variables temporaires et les autres types de variables sont traitées différemment lorsqu'elles sont renvoyées. Avant que le retour ne soit exécuté, le noyau ZE 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 ZE ajoute automatiquement des retours NULL aux fonctions.

Fonction sans instruction de retour

En PHP, il n'y a pas de notion de procédure, seulement des fonctions sans valeur de retour. Mais pour les fonctions qui n'ont pas de valeur de retour, le noyau PHP "vous aidera" à ajouter un NULL comme valeur de retour. Cette opération « vous aider » est également effectuée lors de la génération du code intermédiaire. La fonction zend_do_end_function_declaration doit être exécutée lors de l'analyse de chaque fonction. Il y a une instruction dans cette fonction :

zend_do_return(NULL, 0 TSRMLS_CC);

Combinée avec le contenu précédent, nous savons que la fonction de cette instruction est de renvoyer NULL. C'est pourquoi les fonctions sans instruction return renvoient NULL.

La valeur de retour de la fonction interne est passée via une variable nommée return_value. Cette variable est également un paramètre de la fonction, visible après le développement de la fonction PHP_FUNCTION. Ce paramètre contient toujours un conteneur zval avec un espace pré-alloué, vous pouvez donc accéder directement à ses membres et les modifier sans exécuter au préalable la macro MAKE_STD_ZVAL sur la valeur de retour. Afin de renvoyer plus facilement les résultats des fonctions et d'éviter d'avoir à accéder directement à la structure interne du conteneur zval, ZEND fournit un large ensemble de macro-commandes pour effectuer ces opérations associées. Ces macros définissent automatiquement le type et la valeur.

Macros qui renvoient des valeurs directement à partir des fonctions :

RETURN_RESOURCE(resource) renvoie une ressource.

RETURN_BOOL(bool) Renvoie une valeur booléenne.

RETURN_NULL() renvoie une valeur nulle.

RETURN_LONG(long) Renvoie un entier long.

RETURN_DOUBLE(double) Renvoie un nombre à virgule flottante double précision.

RETURN_STRING(string, duplicate) renvoie une chaîne. duplicate indique si ce caractère est copié à l'aide de estrdup().

RETURN_STRINGL(string, length, duplicate) renvoie une chaîne de longueur fixe. Le reste est identique à RETURN_STRING. Cette macro est plus rapide et sûre en termes de binaire.

RETURN_EMPTY_STRING() renvoie une chaîne vide.

RETURN_FALSE Renvoie un booléen faux.

RETURN_TRUE Renvoie un booléen vrai.

Macro pour définir la valeur de retour de la fonction :

RETVAL_RESOURCE(resource) Définissez la valeur de retour sur une ressource spécifiée.

RETVAL_BOOL(bool) Définit la valeur de retour sur une valeur booléenne spécifiée.

RETVAL_NULL Définissez la valeur de retour sur une valeur nulle

RETVAL_LONG(long) Définissez la valeur de retour sur un entier long spécifié.

RETVAL_DOUBLE(double) Définit la valeur de retour sur un nombre à virgule flottante double précision spécifié.

RETVAL_STRING(string, duplicate) définit la valeur de retour sur une chaîne spécifiée. La signification de duplicate est la même que RETURN_STRING.

RETVAL_STRINGL(string, length, duplicate) Définissez la valeur de retour sur une chaîne de longueur fixe spécifiée. Le reste est identique à RETVAL_STRING. Cette macro est plus rapide et sûre en termes de binaire.

RETVAL_EMPTY_STRING définit la valeur de retour sur une chaîne vide.

RETVAL_FALSE Définissez la valeur de retour sur Boolean false.

RETVAL_TRUE définit la valeur de retour sur Boolean true.

Si vous devez renvoyer des types de données complexes tels que des tableaux et des objets, vous devez d'abord appeler array_init() et object_init(), ou vous pouvez utiliser la fonction de hachage correspondante pour faire fonctionner directement return_value. Étant donné que ces types sont principalement composés d’éléments divers, il n’existe pas de macros correspondantes.



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