ZEND_TICKS と tick 関数
この記事は 闇PHP Advent Calendar 2015 4日目 です
tick について
ZEND_TICKS とは、tick 不可能行*1の後に発行されるオペコードで、多くは、セミコロンで終わるステートメントごとに発行されます。
ただし、デフォルトでは発行されず、利用するためには declare 命令で明示的に有効にする必要があります。
declare 命令の ticks で指定した回数の ZEND_TICKS が呼ばれるごとにregister_tick_function で登録した関数 (tick 関数) が実行されます。
code.1 と code.2 は(内部的には異なりますが)表面上同じ動きをします。
code.1
<?php function tick() { echo "tick!" . PHP_EOL; } register_tick_function('tick'); declare(ticks=1); $a = 1; if ($a < 10) { echo $a . PHP_EOL; }
code.2
<?php function tick() { echo "tick!" . PHP_EOL; } tick(); $a = 1; tick(); if ($a < 10) { tick(); echo "{$a}" . PHP_EOL; tick(); tick(); } tick();
echo の後に 2回 tick が走りますが、これは誤りではなく、echo による tick と if の条件内ステートメントリスト(表面上は見えない) による tick です。
declare(tick=N) の有効範囲
declare による ticks の有効範囲は、少々特殊なので注意が必要です。
declare(ticks=1); declare(ticks=1) {}
のように、単文あるいは空ブロックで指定された場合、ファイル内の declare 以降全てが範囲となり、
declare(ticks=1) sleep(1); declare(ticks=1) { sleep(1); echo "hoge"; }
のように、他の文を伴った場合は、その文やブロックのみが範囲となります。
あまり使うことはないと思いますが、ブロックは入れ子にすることも出来ます。
また、ticks は別ファイルには影響しない事にも注意が必要です。
これは、 ZEND_TICKS の発行がコンパイル時に行われるためです。
ZEND_TICKS オペコードが発行されている部分(ticks > 0)のスクリプト実行は、発行されていない部分と比較して (オペコードや tick 関数を処理する分) オーバヘッドがあることに注意しましょう。
code.3
<?php // ticks=0 (初期値 ZEND_TICKS 発行なし) declare(ticks=1); // tick=1 declare(ticks=2) { [any code] // ticks=2 } // ticks=1 require 'hoge.php'; // hoge.php には ticks は引き継がれない (ticks=0 で開始される) echo "any code"; // もちろんここでも tick=1 のまま