それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

php の proc_open の処理を callback で少し見通しよく

proc_open のコードがカオスになってる

proc_open でプロセスを起動して実行できる。

でも、あれこれ手順が煩雑でわかりにくい。

コールバックを使って整理する

こういうときは、関数の引数に関数を取れば整理されるはず。

<?php
function process_exec( 
    $cmd,
   $callback_on_finished=null,
   $callback_on_every_waiting=null,
   $callback_on_error=null
)
{
  
  $callback_on_finished = $callback_on_finished ?? function(){};
  $callback_on_every_waiting = $callback_on_every_waiting ?? function(){};
  $callback_on_error = $callback_on_error ?? function(){};
  
  $descriptor = [
    0 => ['pipe', 'r'],
    1 => ['pipe', 'w'],
    2 => ['pipe', 'w'],
  ];
  // 実行
  $process = proc_open($cmd, $descriptor, $pipes, sys_get_temp_dir());
  do {
    usleep(1000*1);
    $stat = proc_get_status($process);
    $callback_on_every_waiting($stat, $pipes, $process );
  } while(preg_match('/process/i', get_resource_type($process)) && $stat['running']);
  if( $stat['exitcode'] > 0 ) {
    $callback_on_error($stat, $pipes );
    proc_close($process);
    return ;
  }
  $callback_on_finished($stat, $pipes);
  proc_close($process);
}

実行する側

<?php
$start_time = time();

$waiting = function ( $status , $pipes) use ($start_time) {
  if(preg_match('/stream/i', get_resource_type($pipes[0]))){
    fwrite($pipes[0],"---\nabcd\nefgh\n----\n");
    fclose($pipes[0]);
    usleep(1000*1);
  }
  if ( $start_time + 3 < time() ){
    posix_kill($status['pid'], SIGKILL);
    die('force kill');
  }
};
$on_error = function (){

};
$str = '';
$finished = function ( $staus, $pipes ) use (&$str){
  $str = stream_get_contents($pipes[1]);
};

$cmd = [
  "cat",
];
process_exec( $cmd, $finished, $waiting, $on_error);
print($str);

パイプと最大実行時間

パイプと最大時間をうまく使えば、プロセス起動をうまく使ってゾンビを作らずに済むし、実行時間を気にず、細切れにジョブを実行できる。

関連資料

phpのproc_open関数でコマンドのstdin/stdout/パイプを使う例を確認しました。 - それマグで!