Search code examples
phpcontrol-structure

Understanding PHP declare() and ticks


Today I was looking through the php manual and stumbled upon a control structure declare.

The declare construct is used to set execution directives for a block of code

This is what declare is supposed to do. To be honest I didn't understood it. On reading again it found a new thing Ticks

A tick is an event that occurs for every N low-level tickable statements executed by the parser within the declare block. The value for N is specified using ticks=N within the declare block's directive section.

I didn't understand it either. what does it mean by N low-level tickable statements If there had been a good sample code, then it would have been easy to understand. But none was found in the manual. I have found some on SO Q1, which actually increased my curiosity and confusion. So can anyone what is this for and where can we use this.

My actual confusion is with this statement (from the linked so post) you can declare a tick-function which checks each n executions of your script whether the connection is still alive or not. So when I register a tick function with tick = 20 on a php file and execute it, the file will be alive till 20 execution is complete(got this idea when it was wrongly considered as multithreaded). This is the idea i have got, I dont think its correct..

Or is it a simple replacement for while($x = 20)

[EDIT 1]
I have also seen the implementation of declare() another section of php manual Function arguments

[EDIT 2]
Also in Process Control

You use the declare() statement to specify the locations in your program where callbacks are allowed to occur. This allows you to minimize the overhead of handling asynchronous events


Solution

  • When PHP is executing your script, the execution can be seen as a lot of statements being executed. Most statements cause a Tick, though not necessarily all statements do so. (Manual says: Typically, condition expressions and argument expressions are not tickable.)

    This block would normally cause 5 ticks, as you are executing 5 statements:

    $a = 1;
    $B = 2;
    $a = 3;
    $B = 4;
    $a = 5;
    

    And this block would normally cause 5 ticks, and one more tick as the end of the while loop also is counted as a statement/tick:

    while ($i < 5)
        $a++;
    

    With the help of declare(ticks=N) and register_tick_function(), you can now execute code in between the statements/ticks. The register_tick_function specifies which function should be called when a tick event occurs. And the declare sets how many tick should pass, before a tick event occurs.

    With declare(ticks=1) and register_tick_function('someFunction'); you will call someFunction() code in between every statement/tick.

    If you use declare(ticks=3), then someFunction() will be executed on every third statement/tick.

    Example:

    function handler(){
        echo "x";
    }
    register_tick_function("handler");
    $i = 0;
    declare(ticks = 4) {
        while ($i < 9)
            echo ++$i;
    }
    

    This script will output: 1234x5678x9 It's that simple.

    Now what is meant in the linked question with "whether the connection is still alive", is not really interesting on itself and is not actually related to the above mentioned. It is just something you COULD do on every tick event. But you can also do something totally different. What is mentioned is simply that some scripts can take quite some time to execute and that during the execution, the client can disconnect. (Imagine closing the browser, while the script is still running.) PHP will by default continue to run the script, even if the client has disconnected. You can use the function connection_aborted() to detect if the client has disconnected. This is something you COULD also do without using ticks at all.

    Now let's say for example that you want your script to stop running as soon as the client disconnects. Simply use ...

    function killme() {
        if (connection_aborted()) {
            die();
        }
    }
    register_tick_function('killme');
    declare(ticks=1);
    

    ... and your script will call killme() after each statement of your code. killme() will check if the client is still connected and die() when it isn't.