When interviewing PHP, we often encounter a question about whether various types of null values are true:
<code>$a = <span>''</span>; $a = null $a = false; <span>if</span>($a){<span>...</span>} <span>if</span>(isset($a)){<span>...</span>} <span>if</span>(empty($a)){<span>...</span>} <span>...</span></code>
Let’s take a brief look at how if is handled in the zend engine from the following example:
<code><span><span><?php </span><span>$a</span> = <span>''</span>; <span>//array();</span><span>if</span>(<span>$a</span>){ <span>echo</span><span>"Y"</span>; }</span></span></code>
Here is an example Relatively simple, the result will be nothing. (The codes involved in this article are all version php-7.0.4)
The previous article introduced the zend_execute function, the entrance to the zend execution phase. Let’s start directly from here. If you are not familiar with it, you can read the previous article.
The opcodes generated by compilation are as follows:
Among them, opcode=38 is the execution operation of $a = ”, and opcode=43 is the operation of if. Let’s see how this step is executed.
According to the opcode and the two operand types, the corresponding handler can be found: ZEND_JMPZ_SPEC_CV_HANDLER
<code><span>//zend_vm_execute.h #28307</span><span>static</span> ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *<span>val</span>; <span>val</span> = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); <span>if</span> (Z_TYPE_INFO_P(<span>val</span>) == IS_TRUE) { ZEND_VM_SET_NEXT_OPCODE(opline + <span>1</span>); ZEND_VM_CONTINUE(); } <span>else</span><span>if</span> (EXPECTED(Z_TYPE_INFO_P(<span>val</span>) if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(<span>val</span>) == IS_UNDEF)) { SAVE_OPLINE(); GET_OP1_UNDEF_CV(<span>val</span>, BP_VAR_R); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } <span>else</span> { ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op2)); ZEND_VM_CONTINUE(); } } SAVE_OPLINE(); <span>if</span> (i_zend_is_true(<span>val</span>)) { opline++; } <span>else</span> { opline = OP_JMP_ADDR(opline, opline->op2); } <span>if</span> (UNEXPECTED(EG(<span>exception</span>) != NULL)) { HANDLE_EXCEPTION(); } ZEND_VM_JMP(opline); }</code>
From this function, we can see the execution process of if: if the condition is true, opline++ will execute the next opcode (that is, the statement within the if) in sequence. Otherwise, jump is performed, skipping the inner if statement and directly executing the outer if statement.
i_zend_is_true This function is used to determine whether various types of values are true. The previous part is to determine whether they are bool type. If so, it will be processed directly.
<code><span>//</span>zend_operators.h <span>#283</span> static zend_always_inline int i_zend_is_true(zval *op) { int result = <span>0</span>; <span>again</span>: <span>switch</span> (Z_TYPE_P(op)) { <span>case</span><span>IS_TRUE</span>: result = <span>1</span>; <span>break</span>; <span>//</span>数值类型long、double直接判断即可,与c用法相同 <span>case</span><span>IS_LONG</span>: <span>if</span> (Z_LVAL_P(op)) { result = <span>1</span>; } <span>break</span>; <span>case</span><span>IS_DOUBLE</span>: <span>if</span> (Z_DVAL_P(op)) { result = <span>1</span>; } <span>break</span>; <span>//</span>字符串类型根据长度判断:长度><span>1</span>,或=<span>1</span>且不为<span>'0'</span>为<span>true</span>,所以上面那个例子<span>''</span><span> =></span><span>false</span><span>case</span><span>IS_STRING</span>: <span>if</span> (Z_STRLEN_P(op) > <span>1</span> || (Z_STRLEN_P(op) && Z_STRVAL_P(op)[<span>0</span>] != <span>'0'</span>)) { result = <span>1</span>; } <span>break</span>; <span>//</span>数组类型根据数组元素的个数判断:大于<span>0</span>即为真 <span>case</span><span>IS_ARRAY</span>: <span>if</span><span><span>(zend_hash_num_elements(Z_ARRVAL_P(op)))</span> { // <span>(Z_ARRVAL_P(op))</span>-></span>nNumOfElements result = <span>1</span>; } <span>break</span>; <span>case</span><span>IS_OBJECT</span>: result = zend_object_is_true(op); <span>break</span>; <span>//</span>资源类型实际就是整形(后续会专门介绍资源类型),所以直接判断即可 <span>case</span><span>IS_RESOURCE</span>: <span>if</span> (EXPECTED(Z_RES_HANDLE_P(op))) { result = <span>1</span>; } <span>break</span>; <span>//</span>引用类型则根据指向的值判断 <span>case</span><span>IS_REFERENCE</span>: op = Z_REFVAL_P(op); goto again; <span>break</span>; <span>default</span>: <span>break</span>; } <span>return</span> result; }</code>
isset and empty functions will be added later...
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i ').text(i)); }; $numbering.fadeIn(1700); }); });The above introduces the grammar: the implementation of IF judgment, including aspects of the content. I hope it will be helpful to friends who are interested in PHP tutorials.