ホームページ  >  記事  >  バックエンド開発  >  PHP戻り値return文の使い方詳細解説

PHP戻り値return文の使い方詳細解説

伊谢尔伦
伊谢尔伦オリジナル
2017-06-27 09:32:264488ブラウズ

プログラミング言語では、関数やメソッドは戻り値を持つことが一般的ですが、現時点ではこれらの関数は一部のトランザクションのみを処理し、値を返さない、または値を返さない場合もあります。戻り値をクリアします。Pascal 言語には独自のキーワード プロシージャがあります。 PHP では、関数には戻り値があります。これは、return ステートメントを使用して明示的に返す場合と、return ステートメントを使用せずに NULL を返す場合の 2 つの状況に分けられます。

return ステートメント

return ステートメントを使用すると、PHP は指定された型の変数をユーザー定義関数に返します。 ソース コードを表示するのと同じように、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 です。 戻り値が使用可能な

expression である場合、最初のオペランドの型は式の演算型です。それ以外の場合、型は IS_CONST です。これは、後続の計算で中間コード関数を実行する場合に便利です。 オペランドに応じて、ZEND_RETURN 中間コードは ZEND_RETURN_SPEC_CONST_HANDLER、ZEND_RETURN_SPEC_TMP_HANDLER、または ZEND_RETURN_SPEC_TMP_HANDLER を実行します。 これら 3 つの関数の実行フローは、一部のエラーの処理を含め、基本的に似ています。 ここでは、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) {         //  返回引用时不允许常量和临时变量
       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);   //  返回前执行收尾工作}

関数の戻り値は、プログラムの実行時に *EG(return_value_ptr_ptr) に格納されます。 ZE カーネルは値の戻りと参照の戻りを区別し、これに基づいて、定数、一時変数、およびその他のタイプの変数は返されたときに異なる方法で処理されます。リターンが実行される前に、ZE カーネルは zend_leave_helper_SPEC 関数を呼び出して、関数内で使用されている変数をクリアします。 これが、ZE カーネルが関数に NULL 戻り値を自動的に追加する理由の 1 つです。

return 文のない関数

PHP にはプロシージャの概念はなく、

戻り値 のない関数のみがあります。ただし、戻り値のない関数の場合は、PHP カーネルが戻り値として NULL を追加するのを「支援」します。 この「お手伝い」の操作は、中間コードを生成するときにも実行されます。各関数を解析するときに関数 zend_do_end_function_declaration を実行する必要があります。この関数には次のステートメントがあります。

zend_do_return(NULL, 0 TSRMLS_CC);

前の内容と組み合わせると、このステートメントの関数が NULL を返すことがわかります。これが、return ステートメントのない関数が NULL を返す理由です。

内部関数の戻り値は、return_valueという名前の変数を介して渡されます。 この変数は関数内のパラメータでもあり、PHP_FUNCTION 関数を展開した後に表示されます。 このパラメーターには常に、事前に割り当てられたスペースを持つ zval コンテナーが含まれるため、最初に return_value で MAKE_STD_ZVAL マクロを実行しなくても、そのメンバーに直接アクセスしてメンバーを変更できます。 関数からより便利に結果を返し、zval コンテナの内部構造に直接アクセスする手間を省くために、ZEND はこれらの関連操作を完了するためのマクロ コマンドの大きなセットを提供します。 これらのマクロは、型と値を自動的に設定します。

関数から直接値を返すマクロ:

RETURN_RESOURCE(resource) はリソースを返します。

RETURN_BOOL(bool) ブール値を返します。

RETURN_NULL() は null 値を返します。

RETURN_LONG(long) 長整数を返します。

RETURN_DOUBLE(double) は倍精度浮動小数点数を返します。

RETURN_STRING(string, Duplicate) は

string を返します。重複は、この文字が estrdup() を使用してコピーされたかどうかを示します。

RETURN_STRINGL(文字列, 長さ, 重複) は、固定長の文字列を返します。残りは RETURN_STRING と同じです。このマクロはより高速でバイナリ安全です。

RETURN_EMPTY_STRING() は空の文字列を返します。

RETURN_FALSE ブール値の false を返します。

RETURN_TRUE ブール値 true を返します。

関数の戻り値を設定するマクロ:

RETVAL_RESOURCE(resource) は、戻り値を指定されたリソースに設定します。

RETVAL_BOOL(bool) 戻り値を指定されたブール値に設定します。

RETVAL_NULL 戻り値を null 値に設定します。

RETVAL_LONG(long) 戻り値を指定された長整数に設定します。

RETVAL_DOUBLE(double) は、戻り値を指定された倍精度浮動小数点数に設定します。

RETVAL_STRING(string,重複)は、戻り値を指定された文字列に設定します。重複の意味は RETURN_STRING と同じです。

RETVAL_STRINGL(string, length, Duplicate) は、戻り値を指定された固定長文字列に設定します。残りは RETVAL_STRING と同じです。このマクロはより高速でバイナリ安全です。

RETVAL_EMPTY_STRING 戻り値を空の文字列に設定します。

RETVAL_FALSE 戻り値をブール値 false に設定します。

RETVAL_TRUE は、戻り値をブール値 true に設定します。

配列やオブジェクトなどの複雑なタイプのデータを返す必要がある場合は、最初に array_init() と object_init() を呼び出す必要があります。または、対応するハッシュ関数を使用して return_value を直接操作することもできます。 これらのタイプは主に雑多なもので構成されているため、対応するマクロはありません。



以上がPHP戻り値return文の使い方詳細解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。