Definition of a function
The definition of a user function starts with the functions keyword, as follows
function foo ($var) { echo $var;}
1. Lexical analysis
In ZEND/ZEND_LANGUAGE_SCANNER.L we find the code shown below:
<ST_IN_SCRIPTING> "function" { return t_function;}
What it means is that the function will generate the t_function tag. After getting this tag, we start parsing.
2. Grammatical analysis
The declaration procedure for the function found in the Zend/zend_language_parser.y file is marked as follows:
Function: t_function {$$.u.opline_num = CG (Zend_lineno);}; is_reference:/ * Empty */{$$.op_type = Zend_return_ VAL; } | ' & ' {$$.op_type = zend_return_ref;}; unticked_function_declaration_statement: function Is_reference T_ STRING {zend_do_begin_function_declaration (&$1, &$3, 0, $2.op_type, NULL tsrmls_cc);} ' (' parameter_list ') ' {' inner_statement_list '} ' { zend_do_end_function_declaration (&$1 tsrmls_cc);};
The focus is in function Is_reference t_string, which represents the function keyword, whether reference, function name
The t_function tag is only used to locate the function's declaration, which means that it is a function, and more work is related to this function, including parameters, return values.
3. Generate Intermediate Code
After parsing the syntax, we see that the compiled function executed is zend_do_begin_function_declaration. Find its implementation in the Zend/zend_complie.c file as follows:
void Zend_do_begin_function_declaration (Znode *function_token, Znode *function_name, int is_method, int return_ Reference, Znode *fn_flags_znode tsrmls_dc)/* {{*/{...//Omit Function_token->u.op_array = CG (Active_op_array); Lcname = zend_str_tolower_dup (name, Name_len); Orig_interactive = CG (interactive); CG (interactive) = 0; Init_op_array (&op_array, zend_user_function, initial_op_array_size tsrmls_cc); CG (interactive) = orig_interactive; ...//omit if (Is_method) {...//Omit, class method in the following section describes!ƕgh} else {zend_op *opline = Get_next_op (CG (active_op _array) TSRMLS_CC); Opline->opcode = zend_declare_function; Opline->op1.op_type = Is_const; Build_runtime_defined_function_key (&opline->op1.u.constant, Lcname, Name_len TSRMLS_CC); Opline->op2.op_type = Is_const; Opline->op2.u.constant.type = is_string; Opline->op2.u.constant.value.str.val = Lcname; Opline->op2.u. Constant.value.str.len = Name_len; Z_set_refcount (opline->op2.u.constant, 1); Opline->extended_value = zend_declare_function; Zend_hash_update (CG (function_table), Opline->op1.u.constant.value.str.val, OPLINE->OP1.U.CONSTANT.VALUE.S Tr.len, &op_array, sizeof (Zend_op_array), (void * *) &CG (Active_op_array)); } }/* }}} */
The generated code is zend_declare_function, according to the middle code and the operand corresponding to the op_type. We can find the execution function of the intermediate code as Zend_declare_function_spec_handler.
When generating the intermediate code, you can see that the function name is all lowercase and that the name of the function is not case-sensitive.
To verify this implementation, let's look at a piece of code
function T () { echo 1;} function t () { echo 2;}
Execution code will error fatal Error:cannot Redeclare t () (previously declared in ...)
For PHP, T and T are the same function name, check if the function name is duplicated, where is the process?
4. Execute Intermediate Code
Find the execution function for the Zend_declare_function intermediate code in the Zend/zend_vm_execute.h file: Zend_declare_function_spec_handler. This function only calls the functions do_bind_function. Its calling code is:
Do_bind_function (EX (Opline), EG (function_table), 0);
In this function, the function pointed to by EX (Opline) is added to EG (function_table), and if there is a function with the same name, if there is an error, EG (function_table) is used to hold all function information in the execution. Equivalent to the registry of the function. Its structure is a hashtable, so adding a new function to the Do_bind_function function uses the Hashtable operation function Zend_hash_add