Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: /** Chris@0: * Driver for PHPDBG's code coverage functionality. Chris@0: * Chris@0: * @since Class available since Release 2.2.0 Chris@0: * @codeCoverageIgnore Chris@0: */ Chris@0: class PHP_CodeCoverage_Driver_PHPDBG implements PHP_CodeCoverage_Driver Chris@0: { Chris@0: /** Chris@0: * Constructor. Chris@0: */ Chris@0: public function __construct() Chris@0: { Chris@0: if (PHP_SAPI !== 'phpdbg') { Chris@0: throw new PHP_CodeCoverage_Exception( Chris@0: 'This driver requires the PHPDBG SAPI' Chris@0: ); Chris@0: } Chris@0: Chris@0: if (!function_exists('phpdbg_start_oplog')) { Chris@0: throw new PHP_CodeCoverage_Exception( Chris@0: 'This build of PHPDBG does not support code coverage' Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Start collection of code coverage information. Chris@0: */ Chris@0: public function start() Chris@0: { Chris@0: phpdbg_start_oplog(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Stop collection of code coverage information. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: public function stop() Chris@0: { Chris@0: static $fetchedLines = array(); Chris@0: Chris@0: $dbgData = phpdbg_end_oplog(); Chris@0: Chris@0: if ($fetchedLines == array()) { Chris@0: $sourceLines = phpdbg_get_executable(); Chris@0: } else { Chris@0: $newFiles = array_diff( Chris@0: get_included_files(), Chris@0: array_keys($fetchedLines) Chris@0: ); Chris@0: Chris@0: if ($newFiles) { Chris@0: $sourceLines = phpdbg_get_executable( Chris@0: array('files' => $newFiles) Chris@0: ); Chris@0: } else { Chris@0: $sourceLines = array(); Chris@0: } Chris@0: } Chris@0: Chris@0: foreach ($sourceLines as $file => $lines) { Chris@0: foreach ($lines as $lineNo => $numExecuted) { Chris@0: $sourceLines[$file][$lineNo] = self::LINE_NOT_EXECUTED; Chris@0: } Chris@0: } Chris@0: Chris@0: $fetchedLines = array_merge($fetchedLines, $sourceLines); Chris@0: Chris@0: return $this->detectExecutedLines($fetchedLines, $dbgData); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Convert phpdbg based data into the format CodeCoverage expects Chris@0: * Chris@0: * @param array $sourceLines Chris@0: * @param array $dbgData Chris@0: * @return array Chris@0: */ Chris@0: private function detectExecutedLines(array $sourceLines, array $dbgData) Chris@0: { Chris@0: foreach ($dbgData as $file => $coveredLines) { Chris@0: foreach ($coveredLines as $lineNo => $numExecuted) { Chris@0: // phpdbg also reports $lineNo=0 when e.g. exceptions get thrown. Chris@0: // make sure we only mark lines executed which are actually executable. Chris@0: if (isset($sourceLines[$file][$lineNo])) { Chris@0: $sourceLines[$file][$lineNo] = self::LINE_EXECUTED; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return $sourceLines; Chris@0: } Chris@0: }