[PHP Source Code Reading] empty and isset functions, emptyisset
Recently, I was asked how to judge variables when using empty and isset functions in PHP. At the beginning, I was very frustrated, because I was just a bit confused, in order to understand its true principles, open source code research. After analysis, we can find that both functions call the same function. Therefore, this article will analyze the two functions together.
I have a more detailed description of the PHP source code on github. If you are interested, you can look around and give a star. PHP5.4 source code annotation. You can use the commit record to view the added annotations.
Function Format: empty
bool empty ( mixed $var )
Determines whether the variable is null.
Isset
bool isset ( mixed $var [ , mixed $... ] )
Determines whether the variable is set and not NULL.
Parameter description
For empty, before PHP5.5, empty only supports variable parameters. Other types of parameters may cause parsing errors. For example, function call results cannot be used as parameters.
For isset, if the variable is set as NULL by the unset function, the function returns false. If multiple parameters are passed to the isset function, true is returned only when all parameters are set to the isset function. Calculated from left to right. Once a variable is not set, it is stopped.
Running example
$ Result = empty (0); // true $ result = empty (null); // true
$ Result = empty (false); // true $ result = empty (array (); // true $ result = empty ('0 '); // true $ result = empty (1); // false $ result = empty (callback function); // Error
$ A = null;
$ Result = isset ($ a); // false;
$ A = 1;
$ Result = isset ($ a); // true;
$ A = 1; $ B = 2; $ c = 3;
$ Result = isset ($ a, $ B, $ c); // true
$a = 1;$b = null;$c = 3;
$result = isset($a, $b, $c); // false
Locate the function definition location
In fact, empty is not a function, but a language structure. The language structure is compiled before the PHP program runs. Therefore, you cannot simply search for "PHP_FUNCTION empty" or "ZEND_FUNCTION empty" as before to view the source code. To view the source code of empty and other language structures, you must first understand the PHP code execution mechanism.
PHP executes the code in four steps. The flowchart is as follows:
<ST_IN_SCRIPTING> "isset" {return T_ISSET;} <ST_IN_SCRIPTING> "empty" {return T_EMPTY ;}
Next we will go to the Parsing stage. At this stage, the program converts Tokens such as T_ISSET and T_EMPTY into meaningful expressions, and then performs syntax analysis. The Tokens yacc is saved in the zend_language_parser.y file, you can find the definitions of T_ISSET and T_EMPTY:
internal_functions_in_yacc:T_ISSET '(' isset_variables ')' { $$ = $3; }| T_EMPTY '(' variable ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }| T_INCLUDE expr { zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }| T_INCLUDE_ONCE expr { zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }| T_EVAL '(' expr ')' { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }| T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }| T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); };
The isset and empty functions finally execute the zend_do_isset_or_isempty function to continue searching.
Grep-rn "zend_do_isset_or_isempty"
It can be found that this function is defined in the zend_compile.c file.
Function execution steps
1. Resolution Parameters
2. check whether it is a writable variable.
3. If the op_type of the variable is IS_CV (the variable in the compilation period), set opcode to ZEND_ISSET_ISEMPTY_VAR; otherwise, the next op value is obtained from active_op_array, set the opcode of last_op based on its op value.
4. After opcode is set, it will be handed over to zend_excute for execution.
Source code explanation
IS_CV is a cache mechanism used by the compiler. This variable stores the address of the referenced variable. When a variable is referenced for the first time, it will be CV, you do not need to search for the active symbol table for reference of this variable in the future.
For the empty function, after the opcode step is reached, refer to the opcode processing function, you can know that the isset and empty are executed during the excuteZEND_ISSET_ISEMPTY_VARAnd other functionsZEND_ISSET_ISEMPTY_VAR_SPEC_CV_VAR_HANDLERFor example, find the function definition inZend_vm_execute.h. You can see that the final execution function of the empty function isI _zend_is_true (),The I _zend_is_true function is defined inZend_execute.h. The core code of the I _zend_is_true function is as follows:
Switch (Z_TYPE_P (op) {case IS_NULL: result = 0; break; case IS_LONG: case IS_BOOL: case IS_RESOURCE: // If the empty parameter is an integer and is not 0, false result = (Z_LVAL_P (op )? 1:0); break; case IS_DOUBLE: result = (Z_DVAL_P (op )? 1: 0); break; case IS_STRING: if (Z_STRLEN_P (op) = 0 | (Z_STRLEN_P (op) = 1 & Z_STRVAL_P (op) [0] = '0') {// empty ("0") = true result = 0;} else {result = 1;} break; case IS_ARRAY: // empty (array) Determines result = (zend_hash_num_elements (Z_ARRVAL_P (op) based on the number of arrays ))? 1:0); break; case IS_OBJECT: if (IS_ZEND_STD_OBJECT (* op) {TSRMLS_FETCH (); if (Z_OBJ_HT_P (op)-> cast_object) {zval tmp; if (Z_OBJ_HT_P (op)-> cast_object (op, & tmp, IS_BOOL TSRMLS_CC) = SUCCESS) {result = Z_LVAL (tmp); break ;}} else if (Z_OBJ_HT_P (op)-> get) {zval * tmp = Z_OBJ_HT_P (op)-> get (op TSRMLS_CC); if (Z_TYPE_P (tmp )! = IS_OBJECT) {/* for safety-avoid loop */convert_to_boolean (tmp); result = Z_LVAL_P (tmp); zval_ptr_dtor (& tmp); break ;}} result = 1; break; default: result = 0; break ;}
This code is intuitive, and the function does not convert the detected value. The Code further analyzes the empty function in the example for analysis:
Empty (null), to IS_NULL branch, result = 0, I _zend_is_true () = 0 ,! I _zend_is_true () = 1, so true is returned.
Empty (false), to the IS_BOOL branch, result = ZLVAL_P (false) = 0, I _zend_is_true () = 0 ,! I _zend_is_true () = 1, so true is returned.
Empty (array (), to the IS_ARRAY branch, result = zend_hash_num_elements (Z_ARRVAL_P (op ))? 1: 0), zend_hash_num_elements returns the number of array elements, array is empty, so result is 0, I _zend_is_true () = 0 ,! I _zend_is_true () = 1, so true is returned.
Empty ('0') to the IS_STRING branch, because Z_STRLENP (op) = 1 and Z_STRVAL_P (op) [0] = '0', the result is 0, I _zend_is_true () = 0 ,! I _zend_is_true () = 1, so true is returned.
Empty (1), to the IS_LONG branch, result = Z_LVAL_P (op) = 1, I _zend_is_true = 1 ,! I _zend_is_true () = 0, so false is returned.
For the isset function, the final code for judgment is:
if (isset && Z_TYPE_PP(value) != IS_NULL) { ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 1);} else { ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 0);}
The isset function returns true if the value is set and is not NULL.
Summary
This time I read the source code of these two functions and learned the following:
1. PHP code execution steps during compilation
2. How to find the source code location of the PHP language structure
3. How to find specific functions of the opcode processing function
There is no end to learning. Everyone has their own short board. Only through continuous learning can they make up their short board.
The original article is limited in writing, so it is easy to learn. If there is anything wrong with the article, please let us know.
If this article is helpful to you, please click here for recommendations. Thank you ^_^
At last, I have a more detailed description of the PHP source code on github. If you are interested, you can look around and give a star. PHP5.4 source code annotation. You can use the commit record to view the added annotations.
References
Opcode processing function lookup: http://www.laruence.com/2008/06/18/221.html
PHPopcode deep understanding and PHP code execution steps: http://www.php-internals.com/book? P = chapt02/02-03-from-opcode-to-handler
For more source code articles, visit the personal homepage to continue viewing: hoohack