You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.6 KiB

  1. <?php
  2. /**
  3. * Generates array of classes for autoload
  4. *
  5. * @copyright NetMonsters <team@netmonsters.ru>
  6. * @link http://netmonsters.ru
  7. * @package Majestic
  8. * @subpackage util
  9. * @since 2010-02-24
  10. */
  11. /**
  12. * @todo Refactoring writing, locking
  13. */
  14. class AutoloadBuilder
  15. {
  16. protected $autoload;
  17. protected $dirs;
  18. protected $exclude;
  19. protected $handler;
  20. protected $regex = '/\n(abstract |final )?(class|interface|trait) ([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/';
  21. public function __construct($autoload, $dirs = array(), $exclude = array())
  22. {
  23. $this->autoload = $autoload;
  24. $this->dirs = $dirs;
  25. $this->exclude = $exclude;
  26. }
  27. public function build()
  28. {
  29. $array_string = "<?php\n// This file is autogenerated by \n// " . __FILE__ . " script.\nreturn array(\n";
  30. // for duplicates check
  31. $classes = array();
  32. foreach ($this->dirs as $dir) {
  33. $iterator = new RecursiveIteratorIterator(
  34. new RecursiveDirectoryIterator($dir, FilesystemIterator::FOLLOW_SYMLINKS | FilesystemIterator::SKIP_DOTS),
  35. RecursiveIteratorIterator::LEAVES_ONLY
  36. );
  37. $iterator = new AsciiSortedIterator($iterator);
  38. foreach ($iterator as $file) {
  39. /**
  40. * @var SplFileInfo $file
  41. */
  42. if ($this->isExcluded($file->getRealPath())) {
  43. continue;
  44. }
  45. // skip non php files
  46. $e = explode('.', $file->getFileName());
  47. if ((end($e) !== 'php') || $this->rightSubstr($file->getFileName(), 8) == 'Test.php') {
  48. continue;
  49. }
  50. $content = file_get_contents($file->getRealPath());
  51. $matches = array();
  52. $relative_path = substr($file->getPath() . DIRECTORY_SEPARATOR . $file->getFilename(), strlen(PATH));
  53. if (preg_match_all($this->regex, $content, $matches, PREG_SET_ORDER)) {
  54. foreach ($matches as $match) {
  55. if (array_key_exists($match[3], $classes)) {
  56. continue;
  57. }
  58. $array_string .= "'{$match[3]}'=>'" . $relative_path . "',\n";
  59. $classes[$match[3]] = $file->getRealPath();
  60. }
  61. }
  62. }
  63. unset($file); // without this line trigger_error throws 'Serialization of 'SplFileInfo' is not allowed' exception under PHPUnit
  64. }
  65. $array_string .= ');';
  66. $this->writeAutoload($array_string);
  67. if (!$this->isFileConsistent()) {
  68. unlink($this->autoload);
  69. trigger_error("Error while generating autoload file.", E_USER_ERROR);
  70. }
  71. }
  72. protected function writeAutoload($string)
  73. {
  74. $pid = getmypid();
  75. $tmp = dirname($this->autoload) . '/' . md5(time() + $pid);
  76. file_put_contents($tmp, $string);
  77. rename($tmp, $this->autoload);
  78. }
  79. protected function isFileConsistent()
  80. {
  81. $autoload_array = include($this->autoload);
  82. if (!is_array($autoload_array)) {
  83. return false;
  84. }
  85. return true;
  86. }
  87. protected function isExcluded($file)
  88. {
  89. foreach ($this->exclude as $dir) {
  90. if (stripos($file, $dir) === 0) {
  91. return true;
  92. }
  93. }
  94. return false;
  95. }
  96. protected function rightSubstr($string, $nchars)
  97. {
  98. $right = substr($string, strlen($string) - $nchars, $nchars);
  99. return $right;
  100. }
  101. }