# 附录\*PHP的ticks机制

PHP提供declare关键字和ticks关键字来声明ticks机制。如：declare(ticks = N); 这表示：在当前scope内，每执行N句internal statements（opcodes），就会中断当前的业务语句，去执行通过register\_tick\_function注册的函数（如果存在的话），然后再继续之前的代码。需要注意的是这里的N是指的PHP的一些OPCODE，而OPCODE与我们见到的PHP语句却不是一一对应的。

实例1：

```php
    $name = "phppan";
    echo $name;
    class Tipi {
        public function test() {
            echo "test";
        }
    }
    function f_tipi() {
    }
```

如上代码包括了我们常见的几种语句，赋值，输出，定义类，定义函数。通常我们用VLD查看PHP生成的中间代码，上面的代码通过**php -dvld.active=1 t.php**我们会看到 ECHO、ASSIGN、NOP等中间代码，如下所示：

```
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /home/revin/work/code/test/1.php
function name:  (null)
number of ops:  7
compiled vars:  !0 = $name
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   EXT_STMT                                                 
         1        ASSIGN                                                   !0, 'phppan'
   3     2        EXT_STMT                                                 
         3        ECHO                                                     !0
   4     4        EXT_STMT                                                 
   9     5        EXT_STMT                                                 
  10     6      > RETURN                                                   1

branch: #  0; line:     2-   10; sop:     0; eop:     6; out1:  -2
path #1: 0, 
Function f_tipi:
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /home/revin/work/code/test/1.php
function name:  f_tipi
number of ops:  3
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   9     0  E >   EXT_NOP                                                  
  10     1        EXT_STMT                                                 
         2      > RETURN                                                   null

branch: #  0; line:     9-   10; sop:     0; eop:     2; out1:  -2
path #1: 0, 
End of function f_tipi

Class Tipi:
Function test:
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /home/revin/work/code/test/1.php
function name:  test
number of ops:  5
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   5     0  E >   EXT_NOP                                                  
   6     1        EXT_STMT                                                 
         2        ECHO                                                     'test'
   7     3        EXT_STMT                                                 
         4      > RETURN                                                   null

branch: #  0; line:     5-    7; sop:     0; eop:     4; out1:  -2
path #1: 0, 
End of function test

End of class Tipi.

phppan
```

现在我们在示例1的代码上添加上ticks机制。如PHP代码示例2：

```php
    declare(ticks=1);
    $name = "phppan";
    echo $name;
    class Tipi {
        public function test() {
            echo "test";
        }
    }
    function f_tipi() {
    }
```

示例2与示例1相比也就是多了第一条语句： declare(ticks=1); 如果我们此时再次通过VLD查看中间代码，会发现在每个中间代码的后面都多了一句中间代码：**TICKS**。

```
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /home/revin/work/code/test/1.php
function name:  (null)
number of ops:  13
compiled vars:  !0 = $name
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   EXT_STMT                                                 
         1        TICKS                                                    
   3     2        EXT_STMT                                                 
         3        ASSIGN                                                   !0, 'phppan'
         4        TICKS                                                    
   4     5        EXT_STMT                                                 
         6        ECHO                                                     !0
         7        TICKS                                                    
   5     8        EXT_STMT                                                 
         9        TICKS                                                    
  10    10        EXT_STMT                                                 
  11    11        TICKS                                                    
        12      > RETURN                                                   1

branch: #  0; line:     2-   11; sop:     0; eop:    12; out1:  -2
path #1: 0, 
Function f_tipi:
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /home/revin/work/code/test/1.php
function name:  f_tipi
number of ops:  3
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
  10     0  E >   EXT_NOP                                                  
  11     1        EXT_STMT                                                 
         2      > RETURN                                                   null

branch: #  0; line:    10-   11; sop:     0; eop:     2; out1:  -2
path #1: 0, 
End of function f_tipi

Class Tipi:
Function test:
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename:       /home/revin/work/code/test/1.php
function name:  test
number of ops:  6
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   6     0  E >   EXT_NOP                                                  
   7     1        EXT_STMT                                                 
         2        ECHO                                                     'test'
         3        TICKS                                                    
   8     4        EXT_STMT                                                 
         5      > RETURN                                                   null

branch: #  0; line:     6-    8; sop:     0; eop:     5; out1:  -2
path #1: 0, 
End of function test

End of class Tipi.

phppan
```

