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 です。 戻り値が使用可能な
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); // 返回前执行收尾工作}return 文のない関数 PHP にはプロシージャの概念はなく、
zend_do_return(NULL, 0 TSRMLS_CC);前の内容と組み合わせると、このステートメントの関数が NULL を返すことがわかります。これが、return ステートメントのない関数が NULL を返す理由です。 関数から直接値を返すマクロ: 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 サイトの他の関連記事を参照してください。