深入理解PHP内核(六)函数的定义、传参及返回值
一、函数的定义
用户函数的定义从function 关键字开始,如下
<span style="color: #0000ff">function</span> foo(<span style="color: #800080">$var</span><span style="color: #000000">) { </span><span style="color: #0000ff">echo</span> <span style="color: #800080">$var</span><span style="color: #000000">;}</span>
1、词法分析
在Zend/zend_language_scanner.l中我们找到如下所示的代码:
<span style="color: #800000">"</span><span style="color: #800000">function</span><span style="color: #800000">"</span><span style="color: #000000"> { </span><span style="color: #0000ff">return</span><span style="color: #000000"> T_FUNCTION;}</span>
它所表示的含义是function将会生成T_FUNCTION标记。在获取这个标记后,我们开始语法分析。
2、语法分析
在Zend/zend_language_parser.y文件中找到函数的声明过程标记如下:
<span style="color: #000000">function: T_FUNCTION { $$.u.opline_num </span>=<span style="color: #000000"> CG(zend_lineno); }; is_reference: </span><span style="color: #008000">/*</span><span style="color: #008000"> empty </span><span style="color: #008000">*/</span> { $$.op_type =<span style="color: #000000"> ZEND_RETURN_VAL; } </span>| <span style="color: #800000">'</span><span style="color: #800000">&</span><span style="color: #800000">'</span> { $$.op_type <div style="color:transparent">!本文来源gaodai.ma#com搞##代!^码网(</div><sup>搞gaodaima代码</sup>=<span style="color: #000000"> ZEND_RETURN_REF; }; unticked_function_declaration_statement: function is_reference T_STRING {zend_do_begin_function_declaration(</span>&$<span style="color: #800080">1</span>, &$<span style="color: #800080">3</span>, <span style="color: #800080">0</span>, $<span style="color: #800080">2</span><span style="color: #000000">.op_type, NULL TSRMLS_CC); } </span><span style="color: #800000">'</span><span style="color: #800000">(</span><span style="color: #800000">'</span> parameter_list <span style="color: #800000">'</span><span style="color: #800000">)</span><span style="color: #800000">'</span> <span style="color: #800000">'</span><span style="color: #800000">{</span><span style="color: #800000">'</span> inner_statement_list <span style="color: #800000">'</span><span style="color: #800000">}</span><span style="color: #800000">'</span><span style="color: #000000"> { zend_do_end_function_declaration(</span>&$<span style="color: #800080">1</span><span style="color: #000000"> TSRMLS_CC); };</span>
关注点在function is_reference T_STRING,表示function关键字,是否引用,函数名
T_FUNCTION标记只是用来定位函数的声明,表示这是一个函数,而更多的工作是与这个函数相关的东西,包括参数,返回值。
3、生成中间代码
语法解析后,我们看到所执行编译函数为zend_do_begin_function_declaration。在Zend/zend_complie.c文件找到其实现如下:
<span style="color: #0000ff">void</span> zend_do_begin_function_declaration(znode *<span style="color: #000000">function_token, znode </span>*<span style="color: #000000">function_name, </span><span style="color: #0000ff">int</span> is_method, <span style="color: #0000ff">int</span> return_reference, znode *fn_flags_znode TSRMLS_DC) <span style="color: #008000">/*</span><span style="color: #008000"> {{{ </span><span style="color: #008000">*/</span><span style="color: #000000">{ ...</span><span style="color: #008000">//</span><span style="color: #008000">省略</span> function_token->u.op_array =<span style="color: #000000"> CG(active_op_array); lcname </span>=<span style="color: #000000"> zend_str_tolower_dup(name, name_len); orig_interactive </span>=<span style="color: #000000"> CG(interactive); CG(interactive) </span>= <span style="color: #800080">0</span><span style="color: #000000">; init_op_array(</span>&<span style="color: #000000">op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); CG(interactive) </span>=<span style="color: #000000"> orig_interactive; ...</span><span style="color: #008000">//</span><span style="color: #008000">省略</span> <span style="color: #0000ff">if</span><span style="color: #000000"> (is_method) { ...</span><span style="color: #008000">//</span><span style="color: #008000">省略,类方法 在后面的章节介绍</span>?!<span style="color: #000000">?GH } </span><span style="color: #0000ff">else</span><span style="color: #000000"> { zend_op </span>*opline =<span style="color: #000000"> get_next_op(CG(active_op_array) TSRMLS_CC); opline</span>->opcode =<span style="color: #000000"> ZEND_DECLARE_FUNCTION; opline</span>->op1.op_type =<span style="color: #000000"> IS_CONST; build_runtime_defined_function_key(</span>&opline-><span style="color: #000000">op1.u.constant, lcname, name_len TSRMLS_CC); opline</span>->op2.op_type =<span style="color: #000000"> IS_CONST; opline</span>->op2.u.constant.type =<span style="color: #000000"> IS_STRING; opline</span>->op2.u.constant.value.str.val =<span style="color: #000000"> lcname; opline</span>->op2.u.constant.value.str.len =<span style="color: #000000"> name_len; Z_SET_REFCOUNT(opline</span>->op2.u.constant, <span style="color: #800080">1</span><span style="color: #000000">); opline</span>->extended_value =<span style="color: #000000"> ZEND_DECLARE_FUNCTION; zend_hash_update(CG(function_table), opline</span>-><span style="color: #000000">op1.u.constant.value.str.val, opline</span>->op1.u.constant.value.str.len, &<span style="color: #000000">op_array, </span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(zend_op_array), (</span><span style="color: #0000ff">void</span> **) &<span style="color: #000000">CG(active_op_array)); } }</span><span style="color: #008000">/*</span><span style="color: #008000"> }}} </span><span style="color: #008000">*/</span><span style="color: #000000"><br /></span>