Xdebug.php 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. <?php
  2. /*
  3. * This file is part of the php-code-coverage package.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace SebastianBergmann\CodeCoverage\Driver;
  11. use SebastianBergmann\CodeCoverage\RuntimeException;
  12. /**
  13. * Driver for Xdebug's code coverage functionality.
  14. *
  15. * @codeCoverageIgnore
  16. */
  17. class Xdebug implements Driver
  18. {
  19. /**
  20. * Cache the number of lines for each file
  21. *
  22. * @var array
  23. */
  24. private $cacheNumLines = [];
  25. /**
  26. * Constructor.
  27. */
  28. public function __construct()
  29. {
  30. if (!extension_loaded('xdebug')) {
  31. throw new RuntimeException('This driver requires Xdebug');
  32. }
  33. if (version_compare(phpversion('xdebug'), '2.2.1', '>=') &&
  34. !ini_get('xdebug.coverage_enable')) {
  35. throw new RuntimeException(
  36. 'xdebug.coverage_enable=On has to be set in php.ini'
  37. );
  38. }
  39. }
  40. /**
  41. * Start collection of code coverage information.
  42. *
  43. * @param bool $determineUnusedAndDead
  44. */
  45. public function start($determineUnusedAndDead = true)
  46. {
  47. if ($determineUnusedAndDead) {
  48. xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
  49. } else {
  50. xdebug_start_code_coverage();
  51. }
  52. }
  53. /**
  54. * Stop collection of code coverage information.
  55. *
  56. * @return array
  57. */
  58. public function stop()
  59. {
  60. $data = xdebug_get_code_coverage();
  61. xdebug_stop_code_coverage();
  62. return $this->cleanup($data);
  63. }
  64. /**
  65. * @param array $data
  66. *
  67. * @return array
  68. */
  69. private function cleanup(array $data)
  70. {
  71. foreach (array_keys($data) as $file) {
  72. unset($data[$file][0]);
  73. if (strpos($file, 'xdebug://debug-eval') !== 0 && file_exists($file)) {
  74. $numLines = $this->getNumberOfLinesInFile($file);
  75. foreach (array_keys($data[$file]) as $line) {
  76. if ($line > $numLines) {
  77. unset($data[$file][$line]);
  78. }
  79. }
  80. }
  81. }
  82. return $data;
  83. }
  84. /**
  85. * @param string $file
  86. *
  87. * @return int
  88. */
  89. private function getNumberOfLinesInFile($file)
  90. {
  91. if (!isset($this->cacheNumLines[$file])) {
  92. $buffer = file_get_contents($file);
  93. $lines = substr_count($buffer, "\n");
  94. if (substr($buffer, -1) !== "\n") {
  95. $lines++;
  96. }
  97. $this->cacheNumLines[$file] = $lines;
  98. }
  99. return $this->cacheNumLines[$file];
  100. }
  101. }