ServerClientTestCase.inc 2.3 KB

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