PageRenderTime 24ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/classpreloader/classpreloader/src/ClassPreloader.php

https://gitlab.com/ealexis.t/trends
PHP | 181 lines | 83 code | 24 blank | 74 comment | 18 complexity | 9670d8478db2487a1bac196768d15f8e MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of Class Preloader.
  4. *
  5. * (c) Graham Campbell <graham@alt-three.com>
  6. * (c) Michael Dowling <mtdowling@gmail.com>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace ClassPreloader;
  12. use ClassPreloader\Parser\NodeTraverser;
  13. use PhpParser\Node\Stmt\Namespace_ as NamespaceNode;
  14. use PhpParser\Parser;
  15. use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
  16. use RuntimeException;
  17. /**
  18. * This is the class preloader class.
  19. *
  20. * This is the main point of entry for interacting with this package.
  21. */
  22. class ClassPreloader
  23. {
  24. /**
  25. * The printer.
  26. *
  27. * @var \PhpParser\PrettyPrinter\Standard
  28. */
  29. protected $printer;
  30. /**
  31. * The parser.
  32. *
  33. * @var \PhpParser\Parser
  34. */
  35. protected $parser;
  36. /**
  37. * The traverser.
  38. *
  39. * @var \ClassPreloader\Parser\NodeTraverser
  40. */
  41. protected $traverser;
  42. /**
  43. * Create a new class preloader instance.
  44. *
  45. * @param \PhpParser\PrettyPrinter\Standard $printer
  46. * @param \PhpParser\Parser $parser
  47. * @param \ClassPreloader\Parser\NodeTraverser $traverser
  48. *
  49. * @return void
  50. */
  51. public function __construct(PrettyPrinter $printer, Parser $parser, NodeTraverser $traverser)
  52. {
  53. $this->printer = $printer;
  54. $this->parser = $parser;
  55. $this->traverser = $traverser;
  56. }
  57. /**
  58. * Prepare the output file and directory.
  59. *
  60. * @param string $output
  61. * @param bool $strict
  62. *
  63. * @throws \RuntimeException
  64. *
  65. * @return resource
  66. */
  67. public function prepareOutput($output, $strict = false)
  68. {
  69. if ($strict && version_compare(PHP_VERSION, '7') < 1) {
  70. throw new RuntimeException('Strict mode requires PHP 7 or greater.');
  71. }
  72. $dir = dirname($output);
  73. if (!is_dir($dir) && !mkdir($dir, 0777, true)) {
  74. throw new RuntimeException("Unable to create directory $dir.");
  75. }
  76. $handle = fopen($output, 'w');
  77. if (!$handle) {
  78. throw new RuntimeException("Unable to open $output for writing.");
  79. }
  80. if ($strict) {
  81. fwrite($handle, "<?php declare(strict_types=1);\n");
  82. } else {
  83. fwrite($handle, "<?php\n");
  84. }
  85. return $handle;
  86. }
  87. /**
  88. * Get a pretty printed string of code from a file while applying visitors.
  89. *
  90. * @param string $file
  91. *
  92. * @throws \RuntimeException
  93. *
  94. * @return string
  95. */
  96. public function getCode($file, $comments = true)
  97. {
  98. if (!is_string($file) || empty($file)) {
  99. throw new RuntimeException('Invalid filename provided.');
  100. }
  101. if (!is_readable($file)) {
  102. throw new RuntimeException("Cannot open $file for reading.");
  103. }
  104. if ($comments) {
  105. $content = file_get_contents($file);
  106. } else {
  107. $content = php_strip_whitespace($file);
  108. }
  109. $parsed = $this->parser->parse($content);
  110. $stmts = $this->traverser->traverseFile($parsed, $file);
  111. $pretty = $this->printer->prettyPrint($stmts);
  112. if (substr($pretty, 30) === '<?php declare(strict_types=1);' || substr($pretty, 30) === "<?php\ndeclare(strict_types=1);") {
  113. $pretty = substr($pretty, 32);
  114. } elseif (substr($pretty, 31) === "<?php\r\ndeclare(strict_types=1);") {
  115. $pretty = substr($pretty, 33);
  116. } elseif (substr($pretty, 5) === '<?php') {
  117. $pretty = substr($pretty, 7);
  118. }
  119. return $this->getCodeWrappedIntoNamespace($parsed, $pretty);
  120. }
  121. /**
  122. * Wrap the code into a namespace.
  123. *
  124. * @param array $parsed
  125. * @param string $pretty
  126. *
  127. * @return string
  128. */
  129. protected function getCodeWrappedIntoNamespace(array $parsed, $pretty)
  130. {
  131. if ($this->parsedCodeHasNamespaces($parsed)) {
  132. $pretty = preg_replace('/^\s*(namespace.*);/i', '${1} {', $pretty, 1)."\n}\n";
  133. } else {
  134. $pretty = sprintf("namespace {\n%s\n}\n", $pretty);
  135. }
  136. return preg_replace('/(?<!.)[\r\n]+/', '', $pretty);
  137. }
  138. /**
  139. * Check parsed code for having namespaces.
  140. *
  141. * @param array $parsed
  142. *
  143. * @return bool
  144. */
  145. protected function parsedCodeHasNamespaces(array $parsed)
  146. {
  147. // Namespaces can only be on first level in the code,
  148. // so we make only check on it.
  149. $node = array_filter(
  150. $parsed,
  151. function ($value) {
  152. return $value instanceof NamespaceNode;
  153. }
  154. );
  155. return !empty($node);
  156. }
  157. }