phpのini_set("max_execution_time",n)とset_time_limitの違いについて調べた
背景
phpでスクリプトのタイムアウト上限を伸ばすには2つの方法がある。
- set_time_limitを呼ぶ方法
php.ini
もしくはini_set
でmax_execution_timeを変更する方法
このうちset_time_limit
のドキュメントにこのような記述がある。
デフォルトの制限値は 30 秒です。 なお、php.iniでmax_execution_timeの 値が定義されている場合にはそれを用います。
これを僕は「常にmax_execution_timeが優先される」ように解釈した。調べてみた。
結論
「常にmax_execution_timeが優先される」ようなことはない。
set_time_limit
はini_set('max_execution_time', n)
のラッパーというだけな気がする。
調査
$ php -v PHP 7.0.14 (cli) (built: Apr 1 2017 23:41:23) ( NTS ) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
まずは実際に挙動を確認
<?php // 初期値を確認 var_dump(ini_get("max_execution_time")); // ini_setで上限値を更新 ini_set("max_execution_time", 60); var_dump(ini_get("max_execution_time")); // set_time_limitで上限値を更新 set_time_limit(120); var_dump(ini_get("max_execution_time"));
コマンドライン経由だとmax_execution_time
は0になるので、ビルトインサーバーを起動してリクエストを投げることで確認した。
-- ビルトインサーバー起動 $ php -S localhost:9000 -- 別コンソールからリクエスト実行 $ curl "http://localhost:9000/sample.php" string(2) "30" string(2) "60" string(3) "120"
もし「max_execution_timeが優先される」なら最後の出力は30もしくは60になるはずだが、実際はちゃんと値が更新されている。
だとすると、ドキュメントの一文は何を意味するのか。
英語の原文を見る
英語のドキュメントだとこう書かれている。
The default limit is 30 seconds or, if it exists, the max_execution_time value defined in the php.ini.
「デフォルト値は30秒だが、もしphp.iniにmax_execution_timeの定義があればそれをデフォルト値とする」という意味に読める。
言葉の意味は分かるが、そもそもset_time_limit
は引数が必須だ。このデフォルト値とは何のことなのか。一応php本体のコードも読むことにした。
PHP本体のソースを読む
ざっくりとしか読んでいないので間違いはあるかもしれない。
- ini_setはzend_alter_ini_entry_exを通して更新する
- set_time_limitはzend_alter_ini_entry_chars_exを呼ぶ
- 内部でini_setと同じくzend_alter_ini_entry_exを呼ぶ
set_time_limit
引数の値をそのまま使うので、どこかからデフォルトを持ってきてどうこうすることはない
処理的には両者に違いはほとんどない。
デフォルト値がどう関係するかといえば次に書く通り。
どちらも設定値を上書きするたびにカウンタはリセットされる
set_time_limit
のドキュメントより。
この関数がコールされた場合、 タイムアウトカウンタをゼロから再スタートします。 言いかえると、タイムアウトがデフォルトの 30 秒で スクリプト実行までに 25 秒かかる場合に、 set_time_limit(20) を実行すると、スクリプトは、 タイムアウトまでに全体で 45秒 の間実行されます。
つまり、以下のコードはタイムアウトにならずに無限ループになる。
<?php while (true) { set_time_limit(1); // ini_setの場合も同じ // ini_set("max_execution_time", 1); }
なお、これを実際に試すとプロセスを直接killしないとCPU100%でずっと走り続けるので注意。
本体のソースコードを読んで「これini_setも同様にゼロから再スタートするのでは」と思って試した。
この挙動はset_time_limit
だけだと勝手に思っていたが、ini_set('max_execution_time', n)
でも同様だった。
ドキュメント的にもmax_execution_time
の項にはset_time_limit
を参照するように書かれているわけなので正しい。
ちなみに手元のphp.ini
は最初からmax_execution_time
が30秒で設定されていたが、仮に設定がなくてもphp本体が30秒をデフォルト値にしている。
要は「タイムアウト値のデフォルトはmax_execution_time
に依存する」というだけの話だと思う。