1<?php 2 3const WORKER_ARGV_VALUE = 'RUN_WORKER'; 4 5function phpt_notify() 6{ 7 ServerClientTestCase::getInstance()->notify(); 8} 9 10function phpt_wait() 11{ 12 ServerClientTestCase::getInstance()->wait(); 13} 14 15/** 16 * This is a singleton to let the wait/notify functions work 17 * I know it's horrible, but it's a means to an end 18 */ 19class ServerClientTestCase 20{ 21 private $isWorker = false; 22 23 private $workerHandle; 24 25 private $workerStdIn; 26 27 private $workerStdOut; 28 29 private static $instance; 30 31 public static function getInstance($isWorker = false) 32 { 33 if (!isset(self::$instance)) { 34 self::$instance = new self($isWorker); 35 } 36 37 return self::$instance; 38 } 39 40 public function __construct($isWorker = false) 41 { 42 if (!isset(self::$instance)) { 43 self::$instance = $this; 44 } 45 46 $this->isWorker = $isWorker; 47 } 48 49 private function spawnWorkerProcess($code) 50 { 51 $cmd = sprintf('%s "%s" %s', PHP_BINARY, __FILE__, WORKER_ARGV_VALUE); 52 53 $this->workerHandle = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], STDERR], $pipes); 54 $this->workerStdIn = $pipes[0]; 55 $this->workerStdOut = $pipes[1]; 56 57 fwrite($this->workerStdIn, $code . "\n---\n"); 58 } 59 60 private function cleanupWorkerProcess() 61 { 62 fclose($this->workerStdIn); 63 fclose($this->workerStdOut); 64 proc_close($this->workerHandle); 65 } 66 67 private function stripPhpTagsFromCode($code) 68 { 69 return preg_replace('/^\s*<\?(?:php)?|\?>\s*$/i', '', $code); 70 } 71 72 public function runWorker() 73 { 74 $code = ''; 75 76 while (1) { 77 $line = fgets(STDIN); 78 79 if (trim($line) === "---") { 80 break; 81 } 82 83 $code .= $line; 84 } 85 86 eval($code); 87 } 88 89 public function run($proc1Code, $proc2Code) 90 { 91 $this->spawnWorkerProcess($this->stripPhpTagsFromCode($proc2Code)); 92 eval($this->stripPhpTagsFromCode($proc1Code)); 93 $this->cleanupWorkerProcess(); 94 } 95 96 public function wait() 97 { 98 fgets($this->isWorker ? STDIN : $this->workerStdOut); 99 } 100 101 public function notify() 102 { 103 fwrite($this->isWorker ? STDOUT : $this->workerStdIn, "\n"); 104 } 105} 106 107if (isset($argv[1]) && $argv[1] === WORKER_ARGV_VALUE) { 108 ServerClientTestCase::getInstance(true)->runWorker(); 109} 110