PHPにはexec関数があります。
これを使って他スクリプトを起動する時…
- 別のPHPスクリプトを起動したい
- ただし独立した別プロセスで動かしたい
- つまり非同期的に実行したかった
こういう感じで使う方法を探していました。
これには一部OS固有の方法が必要になります。
それも含めて具体的コード例をまとめました。
このページの目次
そもそもexec関数は何なのか?デフォルトの挙動
公式では次のように説明されています。
▼ php.netでのexec関数の解説
exec(string $command, array &$output = null, int &$result_code = null): string|false
exec() は指定されたコマンド command を実行します。戻り値 : コマンド結果の最後の行を返します。コマンドを実行し、 一切干渉を受けずに直接コマンドから全てのデータを受けとる必要が あるならば、passthru() 関数を使ってください。失敗時に false を返します。
▼ こんな感じで使える
1 2 |
/// 別スクリプトを起動 exec('php hoge.php'); |
たったこれだけですが・・・
問題は結果が返るまで待つことです。
普通の用途なら問題ないけど、Cronジョブで重い処理を別プロセスで実行したい場合、exec関数をそのまま使うのはメインプロセスで全部やるのと変わりません。
つまり「exec関数は無条件では別プロセスにならない」ということです。でも戻り値を気にしないなら、別プロセスとして起動することも可能です。
exec関数で非同期な別プロセスを作るコード例
ポイントは次の2点
- 実行されるスクリプトの出力を捨てる
- OS(Win/Linux)ごとに少し工夫が必要
これを考慮すれば別プロセスが起動できます。
例えば次のようなコードがその例です。
▼ exec()で別プロセス起動のコード例
1 2 3 4 5 6 7 8 9 10 11 12 |
/// 実行したいコマンド本体 $command = "php hoge.php"); /// OSごとに少し起動方法を変える if((substr(PHP_OS, 0, 3) !== 'WIN')){ /// Linux系OSの場合 exec($command . ' >/dev/null 2>&1 &'); }else{ /// Windows系OSの場合 $fp = popen('start "" '.$command, 'r'); pclose($fp); } |
重要なのは実行されるスクリプトの出力を廃棄することです。ファイルに書き出すという意味ではなく、データそのものを虚無に返しています。
そのためにLinuxでは /dev/null という特別なデバイスファイルがあり、Windowsでは nul というのが用意されてます( null ではなく nul なのが紛らわしい...)
- Linux : /dev/null に捨てる
- Windows : nul に捨てる
Macの場合も恐らく /dev/null のはずです。
ちなみにLinuxの処理にある >dev/null 2>&1 & は標準出力・エラー出力を破棄・バックグラウンド実行(&)するという意味です。
関連 - PHPプロセスの多重起動の防止について
少しだけ関係があるので蛇足で紹介
複数プロセスの多重起動禁止についてです。
▼ 例えばこういうケース
- あるスクリプトをCronなどで定期実行
- その間は同一スクリプトの起動を禁止
- 複数プロセスを存在させたくない
今回のように別プロセスを動かしたり、Cronジョブからスクリプトを定期実行する場合、プロセスを多重起動させたくないこともあるはずです。
そういう時は ▼次記事 でも解説したように、flockによる排他的ロックを使えば複数プロセス起動を阻止できます(Windows・Linux両方対応 プラットフォーム関係なし)
こういう知恵が必要になる時も極まれにあります。
良ければ参考までにご覧ください。
まとめ - バックグラウンド処理とかで活用できるかも
ここまでの方法は次の場面で役立つかも
- サーバーでCronジョブなど動かす
- その時、重い処理は別プロセスで実行
- 例えばメール送信・ファイル操作など
とはいえ滅多に使うことはないはずです。
こういう方法もあると学んだので記事にしました。
以上、PHPのexec()で別プロセス起動でした。