是否因为ticks=1的原因而在每个中间代码的后面添加了TICKS？将declare(ticks=1);换成declare(ticks=100);，再次VLD，结果没有变化。从以上的结果可以看出，PHP内核在语法分析过程中实现了ticks机制。

## 声明ticks机制过程

声明的过程就是调用declare(ticks = N); 在语法分析时根据declare关键字和参数中的ticks关键字来声明ticks机制。通过zend\_compile.c文件中的zend\_do\_declare\_begin、declare\_statement、zend\_do\_declare\_end三个函数来编译声明ticks机制。在declare\_statement函数中我们可以看到：declare除了可以声明ticks之外，还可以声明encoding，这在代码里面就是一个if else的判断。

ticks机制的声明仅在编译过程有用，它为后面的声明控制语句服务。其编译过程中的全局变量为：CG(declarables)。这是一个结构体，它仅有一个成员：ticks。当然后面应该还会有更多的成员出现。

## 声明控制语句

示例1和示例2已经充分说明在每条语句的语法分析时，会根据是否声明了ticks机制来添加TICKS中间代码，其实现在于每条语句在语法解析时都会添加一条函数调用：zend\_do\_ticks。从zend\_language\_parser.y文件中可以看出：zend\_do\_ticks函数添加在类定义语句，函数定义语句和常规语句的后面。 zend\_compile.c文件中的zend\_do\_ticks函数会根据前面提到的 CG(declarables).ticks 来判断是否生成 ZEND\_TICKS 中间代码（在VLD中看到的中间代码都是没有ZEND开头）。

除了声明ticks机制，还有执行。执行过程中关键的变量是在声明时的ticks=N。其实这里的N可以换个角度去理解：ticks指定的数字是指执行了多少次TICKS语句。在TICKS中间代码的执行函数ZEND\_TICKS\_SPEC\_CONST\_HANDLER中，会统计执行当前函数的次数，存储变量为EG(ticks\_count)。当达到当初声明的界限，就会调用一次所有通过register\_tick\_function注册的函数，并计数清零。

与当初自己设想的实现相比，PHP内核对ticks机制的实现满足了功能单一原则和松耦合原则。将ticks机制作为一个中间代码添加到整个中间代码的执行体系中，包括状态的转移，函数的切换这些都是直接使用原有的机制。

## ticks机制的应用场景

手册上说：Ticks 很适合用来做调试，以及实现简单的多任务，后台 I/O 和很多其它任务。

在调试过程中，对于定位一段特定代码中速度慢的语句比较有用，我们可以每执行两条低级语句就记录一次时间。虽然这个过程也可以用其它方法完成，但用 tick 更方便也更容易实现。

PCNTL也使用ticks机制来作为信号处理机制（signal handle callback mechanism），可以最小程度地降低处理异步事件时的负载。这里的关键在于PCNTL扩展的模块初始化函数（PHP\_MINIT\_FUNCTION(pcntl)）。在此模块做模块初始化时，它会调用： php\_add\_tick\_function(pcntl\_signal\_dispatch);将pcntl的分发执行函数添加到ticks机制的调用函数中去，从而当ticks触发时就会调用PCNTL扩展函数中指定的所有方法。

## 资料

[PHP的ticks机制](http://www.codesky.net/article/201306/181874.html)

[php手册里，pcntl\_signal函数解释，很多例子前面declare(ticks=1)这句话的意义](http://blog.chinaunix.net/uid-26363964-id-3938401.html)

[你知道PHP信号处理的正确打开方式吗？](http://www.jianshu.com/p/c3fb535ecd8b)

[PHP官方的pcntl\_signal性能极差](http://rango.swoole.com/archives/364)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://php7.shujuwajue.com/fu-5f55-php-de-ticks-ji-zhi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
