& Lt; spanstyle = & quot; color: rgb (54,46, 43); font-family: Simsun; font-size: 16px; line-height: 24px; text-indent: 2em; & quot; & gt; when we were studying the first language, for example, the C language programming in a university course, maybe when we were learning the first language, for example, the C language programming in university courses may have been entangled in prefix Auto-increment (++ I) and suffix auto-increment (I ++. I thought we understood:
- I ++: first reference and then add, first use the current value of I in the expression where I is located, and then let I add 1
- ++ I: First add and then reference, let I add 1 first, then use the new value of I in the expression where I is located
This expression is basically correct, but not accurate enough. In the appendix of the book "Expert C Programming", there is a note: ++ I represents the address of I, adds its content, and then places the value in the register; I ++ indicates taking the I address, loading its value into the register, and then increasing the I value in the memory. The register here stores the values we use in the expression.
In PHP, there are also ++ $ I and $ I ++. how does the Zend kernel implement these two auto-increment methods? Let's look at the following example. what do you think will be output without running this code?
$i = 0;$i = $i++;echo $i;
No matter what the answer is? We can directly view the implementation of this auto-increment operation from the Zend kernel.
Use VLD to view the intermediate code generated by PHP code that contains $ I ++ and ++ $ I:
$i = 0;$i++;++$i;
Run the VLD command (php-dvld. active = 1-dvld. verbosity = 3 t. php) to view the detailed parameters:
number of ops: 8compiled vars: !0 = $iline # * op fetch ext return operands--------------------------------------------------------------------------------- 2 0 > EXT_STMT RES[ IS_UNUSED ] OP1[ IS_UNUSED ] OP2[ IS_UNUSED ] 1 ASSIGN OP1[IS_CV !0 ] OP2[ , IS_CONST (0) 0 ] 3 2 EXT_STMT RES[ IS_UNUSED ] OP1[ IS_UNUSED ] OP2[ IS_UNUSED ] 3 POST_INC RES[ IS_TMP_VAR ~1 ] OP1[ IS_CV !0 ] 4 FREE OP1[IS_TMP_VAR ~1 ] 4 5 EXT_STMT RES[ IS_UNUSED ] OP1[ IS_UNUSED ] OP2[ IS_UNUSED ] 6 PRE_INC OP1[IS_CV !0 ] 5 7 > RETURN OP1[IS_CONST (0) 1 ]branch: # 0; line: 2- 5; sop: 0; eop: 7path #1: 0,
According to the output information of the VLD extension, the opcode corresponding to the prefix Auto-increment (++ $ I) is PRE_INC, and the opcode corresponding to the suffix auto-increment ($ I ++) is POST_INC. First, we can see that the prefix Auto-increment (++ $ I), ++ $ I does not return a value or its return value is null. According to the intermediate code and the OP1 parameter type displayed by the VLD, we can know that the intermediate code of ++ $ I finally calls the ZEND_PRE_INC_SPEC_CV_HANDLER function in the Zend/zend_vm_execute.h file during execution. There are several key points in the ZEND_PRE_INC_SPEC_CV_HANDLER function:
- To obtain a variable of the CV type, call _ get_zval_ptr_ptr_cv to obtain the variable of the CV type. The CV type variables here are similar to the cache during PHP compilation, and are mainly used to increase the storage speed of some variables.
- The increment_function, whether it is an instance variable, a class variable, or a regular variable, eventually calls the increment_function function to add a variable. In this function, the program will handle different types of variables. in PHP5.3.1, PHP supports four types: IS_LONG, IS_DOUBLE, IS_NULL, and IS_STRING. If the type of the variable is IS_NULL, the program will assign the value of the variable to 1. If the variable type is string, the program converts it into an integer or floating point type for calculation.
- Use the RETURN_VALUE_UNUSED macro to clear the returned results. this macro sets the result variable type to the EXT_TYPE_UNUSED type.
The prefix Auto-increment (++ $ I) operation is essentially an operation variable in the Zend kernel, and the variable itself is used in the expression.
After learning about the implementation of ++ $ I, we can see that more $ I ++ operations may be used. Similarly, the intermediate code POST_INC and OP1 are of the IS_CV type. we can find the ZEND_POST_INC_SPEC_CV_HANDLER implementation in the Zend/zend_vm_execute.h file. Compared with the preceding ZEND_PRE_INC_SPEC_CV_HANDLER, they all have a process of getting the CV type variables, and an increment_function function is used to increase the variable value. However, it has an additional operation, one operation is also missing. One more operation is:
EX_T(opline->result.u.var).tmp_var = **var_ptr;zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var);
The two lines of code initialize the return value to the temporary variable and store the original $ I value here, this is how we used VLD to view the generated intermediate code. The result is RES [IS_TMP_VAR ~ 1. After the initialization is complete, the program will continue to perform the ADD operation. after the ADD operation is complete, it will end, in the previous ++ $ I operation, the result is set to the UNUSED type, which is the one with fewer operations.
The suffix auto-increment ($ I ++) is used in the expression to store the original variable value in the temporary variable, and the value of the variable itself has increased. In PHP, the separation of such variables is solved through temporary variables + return values.
Here, we can answer the first question, and it will output 0. In the expression, the returned value of $ I ++ is a temporary variable, that is, the original value of $ I, that is, 0.