3 * This file is part of PHPUnit.
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
12 * Utility methods for PHP sub-processes.
14 * @since Class available since Release 3.4.0
16 abstract class PHPUnit_Util_PHP
19 * @return PHPUnit_Util_PHP
21 * @since Method available since Release 3.5.12
23 public static function factory()
25 if (DIRECTORY_SEPARATOR == '\\') {
26 return new PHPUnit_Util_PHP_Windows;
29 return new PHPUnit_Util_PHP_Default;
33 * Runs a single test in a separate PHP process.
36 * @param PHPUnit_Framework_Test $test
37 * @param PHPUnit_Framework_TestResult $result
39 * @throws PHPUnit_Framework_Exception
41 public function runTestJob($job, PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result)
43 $result->startTest($test);
45 $_result = $this->runJob($job);
47 $this->processChildResult(
56 * Runs a single job (PHP code) using a separate PHP process.
59 * @param array $settings
63 * @throws PHPUnit_Framework_Exception
65 abstract public function runJob($job, array $settings = array());
68 * @param array $settings
72 * @since Method available since Release 4.0.0
74 protected function settingsToParameters(array $settings)
78 foreach ($settings as $setting) {
79 $buffer .= ' -d ' . $setting;
86 * Processes the TestResult object from an isolated process.
88 * @param PHPUnit_Framework_Test $test
89 * @param PHPUnit_Framework_TestResult $result
90 * @param string $stdout
91 * @param string $stderr
93 * @since Method available since Release 3.5.0
95 private function processChildResult(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result, $stdout, $stderr)
99 if (!empty($stderr)) {
102 new PHPUnit_Framework_Exception(trim($stderr)),
106 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
107 throw new ErrorException($errstr, $errno, $errno, $errfile, $errline);
110 if (strpos($stdout, "#!/usr/bin/env php\n") === 0) {
111 $stdout = substr($stdout, 19);
114 $childResult = unserialize(str_replace("#!/usr/bin/env php\n", '', $stdout));
115 restore_error_handler();
116 } catch (ErrorException $e) {
117 restore_error_handler();
118 $childResult = false;
122 new PHPUnit_Framework_Exception(trim($stdout), 0, $e),
127 if ($childResult !== false) {
128 if (!empty($childResult['output'])) {
129 $output = $childResult['output'];
132 $test->setResult($childResult['testResult']);
133 $test->addToAssertionCount($childResult['numAssertions']);
135 $childResult = $childResult['result'];
137 if ($result->getCollectCodeCoverageInformation()) {
138 $result->getCodeCoverage()->merge(
139 $childResult->getCodeCoverage()
143 $time = $childResult->time();
144 $notImplemented = $childResult->notImplemented();
145 $risky = $childResult->risky();
146 $skipped = $childResult->skipped();
147 $errors = $childResult->errors();
148 $failures = $childResult->failures();
150 if (!empty($notImplemented)) {
153 $this->getException($notImplemented[0]),
156 } elseif (!empty($risky)) {
159 $this->getException($risky[0]),
162 } elseif (!empty($skipped)) {
165 $this->getException($skipped[0]),
168 } elseif (!empty($errors)) {
171 $this->getException($errors[0]),
174 } elseif (!empty($failures)) {
177 $this->getException($failures[0]),
184 $result->endTest($test, $time);
186 if (!empty($output)) {
192 * Gets the thrown exception from a PHPUnit_Framework_TestFailure.
194 * @param PHPUnit_Framework_TestFailure $error
198 * @since Method available since Release 3.6.0
199 * @see https://github.com/sebastianbergmann/phpunit/issues/74
201 private function getException(PHPUnit_Framework_TestFailure $error)
203 $exception = $error->thrownException();
205 if ($exception instanceof __PHP_Incomplete_Class) {
206 $exceptionArray = array();
207 foreach ((array) $exception as $key => $value) {
208 $key = substr($key, strrpos($key, "\0") + 1);
209 $exceptionArray[$key] = $value;
212 $exception = new PHPUnit_Framework_SyntheticError(
215 $exceptionArray['_PHP_Incomplete_Class_Name'],
216 $exceptionArray['message']
218 $exceptionArray['code'],
219 $exceptionArray['file'],
220 $exceptionArray['line'],
221 $exceptionArray['trace']