php控制结构语句declare中的tick的详解[整理版]
来源:互联网 发布:如何选笔记本电脑 知乎 编辑:程序博客网 时间:2024/06/03 20:34
先看看手册是怎么说的:
declare 结构用来设定一段代码的执行指令。declare 的语法和其它流程控制结构相似:
1
declare
(directive)
2
statement
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部分用 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 NOP
03
2:
04
3:
function
doTicks ()
05
4: {
06
5:
echo
'Ticks'
;
07
0
ECHO
'Ticks'
08
6: }
09
1 RETURN null
10
7: register_tick_function(
'doTicks'
);
11
1 SEND_VAL
'doTicks'
12
2 DO_FCALL
'register_tick_function'
[extval:1]
13
8:
declare
(ticks = 1) {
14
9:
for
(
$x
= 1;
$x
< 10; ++
$x
) {
15
3 ASSIGN !0, 1
16
4 IS_SMALLER !0, 10 =>RES[~2]
17
5 JMPZNZ ~2, ->14 [extval:8]
18
6 PRE_INC !0
19
7 JMP ->4
20
10:
echo
$x
*
$x
.
'<br />'
;
21
8 MUL !0, !0 =>RES[~4]
22
9 CONCAT ~4,
'<br />'
=>RES[~5]
23
10
ECHO
~5
24
11 TICKS 1 =>RES[]
25
11: }
26
12 TICKS 1 =>RES[]
27
13 JMP ->6
28
14 TICKS 1 =>RES[]
29
12: }
30
15 TICKS 1 =>RES[]
31
16 RETURN 1
很明显,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的三条语法规则:
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
;
也就是说,PHP编译会在statement(语句), function_declaration_statement(函数定义语句), class_declaration_statement后插入TICKS处理函数,即它会在每条statement,函数声明,类(实际上还包括接口)声明后插入一条TICKS指令。
函数与类声明语句比较好理解,根据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 = get_next_op_number(CG(active_op_array)); } expr
')'
{ zend_do_while_cond(&
$4
, &
$5
TSRMLS_CC); } while_statement { zend_do_while_end(&
$1
, &
$5
TSRMLS_CC); }
06
| T_DO {
$1
.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE
'('
{
$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 { zend_do_for_end(&
$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
';'
{ zend_do_brk_cont(ZEND_BRK, NULL TSRMLS_CC); }
18
| T_BREAK expr
';'
{ zend_do_brk_cont(ZEND_BRK, &
$2
TSRMLS_CC); }
19
| T_CONTINUE
';'
{ zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); }
20
| T_CONTINUE expr
';'
{ zend_do_brk_cont(ZEND_CONT, &
$2
TSRMLS_CC); }
21
| T_RETURN
';'
{ zend_do_return(NULL, 0 TSRMLS_CC); }
22
| T_RETURN expr_without_variable
';'
{ zend_do_return(&
$2
, 0 TSRMLS_CC); }
23
| T_RETURN variable
';'
{ zend_do_return(&
$2
, 1 TSRMLS_CC); }
24
| T_GLOBAL global_var_list
';'
25
| T_STATIC static_var_list
';'
26
| T_ECHO echo_expr_list
';'
27
| T_INLINE_HTML { zend_do_echo(&
$1
TSRMLS_CC); }
28
| expr
';'
{ 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
, 1 TSRMLS_CC); }
32
foreach_variable foreach_optional_arg
')'
{ zend_do_foreach_cont(&
$1
, &
$2
, &
$4
, &
$6
, &
$7
TSRMLS_CC); }
33
foreach_statement { zend_do_foreach_end(&
$1
, &
$4
TSRMLS_CC); }
34
| T_FOREACH
'('
expr_without_variable T_AS
35
{ zend_do_foreach_begin(&
$1
, &
$2
, &
$3
, &
$4
, 0 TSRMLS_CC); }
36
variable foreach_optional_arg
')'
{ zend_check_writable_variable(&
$6
); zend_do_foreach_cont(&
$1
, &
$2
, &
$4
, &
$6
, &
$7
TSRMLS_CC); }
37
foreach_statement { zend_do_foreach_end(&
$1
, &
$4
TSRMLS_CC); }
38
| T_DECLARE {
$1
.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); }
'('
declare_list
')'
declare_statement { zend_do_declare_end(&
$1
TSRMLS_CC); }
39
|
';'
/* empty statement */
40
| T_TRY { zend_do_try(&
$1
TSRMLS_CC); }
'{'
inner_statement_list
'}'
41
T_CATCH
'('
{ zend_initialize_try_catch_element(&
$1
TSRMLS_CC); }
42
fully_qualified_class_name { zend_do_first_catch(&
$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 { zend_do_mark_last_catch(&
$7
, &
$18
TSRMLS_CC); }
46
| T_THROW expr
';'
{ zend_do_throw(&
$2
TSRMLS_CC); }
47
| T_GOTO T_STRING
';'
{ zend_do_goto(&
$2
TSRMLS_CC); }
48
;
根据上面的定义,我们知道,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操作等等。
- php控制结构语句declare中的tick的详解[整理版]
- php控制结构语句declare中的tick的详解[整理版]
- php控制结构语句declare中的tick的详解[整理版]
- php控制结构语句declare中的tick的详解
- 关于php的declare语句中的tick的解释 [转]
- php中declare的作用详解
- php 中的declare
- php的控制语句
- 流程控制语句的整理
- php的declare查看
- 【PHP学习】控制结构/文件包含语句
- sysClkRateGet();返回系统时钟每秒的tick数量, tick详解!
- 嵌套的控制结构、其他控制语句
- PHP中的语言结构详解
- 9.PHP中的流程控制结构
- php declare 的应用场景?
- declare语句
- [归纳]PHP手册重读与整理-控制结构
- Trie树
- 姐们儿 想减肥深夜别吃这些东西
- Java常用工具类四
- android 布局权重问题(最近布局经常坑爹)
- 淘宝商城servlet的路径web.xml部分
- php控制结构语句declare中的tick的详解[整理版]
- 字典树
- SQLServer如何导入excel
- 淘宝商城jsp部分
- SQL笔记--第四章
- C语言位运算、数据类型
- 为什么我刚才写的一篇博客,提交成功后又不见了...
- 修改通达OA Mysql数据库密码
- Java常用工具类五 -- 文件处理相关