【PHP8.x】proc_terminate()関数の使い方
proc_terminate関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
proc_terminate関数は、PHPのプロセス制御拡張モジュールで使用される関数で、popen()関数によって開始されたプロセスを終了させるために使用されます。popen()関数は、シェルコマンドを実行し、その入出力をファイルポインタとして扱うことができるようにする関数です。proc_terminate関数は、popen()関数によって返されたファイルポインタを引数として受け取り、そのファイルポインタに関連付けられたプロセスにSIGTERMシグナルを送信することで、プロセスの終了を試みます。
SIGTERMシグナルは、プロセスに対して正常な終了を要求するシグナルです。ほとんどのプロセスはSIGTERMシグナルを受け取ると、実行中の処理を中断し、後処理を行った後に終了します。しかし、プロセスがSIGTERMシグナルを無視したり、適切に処理しない場合、プロセスは終了しません。
proc_terminate関数は、プロセスがSIGTERMシグナルに応答しない場合でも、プロセスの終了を保証するものではありません。より強制的にプロセスを終了させる必要がある場合は、proc_close()関数を使用するか、オペレーティングシステムのコマンド(killコマンドなど)を使用する必要があります。proc_close()関数は、内部的にproc_terminate関数を呼び出し、その後ファイルポインタを閉じます。
この関数は、プロセスを安全に終了させるための第一歩として利用できます。特に、長時間実行される可能性のある外部プロセスを制御する場合に有効です。プロセスが終了しない場合は、より強力な手段を検討する必要があります。また、PHPスクリプトの実行ユーザーが、終了させようとしているプロセスを操作する権限を持っている必要があります。権限がない場合、proc_terminate関数は失敗する可能性があります。
構文(syntax)
1proc_terminate(resource $process, int $signal = 15): bool
引数(parameters)
$process, int $signal = 15
- resource|open_resource $process: 終了させるプロセスを指定するリソース
- int $signal = 15: プロセスに送信するシグナルを指定する整数。デフォルトは15 (SIGTERM)
戻り値(return)
bool
指定されたプロセスを終了させることができるかどうかを示します。成功した場合はtrue、失敗した場合はfalseを返します。
サンプルコード
PHPで外部プロセスを終了し状態確認
1<?php 2 3/** 4 * 外部プロセスを起動し、proc_terminate で終了させ、 5 * proc_get_status でその状態変化を確認するサンプルコードです。 6 * 7 * システムエンジニアを目指す初心者向けに、外部プロセスの基本的な制御方法を示します。 8 */ 9function manageExternalProcessWithTermination(): void 10{ 11 echo "--- 外部プロセス管理の開始 ---\n"; 12 13 // 実行するコマンドを定義します。 14 // この例では、5秒間待機するコマンドを実行します。 15 // Unix/Linux/macOSの場合: 'sleep 5' 16 // Windowsの場合の代替例: 'ping 127.0.0.1 -n 5 > NUL' 17 $command = 'sleep 5'; 18 19 // プロセス記述子 (stdin, stdout, stderr のパイプを定義) 20 // これにより、PHPスクリプトから外部プロセスの入出力を制御できます。 21 $descriptorspec = [ 22 0 => ['pipe', 'r'], // 標準入力 (stdin): PHPからプロセスへデータを送るためのパイプ 23 1 => ['pipe', 'w'], // 標準出力 (stdout): プロセスからPHPへデータを受け取るためのパイプ 24 2 => ['pipe', 'w'], // 標準エラー出力 (stderr): プロセスのエラーをPHPで受け取るためのパイプ 25 ]; 26 27 $pipes = []; // パイプのリソースを格納する配列 28 29 // 外部プロセスを起動します。 30 // proc_open はプロセスリソースとパイプの配列を返します。 31 $process = proc_open($command, $descriptorspec, $pipes); 32 33 if (!is_resource($process)) { 34 echo "エラー: 外部プロセスを起動できませんでした。\n"; 35 return; 36 } 37 38 echo "外部プロセスを起動しました。\n"; 39 40 // 起動直後のプロセスの状態を取得します。 41 // proc_get_status は、プロセスの現在の状態に関する情報を配列で返します。 42 $statusBeforeTerminate = proc_get_status($process); 43 44 if ($statusBeforeTerminate === false) { 45 echo "エラー: 起動直後のプロセスの状態を取得できませんでした。\n"; 46 proc_close($process); 47 return; 48 } 49 50 echo "\n--- 起動直後のプロセス状態 ---\n"; 51 echo " PID: " . $statusBeforeTerminate['pid'] . "\n"; 52 echo " 実行中: " . ($statusBeforeTerminate['running'] ? 'はい' : 'いいえ') . "\n"; 53 echo " コマンド: " . $statusBeforeTerminate['command'] . "\n"; 54 55 // プロセスが実際に実行中であることを確認します。 56 if ($statusBeforeTerminate['running']) { 57 echo "\nプロセスは正常に起動しています。2秒間待機し、その後強制終了します。\n"; 58 sleep(2); // 2秒間待機します。 59 60 echo "proc_terminate() を使用してプロセスを終了させます (デフォルトシグナル: SIGTERM 15)。\n"; 61 // proc_terminate は、指定されたシグナルをプロセスに送信します。 62 // デフォルトでは SIGTERM (終了要求) を送信します。 63 $terminatedSuccessfully = proc_terminate($process); 64 65 if ($terminatedSuccessfully) { 66 echo "プロセスに終了シグナルが正常に送信されました。\n"; 67 } else { 68 echo "エラー: プロセスを終了できませんでした。\n"; 69 } 70 71 // シグナル送信後、プロセスの状態が変化するまで少し待つ場合があります。 72 sleep(1); 73 74 // 終了シグナル送信後のプロセスの状態を再度取得します。 75 $statusAfterTerminate = proc_get_status($process); 76 77 if ($statusAfterTerminate === false) { 78 echo "エラー: 終了シグナル送信後のプロセスの状態を取得できませんでした。\n"; 79 } else { 80 echo "\n--- proc_terminate() 後のプロセス状態 ---\n"; 81 echo " PID: " . $statusAfterTerminate['pid'] . "\n"; 82 echo " 実行中: " . ($statusAfterTerminate['running'] ? 'はい' : 'いいえ') . "\n"; 83 echo " 終了コード: " . $statusAfterTerminate['exitcode'] . "\n"; 84 // 'termsig' は、プロセスがシグナルによって終了した場合のシグナル番号を示します。 85 echo " シグナルによる終了: " . ($statusAfterTerminate['termsig'] > 0 ? 'はい (シグナル: ' . $statusAfterTerminate['termsig'] . ')' : 'いいえ') . "\n"; 86 echo " 停止中: " . ($statusAfterTerminate['stopped'] ? 'はい' : 'いいえ') . "\n"; 87 // proc_terminate が成功した場合、'running' は false になり、'termsig' は 15 (SIGTERM) になることが期待されます。 88 } 89 90 } else { 91 echo "プロセスが起動していないか、すぐに終了しました。\n"; 92 } 93 94 // 開いたパイプをすべて閉じます。 95 foreach ($pipes as $pipe) { 96 fclose($pipe); 97 } 98 99 // プロセスリソースを閉じ、最終的な終了コードを取得します。 100 // これは外部プロセスが終了するまでブロックします。 101 $returnCode = proc_close($process); 102 echo "\nプロセスリソースを閉じました。最終的な戻りコード: " . $returnCode . "\n"; 103 104 echo "--- 外部プロセス管理の終了 ---\n"; 105} 106 107// 関数を実行します。 108manageExternalProcessWithTermination(); 109
proc_terminate関数は、PHPから起動した外部プロセスに対して終了シグナルを送信し、そのプロセスを終了させるために使用されます。第一引数$processには、proc_open関数で取得したプロセスリソースを指定します。第二引数$signalは、プロセスに送信するシグナル番号で、省略するとデフォルトで15(SIGTERM、終了要求シグナル)が送信されます。戻り値はbool型で、シグナルの送信に成功した場合はtrue、失敗した場合はfalseを返します。
サンプルコードでは、sleep 5コマンドを実行する外部プロセスを起動し、proc_get_status関数で起動直後のプロセス状態を確認しています。その後、proc_terminateを呼び出してプロセスに終了シグナルを送信し、再びproc_get_statusを使って、プロセスが正常に終了したか、どのシグナル(termsig)によって終了したかといった状態変化を確認する一連の流れを示しています。これにより、PHPアプリケーションから外部プログラムを安全に制御し、不要になったプロセスを適切に終了させる基本的な方法を学ぶことができます。
proc_terminateは外部プロセスに終了シグナルを送る機能であり、プロセスが必ず即座に終了するわけではありません。状態確認には時間差が生じるため、適宜待機が必要です。サンプル中の外部コマンドはOS依存のため、ご自身の環境に合わせて調整してください。proc_openで開いたプロセスやパイプのリソースは、リソースリーク防止のため、使用後は必ず閉じましょう。また、各関数の戻り値でエラーを確認し、適切な処理をしてください。
PHPでproc_terminateとproc_closeを使い子プロセスを操作する
1<?php 2 3/** 4 * proc_terminate と proc_close の使用例。 5 * 6 * このスクリプトは、新しい子プロセスを起動し、指定された時間が経過した後に 7 * proc_terminate 関数を使って子プロセスに終了シグナルを送信します。 8 * その後、proc_close 関数で子プロセスを閉じ、関連するシステムリソースを解放します。 9 * proc_close はプロセスが実際に終了するまで待機し、その終了コードを返します。 10 */ 11 12// 実行するコマンドを定義します。 13// この例では、PHPインタプリタを使って「sleep(10)」を実行する小さなPHPスクリプトを子プロセスで実行します。 14// これは、子プロセスが10秒間停止することを意味します。 15$command = 'php -r "sleep(10);"'; 16 17// proc_open 関数に渡すディスクリプタ配列を定義します。 18// これにより、子プロセスとの標準入出力ストリームをどのように扱うかを指定します。 19// 0 => stdin (標準入力) : 子プロセスが入力として読み込むためのパイプ 20// 1 => stdout (標準出力) : 子プロセスが書き出すためのパイプ 21// 2 => stderr (標準エラー出力) : 子プロセスがエラーメッセージを書き出すためのパイプ 22$descriptorspec = [ 23 0 => ['pipe', 'r'], 24 1 => ['pipe', 'w'], 25 2 => ['pipe', 'w'], 26]; 27 28// proc_open 関数は子プロセスを起動し、そのプロセスリソースを返します。 29// また、$pipes 配列には子プロセスとの通信に使うパイプのファイルポインタが格納されます。 30$pipes = []; 31$process = proc_open($command, $descriptorspec, $pipes); 32 33// proc_open が子プロセスの起動に失敗した場合の処理 34if (!is_resource($process)) { 35 echo "エラー: 子プロセスの起動に失敗しました。\n"; 36 exit(1); // エラー終了 37} 38 39echo "子プロセスを開始しました。PID: " . proc_get_status($process)['pid'] . "\n"; 40echo "子プロセスはバックグラウンドで10秒間スリープする予定です。\n"; 41 42// 2秒間待機します。これにより子プロセスが動作していることを確認できます。 43sleep(2); 44echo "2秒経過しました。子プロセスに終了シグナルを送信します。\n"; 45 46// proc_terminate 関数を使って、子プロセスに終了シグナルを送信します。 47// デフォルトでは SIGTERM (シグナル番号15) が送信され、これによりプロセスは終了を試みます。 48// 成功した場合は true、失敗した場合は false を返します。 49$terminated = proc_terminate($process); 50 51if ($terminated) { 52 echo "子プロセスに終了シグナルが正常に送信されました。\n"; 53} else { 54 echo "警告: 子プロセスへの終了シグナル送信に失敗しました。\n"; 55} 56 57// proc_close 関数を使って、子プロセスを閉じ、関連するリソースを解放します。 58// この関数は子プロセスが完全に終了するまで待機し、そのプロセスの終了コードを返します。 59$returnCode = proc_close($process); 60echo "子プロセスが終了し、関連リソースが解放されました。終了コード: " . $returnCode . "\n"; 61 62// proc_open で開かれたパイプを閉じます。 63// proc_close はこれらのパイプを自動的に閉じることもありますが、明示的に行うのが安全です。 64foreach ($pipes as $pipe) { 65 fclose($pipe); 66} 67 68echo "スクリプトの実行が完了しました。\n"; 69 70?>
PHPのproc_terminate関数は、proc_open関数で起動した子プロセスに対して、終了シグナルを送信するために使用されます。これにより、実行中の子プロセスに外部から停止を指示し、その終了を促すことが可能です。
引数$processには、proc_openから取得した子プロセスのリソースを指定します。これにより、どのプロセスにシグナルを送るかを識別します。オプションの引数$signalは、送信するシグナルの種類を整数で指定し、デフォルト値の15は、プロセスに穏やかに終了するよう促すSIGTERMシグナルに相当します。関数はシグナル送信の成否をbool型で返し、成功すればtrue、失敗すればfalseとなります。
サンプルコードでは、バックグラウンドで一定時間スリープする子プロセスを起動後、proc_terminateを使って終了シグナルを送信しています。シグナルが送信された後、proc_close関数を呼び出して子プロセスを完全に閉じ、関連するシステムリソースを確実に解放します。proc_closeは、子プロセスが実際に終了するまで待機し、その最終的な終了コードを返します。このようにproc_terminateとproc_closeを組み合わせることで、PHPスクリプトから子プロセスを安全かつ確実に管理できます。
proc_terminateは子プロセスに終了シグナルを送りますが、即座の終了を保証するものではありません。より強制的な終了にはシグナル番号9(SIGKILL)を指定できますが、リソースクリーンアップを妨げる点に注意が必要です。必ずproc_closeを呼び出し、子プロセスが終了するのを待ち、関連するシステムリソースをすべて解放してください。proc_terminate後もproc_closeは必須です。proc_openで作成されたパイプは、proc_closeの後に明示的にfcloseで閉じることが推奨されます。また、proc_openの戻り値が有効なリソースであるか必ず確認し、子プロセスの起動失敗時に適切なエラー処理を実装することが重要です。