PHP用proc_open新建子进程使用管道通信非阻塞执行PHP脚本.
脚本结束时register_shutdown_function回调函数访问管道获取子进程输出的数据.
1例子1(popen): 2<?php 3function foo() { 4 echo date('Y-m-d H:i:s')."\n"; 5 echo shell_exec('php -r \'sleep(1); echo date("Y-m-d H:i:s")." by shell_exec:blocking\n";\''); //阻塞 6 $pipe1 = popen('php -r \'sleep(2); echo date("Y-m-d H:i:s")." by popen1:non-blocking\n";\'', 'r'); //非阻塞(管道) 7 $pipe2 = popen('php -r \'sleep(1); echo date("Y-m-d H:i:s")." by popen2:non-blocking\n";\'', 'r'); //非阻塞(管道) 8 echo date('Y-m-d H:i:s')."\n"; 9 register_shutdown_function(function() use ($pipe1, $pipe2) { //事件驱动(脚本结束事件),异步回调 10 echo stream_get_contents($pipe1); //输出子进程返回的数据 11 echo stream_get_contents($pipe2); //输出子进程返回的数据 12 pclose($pipe1); 13 pclose($pipe2); 14 }); 15} 16foo(); 17//输出 182016-09-11 20:25:30 192016-09-11 20:25:31 by shell_exec:blocking 202016-09-11 20:25:31 212016-09-11 20:25:33 by popen1:non-blocking 222016-09-11 20:25:32 by popen2:non-blocking 23 24例子2(proc_open): 25<?php 26function foo() { 27 $proc = proc_open( 28 //task.php 内容为 $arr = unserialize(stream_get_contents(STDIN)); $arr['time'] = date('Y-m-d H:i:s', $arr['time']); echo serialize($arr); 29 '/png/php/5.4.45/bin/php /home/eechen/task.php', 30 array( 31 0 => array('pipe','r'), //stdin (用fwrite写入数据给管道) 32 1 => array('pipe','w'), //stdout(用stream_get_contents获取管道输出) 33 2 => array('pipe','w'), //stderr(用stream_get_contents获取管道输出) 34 //2 => array('file','/tmp/err.txt','a') //stderr(写入到文件) 35 ), 36 $pipes, //管道(stdin/stdout/stderr) 37 '/tmp', //当前PHP进程的工作目录 38 array('foo' => 'bar') //php.ini 配置 variables_order = "EGPCS" 其中E表示$_ENV,否则$_ENV输出为空 39 ); 40 //var_dump($pipes); //resource of type (stream) 41 if(is_resource($proc)) { 42 //stdin 43 $stdin = serialize(array('time' => time())); 44 fwrite($pipes[0], $stdin); //把参数传给脚本task.php 45 fclose($pipes[0]); //fclose关闭管道后proc_close才能退出子进程,否则会发生死锁 46 register_shutdown_function(function() use($pipes, $proc) { //事件驱动(脚本结束事件),异步回调 47 //stdout 48 $stdout = stream_get_contents($pipes[1]); 49 fclose($pipes[1]); 50 //stderr 51 $stderr = stream_get_contents($pipes[2]); 52 fclose($pipes[2]); 53 //exit code (返回进程的终止状态码,如果发生错则返回-1) 54 $status = proc_close($proc); 55 $data = array( 56 'stdout' => $stdout, 57 'stderr' => $stderr, 58 'status' => $status, 59 ); 60 var_export($data); //echo json_encode($data); 61 }); 62 } 63} 64foo(); 65//输出: 66array ( 67 'stdout' => 'a:1:{s:4:"time";s:19:"2016-09-11 21:26:29";}', 68 'stderr' => '', 69 'status' => 0, 70)