In a programming language, a function or a method typically has a return value, but there is also a case where no value is returned, at which point the function simply handles some transactions, does not return, or does not have a definite return value, and in the Pascal language it has a proprietary keyword procedure. In PHP, functions have return values in two cases, with a return statement that explicitly returns and no return statement to return NULL.
Return statement
When you use the return statement, PHP returns a variable of the specified type to the user-defined function. Still we look at the source of the way, the return keyword for lexical analysis and parsing, the generation of intermediate code. From the Zend/zend_language_parser.y file, you can confirm that the Zend_do_return function is called by its generated intermediate code.
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_met Hod_call (expr)) {Zend_do_end_variable_parse (expr, bp_var_w, 0 TSRMLS_CC);/* Process return reference */} else { Zend_do_end_variable_parse (expr, bp_var_r, 0 TSRMLS_CC);/* Handle General variable return */}} ...//Omit other intermediate code operation OPLINE->OPC Ode = Zend_return; if (expr) {opline->op1 = *expr; if (do_end_vparse && zend_is_function_or_method_call (expr)) {Opline->extended_value = Zend_returns_f unction; }} else {opline->op1.op_type = Is_const; Init_zval (opline->op1.u.constant); } set_unused (OPLINE->OP2);} /* }}} */
The
Generates an intermediate code of Zend_return. The type of the first operand is the action type of the expression when the return value is an expression that is available, otherwise the type is is_const. This is useful when performing intermediate code functions in subsequent computations. Depending on the operand, the Zend_return intermediate code executes Zend_return_spec_const_handler, Zend_return_spec_tmp_handler, or Zend_return_spec_tmp_ HANDLER. The execution flow of these three functions is basically similar, including the handling of some errors. Here we take Zend_return_spec_const_handler as an example to illustrate the execution of function return values:
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) {//return reference does not allow constants and temporary variables if (is_const = = Is_co NST | | Is_const = = Is_tmp_var) {/* Not supposed to happen, but we'll allow it */Zend_error (E_notice, "on Ly variable references \ Should is returned by reference "); Goto Return_by_value; } retval_ptr_ptr = NULL; return value 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 is returned by reference"); Goto Return_by_value; }} if (EG (return_value_ptr_ptr)) {//Return reference separate_zval_to_make_is_ref (RETVAL_PTR_PTR); IS_REFGC is set to 1 z_addref_pp (RETVAL_PTR_PTR); REFCOUNTGC count plus 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); Copies a copy to the return value Zval_copy_ctor (ret); *eg (return_value_ptr_ptr) = ret; } else {*eg (return_value_ptr_ptr) = retval_ptr;//Direct Assignment z_addref_p (RETVAL_PTR); }} else {Zval *ret; Alloc_zval (ret); Init_pzval_copy (ret, retval_ptr); Copies a copy to the return value *eg (return_value_ptr_ptr) = ret; }} return Zend_leave_helper_spec (Zend_opcode_handler_args_passthru); Perform a finishing job before returning}
The return value of the function is stored in *eg (RETURN_VALUE_PTR_PTR) when the program executes. The Ze kernel distinguishes between value returns and reference returns, and on this basis the constants, temporary variables, and other types of variables are treated differently on return. Before the return executes, the Ze kernel clears the variables used inside the function by calling the Zend_leave_helper_spec function. This is one of the reasons why the Ze kernel automatically adds null to the function.
function with no return statement
In PHP, there is no concept of procedure, only functions that have no return value. However, for functions that do not have a return value, the PHP kernel will "help you" add a null to the return value. This "help you" operation is also done when generating intermediate code. The function zend_do_end_function_declaration is required for each function parsing, and there is a statement in this function:
Zend_do_return (NULL, 0 tsrmls_cc);
In conjunction with the previous content, we know that the function of this statement is to return NULL. This is why a function with no return statement returns NULL.
The return value of the intrinsic function is passed through a variable named Return_value. This variable is also a parameter in the function, which can be seen after the Php_function function is expanded. This parameter always contains a zval container that has a good pre-application space, so you can directly access its members and modify them without first executing make_std_zval macros on the return_value. To make it easier to return results from a function, and to eliminate the hassle of directly accessing the internal structure of the Zval container, ZEND provides a large set of macro commands to complete the related operations. These macro commands automatically set the type and value.
A macro that returns a value directly from a function:
Return_resource (RESOURCE) returns a resource.
Return_bool (BOOL) returns a Boolean value.
Return_null () returns a null value.
Return_long (long) returns a long integer.
Return_double (double) returns a double-precision floating-point number.
Return_string (string, duplicate) returns a string. Duplicate indicates whether this character is copied using Estrdup ().
Return_stringl (string, length, duplicate) returns a fixed-length string. The rest is the same as return_string. This macro is fast and binary safe.
Return_empty_string () returns an empty string.
Return_false returns a Boolean value of false.
Return_true Returns a Boolean value true.
To set a macro for a function return value:
Retval_resource (RESOURCE) sets the return value to a specified resource.
Retval_bool (BOOL) sets the return value to a specified Boolean value.
Retval_null set the return value to a null value
Retval_long (long) sets the return value to a specified long integer.
Retval_double (double) sets the return value to a specified double-precision floating-point number.
Retval_string (String, duplicate) sets the return value to a specified string, duplicate meaning is the same as return_string.
Retval_stringl (string, length, duplicate) sets the return value to a specified fixed-length string. The rest is the same as retval_string. This macro is fast and binary safe.
Retval_empty_string sets the return value to an empty string.
Retval_false sets the return value to a Boolean false value.
Retval_true set the return value to a Boolean value true.
If you need to return a complex type of data such as arrays and objects, you need to call Array_init () and Object_init (), or you can use the corresponding hash function to manipulate the return_value directly. Since these types are mainly composed of some assorted, there is no corresponding macro for them.