tickにまつわるエトセトラ
はじめに
普通に PHP を使っている中では、まずお目にかかることが無いであろう機能の一つに declare(ticks=N);
があります (というか最近初めて知りました)。
あんまり使う機会は無いですが、調査したことを書いておきます。
tick とは
PHP マニュアルに以下の記述があります。
tickとはdeclareブロックの実行中にパーサが N個の低レベル tick 可能な文を実行するごとに 発生するイベントのことです。Nの値は declareブロックのディレクティブの箇所で ticks=Nのように 指定します。
実際に使ってみると declare(ticks=N);
と記述すると、tick 可能な文がN回実行される毎に register_tick_function
が呼び出される、という挙動になります。
<?php
// ハンドラを定義
function my_tick_function() {
echo 'A tick has occurred.' . PHP_EOL;
}
// register_tick_function でハンドラを登録
register_tick_function('my_tick_function');
declare(ticks=1);
for ($i = 0; $i < 5; $i++) {
echo 'In the loop: $i' . PHP_EOL;;
}
% php ticks.php
A tick has occurred.
In the loop: 0
A tick has occurred.
In the loop: 1
A tick has occurred.
In the loop: 2
A tick has occurred.
In the loop: 3
A tick has occurred.
In the loop: 4
A tick has occurred.
A tick has occurred.
何に使うの?
文毎にログを出したり、文と文の間の microtime を出力して性能検証をしたりする、という使い方もあるようです。あるいは、シグナルハンドラをディスパッチするために利用するというのが多いんじゃないでしょうか。
<?php
declare(ticks=1);
$receivedSigterm = false;
pcntl_signal(SIGTERM, function() use (&$receivedSigterm) {
echo 'SIGTERM received.' . PHP_EOL;
$receivedSigterm = true;
});
pcntl_signal(SIGINT, function() use (&$receivedSigterm) {
echo 'SIGINT received.' . PHP_EOL;
$receivedSigterm = true;
});
echo 'PID: ' . getmypid() . PHP_EOL;
while (!$receivedSigterm) {
echo 'Working...' . PHP_EOL;
sleep(1);
}
% php signals-dispatch.php
PID: 67626
Working...
Working...
Working...
^CSIGINT received. # control + C
% php signals-dispatch.php
PID: 67601
Working...
Working...
Working...
Working...
SIGTERM received. # kill 67601
例えば cli でバッチ処理などの比較的長時間生存するプロセスがあったとして、kill されたときに安全に終了するために利用することが考えられます。PHP でバッチ処理を実現する是非については置いておくとして。
何で見かけないの?
ただし、当然ながら tick 可能な文が無いとディスパッチされません。そして tick には少なくないオーバーヘッドがあります。
PHP 7.1からは tick のシグナルハンドラのディスパッチ機能の代替として pcntl_async_signals(true)
が実装されました。
<?php
pcntl_async_signals(true);
pcntl_signal(SIGTERM, function() use (&$receivedSigterm) {
echo 'SIGTERM received.' . PHP_EOL;
exit;
});
pcntl_signal(SIGINT, function() use (&$receivedSigterm) {
echo 'SIGINT received.' . PHP_EOL;
});
echo 'PID: ' . getmypid() . PHP_EOL;
while (true) {
// tick 可能な文が無い => declare(ticks=1); だと、ハンドラは実行されない
}
また、tick にまつわる PHP 5系のバグが PHP 7で修正されました。
これにより、このバグに依存したライブラリやプラグインがもろに影響を受けて淘汰されてしまった、ということも見かけない理由の一つかと思われます。今後は削除される?
一応、非推奨化/削除の RFC が過去に出されたことがあります。
しかしながら、それなりのインストール数のある WordPress プラグインでプロファイリングとしての利用があることなどから、後に撤回されています。
確かに、WordPress 環境では Xdebug や外形的なプロファイラを用意することができないこともあるので、機能ごと切り捨てるのは難しそうですね。
また、議論の中で名前のあがっていた WordPress プラグインは先の PHP 5系でのバグ依存だった実装を修正して生き残ったという歴史があります。
ただ、数年前からメンテが止まっているようで、公式ディレクトリからも2022年からダウンロードができなくなっているようです。
おわりに
特にオチはありません。
Discussion