/** * @requires PHP 7 * @ticket https://github.com/sebastianbergmann/php-token-stream/issues/52 */ public function testAnonymousClassesAreHandledCorrectly2() { $ts = new PHP_Token_Stream(TEST_FILES_PATH . 'class_with_method_that_declares_anonymous_class2.php'); $classes = $ts->getClasses(); $this->assertEquals(array('Test'), array_keys($classes)); $this->assertEquals(array('methodOne', 'methodTwo'), array_keys($classes['Test']['methods'])); $this->assertEmpty($ts->getFunctions()); }
public function testSignature() { $ts = new PHP_Token_Stream(TEST_FILES_PATH . 'source5.php'); $f = $ts->getFunctions(); $c = $ts->getClasses(); $i = $ts->getInterfaces(); $this->assertEquals('foo($a, array $b, array $c = array())', $f['foo']['signature']); $this->assertEquals('m($a, array $b, array $c = array())', $c['c']['methods']['m']['signature']); $this->assertEquals('m($a, array $b, array $c = array())', $c['a']['methods']['m']['signature']); $this->assertEquals('m($a, array $b, array $c = array())', $i['i']['methods']['m']['signature']); }
/** * @param \PHP_Token_Stream $tokens */ protected function processFunctions(\PHP_Token_Stream $tokens) { $functions = $tokens->getFunctions(); unset($tokens); $link = $this->getId() . '.html#'; foreach ($functions as $functionName => $function) { $this->functions[$functionName] = ['functionName' => $functionName, 'signature' => $function['signature'], 'startLine' => $function['startLine'], 'executableLines' => 0, 'executedLines' => 0, 'ccn' => $function['ccn'], 'coverage' => 0, 'crap' => 0, 'link' => $link . $function['startLine']]; $this->startLines[$function['startLine']] =& $this->functions[$functionName]; $this->endLines[$function['endLine']] =& $this->functions[$functionName]; } }
/** * Returns the lines of a source file that should be ignored. * * @param string $filename * @return array * @throws PHP_CodeCoverage_Exception * @since Method available since Release 2.0.0 */ private function getLinesToBeIgnored($filename) { if (!is_string($filename)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'string'); } if (!isset($this->ignoredLines[$filename])) { $this->ignoredLines[$filename] = array(); $ignore = false; $stop = false; $lines = file($filename); $numLines = count($lines); foreach ($lines as $index => $line) { if (!trim($line)) { $this->ignoredLines[$filename][] = $index + 1; } } if ($this->cacheTokens) { $tokens = PHP_Token_Stream_CachingFactory::get($filename); } else { $tokens = new PHP_Token_Stream($filename); } $classes = array_merge($tokens->getClasses(), $tokens->getTraits()); $tokens = $tokens->tokens(); foreach ($tokens as $token) { switch (get_class($token)) { case 'PHP_Token_COMMENT': case 'PHP_Token_DOC_COMMENT': $_token = trim($token); $_line = trim($lines[$token->getLine() - 1]); if ($_token == '// @codeCoverageIgnore' || $_token == '//@codeCoverageIgnore') { $ignore = true; $stop = true; } elseif ($_token == '// @codeCoverageIgnoreStart' || $_token == '//@codeCoverageIgnoreStart') { $ignore = true; } elseif ($_token == '// @codeCoverageIgnoreEnd' || $_token == '//@codeCoverageIgnoreEnd') { $stop = true; } if (!$ignore) { $start = $token->getLine(); $end = $start + substr_count($token, "\n"); // Do not ignore the first line when there is a token // before the comment if (0 !== strpos($_token, $_line)) { $start++; } for ($i = $start; $i < $end; $i++) { $this->ignoredLines[$filename][] = $i; } // A DOC_COMMENT token or a COMMENT token starting with "/*" // does not contain the final \n character in its text if (0 === strpos($_token, '/*') && '*/' === substr(trim($lines[$i - 1]), -2)) { $this->ignoredLines[$filename][] = $i; } } break; case 'PHP_Token_INTERFACE': case 'PHP_Token_TRAIT': case 'PHP_Token_CLASS': case 'PHP_Token_FUNCTION': $docblock = $token->getDocblock(); $this->ignoredLines[$filename][] = $token->getLine(); if (strpos($docblock, '@codeCoverageIgnore')) { $endLine = $token->getEndLine(); for ($i = $token->getLine(); $i <= $endLine; $i++) { $this->ignoredLines[$filename][] = $i; } } elseif ($token instanceof PHP_Token_INTERFACE || $token instanceof PHP_Token_TRAIT || $token instanceof PHP_Token_CLASS) { if (empty($classes[$token->getName()]['methods'])) { for ($i = $token->getLine(); $i <= $token->getEndLine(); $i++) { $this->ignoredLines[$filename][] = $i; } } else { $firstMethod = array_shift($classes[$token->getName()]['methods']); do { $lastMethod = array_pop($classes[$token->getName()]['methods']); } while ($lastMethod !== null && substr($lastMethod['signature'], 0, 18) == 'anonymous function'); if ($lastMethod === null) { $lastMethod = $firstMethod; } for ($i = $token->getLine(); $i < $firstMethod['startLine']; $i++) { $this->ignoredLines[$filename][] = $i; } for ($i = $token->getEndLine(); $i > $lastMethod['endLine']; $i--) { $this->ignoredLines[$filename][] = $i; } } } break; case 'PHP_Token_NAMESPACE': $this->ignoredLines[$filename][] = $token->getEndLine(); // Intentional fallthrough // Intentional fallthrough case 'PHP_Token_OPEN_TAG': case 'PHP_Token_CLOSE_TAG': case 'PHP_Token_USE': $this->ignoredLines[$filename][] = $token->getLine(); break; } if ($ignore) { $this->ignoredLines[$filename][] = $token->getLine(); if ($stop) { $ignore = false; $stop = false; } } } $this->ignoredLines[$filename][] = $numLines + 1; $this->ignoredLines[$filename] = array_unique($this->ignoredLines[$filename]); sort($this->ignoredLines[$filename]); } return $this->ignoredLines[$filename]; }
public function testIssue30() { $ts = new PHP_Token_Stream(TEST_FILES_PATH . 'issue30.php'); $this->assertCount(1, $ts->getClasses()); }
/** * Returns the lines of a source file that should be ignored. * * @param string $filename * @param boolean $cacheTokens * @return array * @throws PHP_CodeCoverage_Exception */ public static function getLinesToBeIgnored($filename, $cacheTokens = TRUE) { if (!is_string($filename)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(1, 'string'); } if (!is_bool($cacheTokens)) { throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(2, 'boolean'); } if (!isset(self::$ignoredLines[$filename])) { self::$ignoredLines[$filename] = array(); $ignore = FALSE; $stop = FALSE; $lines = file($filename); foreach ($lines as $index => $line) { if (!trim($line)) { self::$ignoredLines[$filename][$index + 1] = TRUE; } } if ($cacheTokens) { $tokens = PHP_Token_Stream_CachingFactory::get($filename); } else { $tokens = new PHP_Token_Stream($filename); } $classes = array_merge($tokens->getClasses(), $tokens->getTraits()); $tokens = $tokens->tokens(); foreach ($tokens as $token) { switch (get_class($token)) { case 'PHP_Token_COMMENT': case 'PHP_Token_DOC_COMMENT': $count = substr_count($token, "\n"); $line = $token->getLine(); for ($i = $line; $i < $line + $count; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } if ($token instanceof PHP_Token_DOC_COMMENT) { // Workaround for the fact the DOC_COMMENT token // does not include the final \n character in its // text. if (substr(trim($lines[$i - 1]), -2) == '*/') { self::$ignoredLines[$filename][$i] = TRUE; } break; } $_token = trim($token); if ($_token == '// @codeCoverageIgnore' || $_token == '//@codeCoverageIgnore') { $ignore = TRUE; $stop = TRUE; } else { if ($_token == '// @codeCoverageIgnoreStart' || $_token == '//@codeCoverageIgnoreStart') { $ignore = TRUE; } else { if ($_token == '// @codeCoverageIgnoreEnd' || $_token == '//@codeCoverageIgnoreEnd') { $stop = TRUE; } } } break; case 'PHP_Token_INTERFACE': case 'PHP_Token_TRAIT': case 'PHP_Token_CLASS': case 'PHP_Token_FUNCTION': $docblock = $token->getDocblock(); if (strpos($docblock, '@codeCoverageIgnore')) { $endLine = $token->getEndLine(); for ($i = $token->getLine(); $i <= $endLine; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } } else { if ($token instanceof PHP_Token_INTERFACE || $token instanceof PHP_Token_TRAIT || $token instanceof PHP_Token_CLASS) { if (empty($classes[$token->getName()]['methods'])) { for ($i = $token->getLine(); $i <= $token->getEndLine(); $i++) { self::$ignoredLines[$filename][$i] = TRUE; } } else { $firstMethod = array_shift($classes[$token->getName()]['methods']); $lastMethod = array_pop($classes[$token->getName()]['methods']); if ($lastMethod === NULL) { $lastMethod = $firstMethod; } for ($i = $token->getLine(); $i < $firstMethod['startLine']; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } for ($i = $token->getEndLine(); $i > $lastMethod['endLine']; $i--) { self::$ignoredLines[$filename][$i] = TRUE; } } } } break; case 'PHP_Token_INTERFACE': $endLine = $token->getEndLine(); for ($i = $token->getLine(); $i <= $endLine; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } break; case 'PHP_Token_NAMESPACE': self::$ignoredLines[$filename][$token->getEndLine()] = TRUE; // Intentional fallthrough // Intentional fallthrough case 'PHP_Token_OPEN_TAG': case 'PHP_Token_CLOSE_TAG': case 'PHP_Token_USE': self::$ignoredLines[$filename][$token->getLine()] = TRUE; break; } if ($ignore) { self::$ignoredLines[$filename][$token->getLine()] = TRUE; if ($stop) { $ignore = FALSE; $stop = FALSE; } } } } return self::$ignoredLines[$filename]; }
/** * Returns the lines of a source file that should be ignored. * * @param string $filename * @param boolean $cacheTokens * @return array * @throws InvalidArgumentException */ public static function getLinesToBeIgnored($filename, $cacheTokens = TRUE) { if (!is_bool($cacheTokens)) { throw new InvalidArgumentException(); } if (!isset(self::$ignoredLines[$filename])) { self::$ignoredLines[$filename] = array(); $ignore = FALSE; $stop = FALSE; if ($cacheTokens) { $tokens = PHP_Token_Stream_CachingFactory::get($filename); } else { $tokens = new PHP_Token_Stream($filename); } $classes = $tokens->getClasses(); $tokens = $tokens->tokens(); foreach ($tokens as $token) { switch (get_class($token)) { case 'PHP_Token_CLASS': case 'PHP_Token_FUNCTION': $docblock = $token->getDocblock(); if (strpos($docblock, '@codeCoverageIgnore')) { $endLine = $token->getEndLine(); for ($i = $token->getLine(); $i <= $endLine; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } } else { if ($token instanceof PHP_Token_CLASS && !empty($classes[$token->getName()]['methods'])) { $firstMethod = array_shift($classes[$token->getName()]['methods']); for ($i = $token->getLine(); $i < $firstMethod['startLine']; $i++) { self::$ignoredLines[$filename][$i] = TRUE; } } } break; case 'PHP_Token_COMMENT': $_token = trim($token); if ($_token == '// @codeCoverageIgnoreStart' || $_token == '//@codeCoverageIgnoreStart') { $ignore = TRUE; } else { if ($_token == '// @codeCoverageIgnoreEnd' || $_token == '//@codeCoverageIgnoreEnd') { $stop = TRUE; } } break; } if ($ignore) { self::$ignoredLines[$filename][$token->getLine()] = TRUE; if ($stop) { $ignore = FALSE; $stop = FALSE; } } } } return self::$ignoredLines[$filename]; }
/** * @requires PHP 7 */ public function testAnonymousClassesAreHandledCorrectly() { $ts = new PHP_Token_Stream(TEST_FILES_PATH . 'class_with_method_that_declares_anonymous_class.php'); $classes = $ts->getClasses(); $this->assertEquals(array('class_with_method_that_declares_anonymous_class'), array_keys($classes)); }
/** * Processes whitelisted files that are not covered. */ protected function processUncoveredFilesFromWhitelist() { $data = array(); $uncoveredFiles = array_diff($this->filter->getWhitelist(), array_keys($this->data)); foreach ($uncoveredFiles as $uncoveredFile) { if (!file_exists($uncoveredFile)) { continue; } if ($this->cacheTokens) { $tokens = PHP_Token_Stream_CachingFactory::get($uncoveredFile); } else { $tokens = new PHP_Token_Stream($uncoveredFile); } $classes = $tokens->getClasses(); $interfaces = $tokens->getInterfaces(); $functions = $tokens->getFunctions(); unset($tokens); foreach (array_keys($classes) as $class) { if (class_exists($class, FALSE)) { continue 2; } } unset($classes); foreach (array_keys($interfaces) as $interface) { if (interface_exists($interface, FALSE)) { continue 2; } } unset($interfaces); foreach (array_keys($functions) as $function) { if (function_exists($function)) { continue 2; } } unset($functions); $this->driver->start(); include_once $uncoveredFile; $coverage = $this->driver->stop(); foreach ($coverage as $file => $fileCoverage) { if (!isset($data[$file]) && in_array($file, $uncoveredFiles)) { foreach (array_keys($fileCoverage) as $key) { if ($fileCoverage[$key] == 1) { $fileCoverage[$key] = -1; } } $data[$file] = $fileCoverage; } } } $this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST'); }
/** * @requires PHP 5.6 */ public function testImportedFunctionsAreHandledCorrectly() { $ts = new PHP_Token_Stream(TEST_FILES_PATH . 'classUsesNamespacedFunction.php'); $this->assertEmpty($ts->getFunctions()); }
protected function processFunctions() { if ($this->cacheTokens) { $tokens = PHP_Token_Stream_CachingFactory::get($this->getPath()); } else { $tokens = new PHP_Token_Stream($this->getPath()); } $functions = $tokens->getFunctions(); unset($tokens); if (count($functions) > 0 && !isset($this->classes['*'])) { $this->classes['*'] = array('methods' => array(), 'startLine' => 0, 'executableLines' => 0, 'executedLines' => 0, 'ccn' => 0); } foreach ($functions as $functionName => $function) { $this->classes['*']['methods'][$functionName] = array('signature' => $function['signature'], 'startLine' => $function['startLine'], 'executableLines' => 0, 'executedLines' => 0, 'ccn' => $function['ccn']); $this->startLines[$function['startLine']] =& $this->classes['*']['methods'][$functionName]; $this->endLines[$function['endLine']] =& $this->classes['*']['methods'][$functionName]; } }
protected function _getClassessInFile($path) { if (version_compare(PHPUnit_Runner_Version::id(), '3.4', '<')) { $classes = array(); foreach (PHPUnit_Util_Class::getClassesInFile($path) as $reflection) { $classes[] = $reflection->getName(); } return $classes; } elseif (version_compare(PHPUnit_Runner_Version::id(), '3.7', '<')) { return array_keys(PHPUnit_Util_File::getClassesInFile($path)); } else { $stream = new PHP_Token_Stream($path); return array_keys($stream->getClasses()); } }
#!/usr/bin/env php <?php if (!file_exists(__DIR__ . '/../vendor/autoload.php')) { die('You need to set up the project dependencies using the following commands:' . PHP_EOL . 'wget https://getcomposer.org/composer.phar' . PHP_EOL . 'php composer.phar install' . PHP_EOL); } require __DIR__ . '/../vendor/autoload.php'; use SebastianBergmann\FinderFacade\FinderFacade; $finder = new FinderFacade(array(__DIR__ . '/../example/src'), array(), array('*.php')); print 'digraph G {' . PHP_EOL; foreach ($finder->findFiles() as $file) { $file = new PHP_Token_Stream($file); foreach ($file->getClasses() as $className => $class) { if ($class['parent'] == 'AbstractDoorState') { foreach ($class['methods'] as $methodName => $method) { if (!in_array($methodName, array('open', 'close', 'lock', 'unlock'))) { continue; } $annotations = array('return' => array()); if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \\t]+(?P<value>.*?))?[ \\t]*\\r?$/m', $method['docblock'], $matches)) { for ($i = 0; $i < count($matches[0]); ++$i) { $annotations[$matches['name'][$i]][] = $matches['value'][$i]; } } foreach ($annotations['return'] as $return) { printf(' "%s" -> "%s";' . PHP_EOL, str_replace(array('Door', 'State'), array(' Door', ''), $className), str_replace(array('Door', 'State'), array(' Door', ''), $return)); } } } } } print '}' . PHP_EOL;
/** * @param PHP_CodeCoverage $coverage * @param string $target * @param string $name * @return string */ public function process(PHP_CodeCoverage $coverage, $target = NULL, $name = NULL) { $document = new DOMDocument('1.0', 'UTF-8'); $document->formatOutput = TRUE; $root = $document->createElement('coverage'); $root->setAttribute('generated', (int) $_SERVER['REQUEST_TIME']); $document->appendChild($root); $project = $document->createElement('project'); $project->setAttribute('timestamp', (int) $_SERVER['REQUEST_TIME']); if (is_string($name)) { $project->setAttribute('name', $name); } $root->appendChild($project); $files = $coverage->getData(); $packages = array(); $projectStatistics = array('files' => 0, 'loc' => 0, 'ncloc' => 0, 'classes' => 0, 'methods' => 0, 'coveredMethods' => 0, 'conditionals' => 0, 'coveredConditionals' => 0, 'statements' => 0, 'coveredStatements' => 0); foreach ($files as $filename => $data) { $namespace = 'global'; if (file_exists($filename)) { $fileStatistics = array('classes' => 0, 'methods' => 0, 'coveredMethods' => 0, 'conditionals' => 0, 'coveredConditionals' => 0, 'statements' => 0, 'coveredStatements' => 0); $file = $document->createElement('file'); $file->setAttribute('name', $filename); if ($this->cacheTokens) { $tokens = PHP_Token_Stream_CachingFactory::get($filename); } else { $tokens = new PHP_Token_Stream($filename); } $classesInFile = $tokens->getClasses(); $linesOfCode = $tokens->getLinesOfCode(); unset($tokens); $ignoredLines = PHP_CodeCoverage_Util::getLinesToBeIgnored($filename, $this->cacheTokens); $lines = array(); foreach ($classesInFile as $className => $_class) { $classStatistics = array('methods' => 0, 'coveredMethods' => 0, 'conditionals' => 0, 'coveredConditionals' => 0, 'statements' => 0, 'coveredStatements' => 0); foreach ($_class['methods'] as $methodName => $method) { $classStatistics['methods']++; $methodCount = 0; $methodLines = 0; $methodLinesCovered = 0; for ($i = $method['startLine']; $i <= $method['endLine']; $i++) { if (isset($ignoredLines[$i])) { continue; } $add = TRUE; $count = 0; if (isset($files[$filename][$i])) { if ($files[$filename][$i] !== NULL) { $classStatistics['statements']++; $methodLines++; } else { $add = FALSE; } $count = count($files[$filename][$i]); if ($count > 0) { $classStatistics['coveredStatements']++; $methodLinesCovered++; } } else { $add = FALSE; } $methodCount = max($methodCount, $count); if ($add) { $lines[$i] = array('count' => $count, 'type' => 'stmt'); } } if ($methodCount > 0) { $classStatistics['coveredMethods']++; } $lines[$method['startLine']] = array('count' => $methodCount, 'crap' => PHP_CodeCoverage_Util::crap($method['ccn'], PHP_CodeCoverage_Util::percent($methodLinesCovered, $methodLines)), 'type' => 'method', 'name' => $methodName); } $package = PHP_CodeCoverage_Util::getPackageInformation($className, $_class['docblock']); if (!empty($package['namespace'])) { $namespace = $package['namespace']; } $class = $document->createElement('class'); $class->setAttribute('name', $className); $class->setAttribute('namespace', $namespace); if (!empty($package['fullPackage'])) { $class->setAttribute('fullPackage', $package['fullPackage']); } if (!empty($package['category'])) { $class->setAttribute('category', $package['category']); } if (!empty($package['package'])) { $class->setAttribute('package', $package['package']); } if (!empty($package['subpackage'])) { $class->setAttribute('subpackage', $package['subpackage']); } $file->appendChild($class); $metrics = $document->createElement('metrics'); $metrics->setAttribute('methods', $classStatistics['methods']); $metrics->setAttribute('coveredmethods', $classStatistics['coveredMethods']); $metrics->setAttribute('conditionals', $classStatistics['conditionals']); $metrics->setAttribute('coveredconditionals', $classStatistics['coveredConditionals']); $metrics->setAttribute('statements', $classStatistics['statements']); $metrics->setAttribute('coveredstatements', $classStatistics['coveredStatements']); $metrics->setAttribute('elements', $classStatistics['conditionals'] + $classStatistics['statements'] + $classStatistics['methods']); $metrics->setAttribute('coveredelements', $classStatistics['coveredConditionals'] + $classStatistics['coveredStatements'] + $classStatistics['coveredMethods']); $class->appendChild($metrics); $fileStatistics['methods'] += $classStatistics['methods']; $fileStatistics['coveredMethods'] += $classStatistics['coveredMethods']; $fileStatistics['conditionals'] += $classStatistics['conditionals']; $fileStatistics['coveredConditionals'] += $classStatistics['coveredConditionals']; $fileStatistics['statements'] += $classStatistics['statements']; $fileStatistics['coveredStatements'] += $classStatistics['coveredStatements']; $fileStatistics['classes']++; } foreach ($data as $_line => $_data) { if (isset($lines[$_line]) || isset($ignoredLines[$_line])) { continue; } if ($_data !== NULL) { $fileStatistics['statements']++; $count = count($_data); if ($count > 0) { $fileStatistics['coveredStatements']++; } $lines[$_line] = array('count' => $count, 'type' => 'stmt'); } } ksort($lines); foreach ($lines as $_line => $_data) { if (isset($ignoredLines[$_line])) { continue; } $line = $document->createElement('line'); $line->setAttribute('num', $_line); $line->setAttribute('type', $_data['type']); if (isset($_data['name'])) { $line->setAttribute('name', $_data['name']); } if (isset($_data['crap'])) { $line->setAttribute('crap', $_data['crap']); } $line->setAttribute('count', $_data['count']); $file->appendChild($line); } $metrics = $document->createElement('metrics'); $metrics->setAttribute('loc', $linesOfCode['loc']); $metrics->setAttribute('ncloc', $linesOfCode['ncloc']); $metrics->setAttribute('classes', $fileStatistics['classes']); $metrics->setAttribute('methods', $fileStatistics['methods']); $metrics->setAttribute('coveredmethods', $fileStatistics['coveredMethods']); $metrics->setAttribute('conditionals', $fileStatistics['conditionals']); $metrics->setAttribute('coveredconditionals', $fileStatistics['coveredConditionals']); $metrics->setAttribute('statements', $fileStatistics['statements']); $metrics->setAttribute('coveredstatements', $fileStatistics['coveredStatements']); $metrics->setAttribute('elements', $fileStatistics['conditionals'] + $fileStatistics['statements'] + $fileStatistics['methods']); $metrics->setAttribute('coveredelements', $fileStatistics['coveredConditionals'] + $fileStatistics['coveredStatements'] + $fileStatistics['coveredMethods']); $file->appendChild($metrics); if ($namespace == 'global') { $project->appendChild($file); } else { if (!isset($packages[$namespace])) { $packages[$namespace] = $document->createElement('package'); $packages[$namespace]->setAttribute('name', $namespace); $project->appendChild($packages[$namespace]); } $packages[$namespace]->appendChild($file); } $projectStatistics['loc'] += $linesOfCode['loc']; $projectStatistics['ncloc'] += $linesOfCode['ncloc']; $projectStatistics['classes'] += $fileStatistics['classes']; $projectStatistics['methods'] += $fileStatistics['methods']; $projectStatistics['coveredMethods'] += $fileStatistics['coveredMethods']; $projectStatistics['conditionals'] += $fileStatistics['conditionals']; $projectStatistics['coveredConditionals'] += $fileStatistics['coveredConditionals']; $projectStatistics['statements'] += $fileStatistics['statements']; $projectStatistics['coveredStatements'] += $fileStatistics['coveredStatements']; $projectStatistics['files']++; } } $metrics = $document->createElement('metrics'); $metrics->setAttribute('files', $projectStatistics['files']); $metrics->setAttribute('loc', $projectStatistics['loc']); $metrics->setAttribute('ncloc', $projectStatistics['ncloc']); $metrics->setAttribute('classes', $projectStatistics['classes']); $metrics->setAttribute('methods', $projectStatistics['methods']); $metrics->setAttribute('coveredmethods', $projectStatistics['coveredMethods']); $metrics->setAttribute('conditionals', $projectStatistics['conditionals']); $metrics->setAttribute('coveredconditionals', $projectStatistics['coveredConditionals']); $metrics->setAttribute('statements', $projectStatistics['statements']); $metrics->setAttribute('coveredstatements', $projectStatistics['coveredStatements']); $metrics->setAttribute('elements', $projectStatistics['conditionals'] + $projectStatistics['statements'] + $projectStatistics['methods']); $metrics->setAttribute('coveredelements', $projectStatistics['coveredConditionals'] + $projectStatistics['coveredStatements'] + $projectStatistics['coveredMethods']); $project->appendChild($metrics); if ($target !== NULL) { if (!is_dir(dirname($target))) { mkdir(dirname($target), 0777, TRUE); } return $document->save($target); } else { return $document->saveXML(); } }