php控制结构语句declare中的tick的详解
2014-07-31 16:47
681 查看
先看看手册是怎么说的:
declare 结构用来设定一段代码的执行指令。declare 的语法和其它流程控制结构相似:
directive 部分允许设定 declare 代码段的行为。目前只认识两个指令:ticks(更多信息见下面 ticks 指令)以及encoding(更多信息见下面 encoding指令)。
Note:
ticks 指令在 PHP 5.3.0 中是过时指令,将会从 PHP 6.0.0 移除。
encoding 是 PHP 5.3.0 新增指令。
Tick 是一个在 declare 代码段中解释器每执行 N 条低级语句就会发生的事件。N 的值是在 declare 中的 directive部分用
在每个 tick 中出现的事件是由 register_tick_function() 来指定的。更多细节见下面的例子。注意每个
tick 中可以出现多个事件。
看完手册还是觉得云里雾里,再看看别人是怎么描述:
根据代码解析:
运算结果:
产生三个疑问:
(1)为什么先输出1之后才输出“Ticks”?
(2)为什么在输出81后还输出四个Ticks ?
(3)declare中的for循环怎么分解成低级语句(low-level)?
这是每个初次接触ticks的人都会碰到的问题。首先register_tick_function函数定义了每个tick事件发生时的处理函数。那么什么是tick事件呢?先看手册上对ticks的解释:
这个解释有三层意思:
(1) tick是一个事件。
(2) tick事件在PHP每执行N条低级语句就发生一次,N由declare语句指定。
(3)可以用register_tick_function()来指定tick事件发生时应该执行的操作。
很明显,理解上面的输出结果最关键的是了解什么是低级语句(low-level
statements),它又是如何进行计数的。我们首先还是将上面的程序通过OPDUMP编译成OPCODEs:
很明显,PHP的编译过程已经在编译后每条语句的OPCODE序列中插入了TICKS指令用于处理tick事件。那么这些TICKS是根据什么规则来插入的呢?
我们还是从PHP Zend Engine的源代码中寻找答案。
通过简单的文本搜索我们可以知道生成ZEND_TICKS指令的唯一函数是zend_do_ticks(该函数的实现在zend_compile.c中)。
现在再从PHP的语法分析文件zend_language_parser.y(PHP使用bison来做语法分析,所有的语法规则均定义在zend_language_parser.y中)中寻找调用zend_do_ticks的地方。
再一次使用简单的文本搜索,我们可以得到调用zend_do_ticks的三条语法规则:
也就是说,PHP编译会在statement(语句), function_declaration_statement(函数定义语句), class_declaration_statement后插入TICKS处理函数,即它会在每条statement,函数声明,类(实际上还包括接口)声明后插入一条TICKS指令。
函数与类声明语句比较好理解,根据unticked_function_declaration_statement的语法定义:
可以知道function_declaration_statement是完整的函数声明,也就是说,一个函数的定义包括完整的函数原形及函数体算一条function_declaration_statement。
同样从unticked_class_declaration_statement的语法定义:
也可以知道,完整的class或interface定义算是一个class_declration_statement。
最复杂的是statement,它的核心是下面的定义:
根据上面的定义,我们知道,statement包括:
(1) 简单语句:空语句(就一个;号),return,break,continue,throw, goto,global,static,unset,echo, 内置的HTML文本,分号结束的表达式等均算一个语句。
(2) 复合语句:完整的if/elseif,while,do...while,for,foreach,switch,try...catch等算一个语句。
(3) 语句块:{} 括出来的语句块。
(4) 最后特别的:declare块本身也算一个语句(按道理declare块也算是复合语句,但此处特意将其独立出来)。
所有的statement, function_declare_statement, class_declare_statement就构成了所谓的低级语句(low-level
statement)。
现在再来看开始的例子就比较好理解了:
首先完整的for循环算一个语句,但必须要等循环结束才算,因此在编译时for循环里面的echo
算第一个语句。
所以第一个doTicks是在第一个echo后执行的,也就是1输出后才发生第一个tick事件。
在$x 从1到9的循环中,每个循环包括两个语句,一个echo,
一个for循环。在81输出后,因为echo是一条语句,因此输出第一个ticks。
同时$x=9的这个for循环也结束了,这又是一条语句,输出第二个ticks;开始$x=10的循环,但这时已不满足循环条件,for循环执行结束,这个循环又是一个语句,这时输出第三个ticks。
最后declare本身也算一条语句,所以又输出第四个ticks。
说了半天,ticks到底有什么用?实际上可用tick来进行调试,性能测试,实现简单的多任务,或者做一些后台的I/O操作等等。
declare 结构用来设定一段代码的执行指令。declare 的语法和其它流程控制结构相似:
1 | declare (directive) |
2 | statement |
Note:
ticks 指令在 PHP 5.3.0 中是过时指令,将会从 PHP 6.0.0 移除。
encoding 是 PHP 5.3.0 新增指令。
Tick 是一个在 declare 代码段中解释器每执行 N 条低级语句就会发生的事件。N 的值是在 declare 中的 directive部分用
ticks=N来指定的。
在每个 tick 中出现的事件是由 register_tick_function() 来指定的。更多细节见下面的例子。注意每个
tick 中可以出现多个事件。
看完手册还是觉得云里雾里,再看看别人是怎么描述:
根据代码解析:
01 | <?php |
02 | function doTicks () |
03 | { |
04 | echo 'Ticks' ; |
05 | } |
06 | register_tick_function( 'doTicks' ); |
07 | declare (ticks = 1) { |
08 | for ( $x = 1; $x < 10; ++ $x ) { |
09 | echo $x * $x . '<br />' ; |
10 | } |
11 | } |
12 | ?> |
01 | 1 |
02 | TicksTicks4 |
03 | TicksTicks9 |
04 | TicksTicks16 |
05 | TicksTicks25 |
06 | TicksTicks36 |
07 | TicksTicks49 |
08 | TicksTicks64 |
09 | TicksTicks81 |
10 | TicksTicksTicksTicks |
(1)为什么先输出1之后才输出“Ticks”?
(2)为什么在输出81后还输出四个Ticks ?
(3)declare中的for循环怎么分解成低级语句(low-level)?
这是每个初次接触ticks的人都会碰到的问题。首先register_tick_function函数定义了每个tick事件发生时的处理函数。那么什么是tick事件呢?先看手册上对ticks的解释:
1 | A tick is an event that occurs for every N low-level statements executed by the parser within the declare block. The value for N is specified using ticks=N within the declare blocks's directive section. |
2 | The event(s) that occur on each tick are specified using the register_tick_function(). |
(1) tick是一个事件。
(2) tick事件在PHP每执行N条低级语句就发生一次,N由declare语句指定。
(3)可以用register_tick_function()来指定tick事件发生时应该执行的操作。
很明显,理解上面的输出结果最关键的是了解什么是低级语句(low-level
statements),它又是如何进行计数的。我们首先还是将上面的程序通过OPDUMP编译成OPCODEs:
01 | 1: <?php |
02 | 0 |
03 | 2: |
04 | 3: function doTicks () |
05 | 4: { |
06 | 5: echo 'Ticks' ; |
07 | 0 ECHO 'Ticks' |
08 | 6: } |
09 | 1 |
10 | 7: register_tick_function( 'doTicks' ); |
11 | 1 'doTicks' |
12 | 2 'register_tick_function' [extval:1] |
13 | 8: declare (ticks = 1) { |
14 | 9: for ( $x = 1; $x < 10; ++ $x ) { |
15 | 3 |
16 | 4 |
17 | 5 |
18 | 6 |
19 | 7 |
20 | 10: echo $x * $x . '<br />' ; |
21 | 8 |
22 | 9 '<br />' =>RES[~5] |
23 | 10 ECHO ~5 |
24 | 11 |
25 | 11: } |
26 | 12 |
27 | 13 |
28 | 14 |
29 | 12: } |
30 | 15 |
31 | 16 |
我们还是从PHP Zend Engine的源代码中寻找答案。
通过简单的文本搜索我们可以知道生成ZEND_TICKS指令的唯一函数是zend_do_ticks(该函数的实现在zend_compile.c中)。
现在再从PHP的语法分析文件zend_language_parser.y(PHP使用bison来做语法分析,所有的语法规则均定义在zend_language_parser.y中)中寻找调用zend_do_ticks的地方。
再一次使用简单的文本搜索,我们可以得到调用zend_do_ticks的三条语法规则:
01 | statement: |
02 | unticked_statement {zend_do_ticks(TSRMLS_C); } |
03 | | ... |
04 | ; |
05 | function_declaration_statement: |
06 | unticked_function_declaration_statement {zend_do_ticks(TSRMLS_C); } |
07 | ; |
08 | class_declaration_statement: |
09 | unticked_class_declaration_statement {zend_do_ticks(TSRMLS_C); } |
10 | ; |
函数与类声明语句比较好理解,根据unticked_function_declaration_statement的语法定义:
1 | unticked_function_declaration_statement: |
2 | function is_reference T_STRING {zend_do_begin_function_declaration(& $1 , & $3 , 0, $2 .op_type, NULL TSRMLS_CC);} |
3 | '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(& $1 TSRMLS_CC); } |
4 | ; |
同样从unticked_class_declaration_statement的语法定义:
01 | unticked_class_declaration_statement: |
02 | class_entry_type T_STRING extends_from |
03 | { zend_do_begin_class_declaration(& $1 , & $2 , & $3 TSRMLS_CC); } |
04 | implements_list |
05 | '{' |
06 | class_statement_list |
07 | '}' { zend_do_end_class_declaration(& $1 , & $2 TSRMLS_CC); } |
08 | | interface_entry T_STRING |
09 | { zend_do_begin_class_declaration(& $1 , & $2 , NULL TSRMLS_CC);} |
10 | interface_extends_list |
11 | '{' |
12 | class_statement_list |
13 | '}' { zend_do_end_class_declaration(& $1 , & $2 TSRMLS_CC); } |
14 | ; |
最复杂的是statement,它的核心是下面的定义:
01 | unticked_statement: |
02 | '{' inner_statement_list '}' |
03 | | T_IF '(' expr ')' { zend_do_if_cond(& $3 , & $4 TSRMLS_CC); } statement {zend_do_if_after_statement(& $4 , 1 TSRMLS_CC);} elseif_list else_single {zend_do_if_end(TSRMLS_C); } |
04 | | T_IF '(' expr ')' ':' { zend_do_if_cond(& $3 , & $4 TSRMLS_CC); } inner_statement_list{zend_do_if_after_statement(& $4 , 1 TSRMLS_CC);} new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); } |
05 | | T_WHILE '(' { $1 .u.opline_num ')' { zend_do_while_cond(& $4 , & $5 TSRMLS_CC); } while_statement {zend_do_while_end(& $1 , & $5 TSRMLS_CC); } |
06 | | $1 .u.opline_num '(' { $5 .u.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' ';' { zend_do_do_while_end(& $1 , & $5 , & $7 TSRMLS_CC); } |
07 | | T_FOR |
08 | '(' |
09 | for_expr |
10 | ';' { zend_do_free(& $3 TSRMLS_CC); $4 .u.opline_num = get_next_op_number(CG(active_op_array)); } |
11 | for_expr |
12 | ';' { zend_do_extended_info(TSRMLS_C); zend_do_for_cond(& $6 , & $7 TSRMLS_CC); } |
13 | for_expr |
14 | ')' { zend_do_free(& $9 TSRMLS_CC); zend_do_for_before_statement(& $4 , & $7 TSRMLS_CC); } |
15 | for_statement $7 TSRMLS_CC); } |
16 | | T_SWITCH '(' expr ')' { zend_do_switch_cond(& $3 TSRMLS_CC); } switch_case_list {zend_do_switch_end(& $6 TSRMLS_CC); } |
17 | | T_BREAK ';' { |
18 | | T_BREAKexpr ';' { zend_do_brk_cont(ZEND_BRK, & $2 TSRMLS_CC); } |
19 | | T_CONTINUE ';' { |
20 | | T_CONTINUEexpr ';' { zend_do_brk_cont(ZEND_CONT, & $2 TSRMLS_CC); } |
21 | | T_RETURN ';' { |
22 | | T_RETURNexpr_without_variable ';' { zend_do_return(& $2 , |
23 | | T_RETURNvariable ';' { zend_do_return(& $2 , |
24 | | T_GLOBAL global_var_list ';' |
25 | | T_STATIC static_var_list ';' |
26 | | T_ECHO echo_expr_list ';' |
27 | | $1 TSRMLS_CC); } |
28 | | ';' { zend_do_free(& $1 TSRMLS_CC); } |
29 | | T_UNSET '(' unset_variables ')' ';' |
30 | | T_FOREACH '(' variable T_AS |
31 | { zend_do_foreach_begin(& $1 , & $2 , & $3 , & $4 , |
32 | foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(& $1 , & $2 , & $4 , & $6 , & $7 TSRMLS_CC); } |
33 | foreach_statement $1 , & $4 TSRMLS_CC); } |
34 | | T_FOREACH '(' expr_without_variable T_AS |
35 | { zend_do_foreach_begin(& $1 , & $2 , & $3 , & $4 , |
36 | variable foreach_optional_arg ')' { zend_check_writable_variable(& $6 ); zend_do_foreach_cont(& $1 , & $2 , & $4 , & $6 , & $7 TSRMLS_CC); } |
37 | foreach_statement $1 , & $4 TSRMLS_CC); } |
38 | | $1 .u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement $1 TSRMLS_CC); } |
39 | | ';' /* empty statement */ |
40 | | $1 TSRMLS_CC); } '{' inner_statement_list '}' |
41 | T_CATCH '(' { zend_initialize_try_catch_element(& $1 TSRMLS_CC); } |
42 | fully_qualified_class_name $7 TSRMLS_CC); } |
43 | T_VARIABLE ')' { zend_do_begin_catch(& $1 , & $9 , & $11 , & $7 TSRMLS_CC); } |
44 | '{' inner_statement_list '}' { zend_do_end_catch(& $1 TSRMLS_CC); } |
45 | additional_catches $7 , & $18 TSRMLS_CC); } |
46 | | ';' { zend_do_throw(& $2 TSRMLS_CC); } |
47 | | T_GOTO T_STRING ';' { zend_do_goto(& $2 TSRMLS_CC); } |
48 | ; |
(1) 简单语句:空语句(就一个;号),return,break,continue,throw, goto,global,static,unset,echo, 内置的HTML文本,分号结束的表达式等均算一个语句。
(2) 复合语句:完整的if/elseif,while,do...while,for,foreach,switch,try...catch等算一个语句。
(3) 语句块:{} 括出来的语句块。
(4) 最后特别的:declare块本身也算一个语句(按道理declare块也算是复合语句,但此处特意将其独立出来)。
所有的statement, function_declare_statement, class_declare_statement就构成了所谓的低级语句(low-level
statement)。
现在再来看开始的例子就比较好理解了:
首先完整的for循环算一个语句,但必须要等循环结束才算,因此在编译时for循环里面的echo
算第一个语句。
所以第一个doTicks是在第一个echo后执行的,也就是1输出后才发生第一个tick事件。
在$x 从1到9的循环中,每个循环包括两个语句,一个echo,
一个for循环。在81输出后,因为echo是一条语句,因此输出第一个ticks。
同时$x=9的这个for循环也结束了,这又是一条语句,输出第二个ticks;开始$x=10的循环,但这时已不满足循环条件,for循环执行结束,这个循环又是一个语句,这时输出第三个ticks。
最后declare本身也算一条语句,所以又输出第四个ticks。
说了半天,ticks到底有什么用?实际上可用tick来进行调试,性能测试,实现简单的多任务,或者做一些后台的I/O操作等等。
相关文章推荐
- php控制结构语句declare中的tick的详解[整理版]
- php控制结构语句declare中的tick的详解[整理版]
- PHP基础之流程控制7——declare语句
- PHP入门教程之操作符与控制结构流程详解
- 【PHP学习】控制结构/文件包含语句
- PHP读书笔记整理_结构语句详解
- 关于php的declare语句中的tick的解释 [转]
- PHP入门教程之操作符与控制结构流程详解
- PHP读书笔记整理_结构语句详解
- php5与mysql5 web 开发技术详解-4 php控制结构和函数
- 用PHP控制浏览器cache obstart()函数详解
- PHP流程控制之分支结构
- PHP 正则 email语句详解
- php流程控制语句
- 第01章 CORE C++_C++ 基本结构_注释_输出语句_输入语句_初始化_条件控制_ASCII码值_转义字符_常量_变量_类型长度_运算符
- PHP 正则 email语句详解
- LAMP兄弟连原创视频教程(PHP笔记一--变量,流程控制结构,函数)
- PHP 正则 email语句详解
- PHP 正则 email语句详解
- shell程序设计-<控制结构>-case语句