PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/zendframework/zend-loader/src/ModuleAutoloader.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 442 lines | 260 code | 48 blank | 134 comment | 41 complexity | 668b57afab97eca3a6afcdf0249d93c0 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Loader;
  10. // Grab SplAutoloader interface
  11. require_once __DIR__ . '/SplAutoloader.php';
  12. use GlobIterator;
  13. use Phar;
  14. use PharFileInfo;
  15. use SplFileInfo;
  16. use Traversable;
  17. class ModuleAutoloader implements SplAutoloader
  18. {
  19. /**
  20. * @var array An array of module paths to scan
  21. */
  22. protected $paths = array();
  23. /**
  24. * @var array An array of modulename => path
  25. */
  26. protected $explicitPaths = array();
  27. /**
  28. * @var array An array of namespaceName => namespacePath
  29. */
  30. protected $namespacedPaths = array();
  31. /**
  32. * @var string Will contain the absolute phar:// path to the executable when packaged as phar file
  33. */
  34. protected $pharBasePath = "";
  35. /**
  36. * @var array An array of supported phar extensions (filled on constructor)
  37. */
  38. protected $pharExtensions = array();
  39. /**
  40. * @var array An array of module classes to their containing files
  41. */
  42. protected $moduleClassMap = array();
  43. /**
  44. * Constructor
  45. *
  46. * Allow configuration of the autoloader via the constructor.
  47. *
  48. * @param null|array|Traversable $options
  49. */
  50. public function __construct($options = null)
  51. {
  52. if (extension_loaded('phar')) {
  53. $this->pharBasePath = Phar::running(true);
  54. $this->pharExtensions = array(
  55. 'phar',
  56. 'phar.tar',
  57. 'tar',
  58. );
  59. // ext/zlib enabled -> phar can read gzip & zip compressed files
  60. if (extension_loaded('zlib')) {
  61. $this->pharExtensions[] = 'phar.gz';
  62. $this->pharExtensions[] = 'phar.tar.gz';
  63. $this->pharExtensions[] = 'tar.gz';
  64. $this->pharExtensions[] = 'phar.zip';
  65. $this->pharExtensions[] = 'zip';
  66. }
  67. // ext/bzip2 enabled -> phar can read bz2 compressed files
  68. if (extension_loaded('bzip2')) {
  69. $this->pharExtensions[] = 'phar.bz2';
  70. $this->pharExtensions[] = 'phar.tar.bz2';
  71. $this->pharExtensions[] = 'tar.bz2';
  72. }
  73. }
  74. if (null !== $options) {
  75. $this->setOptions($options);
  76. }
  77. }
  78. /**
  79. * Configure the autoloader
  80. *
  81. * In most cases, $options should be either an associative array or
  82. * Traversable object.
  83. *
  84. * @param array|Traversable $options
  85. * @return ModuleAutoloader
  86. */
  87. public function setOptions($options)
  88. {
  89. $this->registerPaths($options);
  90. return $this;
  91. }
  92. /**
  93. * Retrieves the class map for all loaded modules.
  94. *
  95. * @return array
  96. */
  97. public function getModuleClassMap()
  98. {
  99. return $this->moduleClassMap;
  100. }
  101. /**
  102. * Sets the class map used to speed up the module autoloading.
  103. *
  104. * @param array $classmap
  105. * @return ModuleAutoloader
  106. */
  107. public function setModuleClassMap(array $classmap)
  108. {
  109. $this->moduleClassMap = $classmap;
  110. return $this;
  111. }
  112. /**
  113. * Autoload a class
  114. *
  115. * @param $class
  116. * @return mixed
  117. * False [if unable to load $class]
  118. * get_class($class) [if $class is successfully loaded]
  119. */
  120. public function autoload($class)
  121. {
  122. // Limit scope of this autoloader
  123. if (substr($class, -7) !== '\Module') {
  124. return false;
  125. }
  126. if (isset($this->moduleClassMap[$class])) {
  127. require_once $this->moduleClassMap[$class];
  128. return $class;
  129. }
  130. $moduleName = substr($class, 0, -7);
  131. if (isset($this->explicitPaths[$moduleName])) {
  132. $classLoaded = $this->loadModuleFromDir($this->explicitPaths[$moduleName], $class);
  133. if ($classLoaded) {
  134. return $classLoaded;
  135. }
  136. $classLoaded = $this->loadModuleFromPhar($this->explicitPaths[$moduleName], $class);
  137. if ($classLoaded) {
  138. return $classLoaded;
  139. }
  140. }
  141. if (count($this->namespacedPaths) >= 1) {
  142. foreach ($this->namespacedPaths as $namespace => $path) {
  143. if (false === strpos($moduleName, $namespace)) {
  144. continue;
  145. }
  146. $moduleNameBuffer = str_replace($namespace . "\\", "", $moduleName);
  147. $path .= DIRECTORY_SEPARATOR . $moduleNameBuffer . DIRECTORY_SEPARATOR;
  148. $classLoaded = $this->loadModuleFromDir($path, $class);
  149. if ($classLoaded) {
  150. return $classLoaded;
  151. }
  152. $classLoaded = $this->loadModuleFromPhar($path, $class);
  153. if ($classLoaded) {
  154. return $classLoaded;
  155. }
  156. }
  157. }
  158. $moduleClassPath = str_replace('\\', DIRECTORY_SEPARATOR, $moduleName);
  159. $pharSuffixPattern = null;
  160. if ($this->pharExtensions) {
  161. $pharSuffixPattern = '(' . implode('|', array_map('preg_quote', $this->pharExtensions)) . ')';
  162. }
  163. foreach ($this->paths as $path) {
  164. $path = $path . $moduleClassPath;
  165. if ($path == '.' || substr($path, 0, 2) == './' || substr($path, 0, 2) == '.\\') {
  166. if (!$basePath = $this->pharBasePath) {
  167. $basePath = realpath('.');
  168. }
  169. if (false === $basePath) {
  170. $basePath = getcwd();
  171. }
  172. $path = rtrim($basePath, '\/\\') . substr($path, 1);
  173. }
  174. $classLoaded = $this->loadModuleFromDir($path, $class);
  175. if ($classLoaded) {
  176. return $classLoaded;
  177. }
  178. // No directory with Module.php, searching for phars
  179. if ($pharSuffixPattern) {
  180. foreach (new GlobIterator($path . '.*') as $entry) {
  181. if ($entry->isDir()) {
  182. continue;
  183. }
  184. if (!preg_match('#.+\.' . $pharSuffixPattern . '$#', $entry->getPathname())) {
  185. continue;
  186. }
  187. $classLoaded = $this->loadModuleFromPhar($entry->getPathname(), $class);
  188. if ($classLoaded) {
  189. return $classLoaded;
  190. }
  191. }
  192. }
  193. }
  194. return false;
  195. }
  196. /**
  197. * loadModuleFromDir
  198. *
  199. * @param string $dirPath
  200. * @param string $class
  201. * @return mixed
  202. * False [if unable to load $class]
  203. * get_class($class) [if $class is successfully loaded]
  204. */
  205. protected function loadModuleFromDir($dirPath, $class)
  206. {
  207. $modulePath = $dirPath . '/Module.php';
  208. if (substr($modulePath, 0, 7) === 'phar://') {
  209. $file = new PharFileInfo($modulePath);
  210. } else {
  211. $file = new SplFileInfo($modulePath);
  212. }
  213. if (($file->isReadable() && $file->isFile())) {
  214. // Found directory with Module.php in it
  215. $absModulePath = $this->pharBasePath ? (string) $file : $file->getRealPath();
  216. require_once $absModulePath;
  217. if (class_exists($class)) {
  218. $this->moduleClassMap[$class] = $absModulePath;
  219. return $class;
  220. }
  221. }
  222. return false;
  223. }
  224. /**
  225. * loadModuleFromPhar
  226. *
  227. * @param string $pharPath
  228. * @param string $class
  229. * @return mixed
  230. * False [if unable to load $class]
  231. * get_class($class) [if $class is successfully loaded]
  232. */
  233. protected function loadModuleFromPhar($pharPath, $class)
  234. {
  235. $pharPath = static::normalizePath($pharPath, false);
  236. $file = new SplFileInfo($pharPath);
  237. if (!$file->isReadable() || !$file->isFile()) {
  238. return false;
  239. }
  240. $fileRealPath = $file->getRealPath();
  241. // Phase 0: Check for executable phar with Module class in stub
  242. if (strpos($fileRealPath, '.phar') !== false) {
  243. // First see if the stub makes the Module class available
  244. require_once $fileRealPath;
  245. if (class_exists($class)) {
  246. $this->moduleClassMap[$class] = $fileRealPath;
  247. return $class;
  248. }
  249. }
  250. // Phase 1: Not executable phar, no stub, or stub did not provide Module class; try Module.php directly
  251. $moduleClassFile = 'phar://' . $fileRealPath . '/Module.php';
  252. $moduleFile = new SplFileInfo($moduleClassFile);
  253. if ($moduleFile->isReadable() && $moduleFile->isFile()) {
  254. require_once $moduleClassFile;
  255. if (class_exists($class)) {
  256. $this->moduleClassMap[$class] = $moduleClassFile;
  257. return $class;
  258. }
  259. }
  260. // Phase 2: Check for nested module directory within archive
  261. // Checks for /path/to/MyModule.tar/MyModule/Module.php
  262. // (shell-integrated zip/tar utilities wrap directories like this)
  263. $pharBaseName = $this->pharFileToModuleName($fileRealPath);
  264. $moduleClassFile = 'phar://' . $fileRealPath . '/' . $pharBaseName . '/Module.php';
  265. $moduleFile = new SplFileInfo($moduleClassFile);
  266. if ($moduleFile->isReadable() && $moduleFile->isFile()) {
  267. require_once $moduleClassFile;
  268. if (class_exists($class)) {
  269. $this->moduleClassMap[$class] = $moduleClassFile;
  270. return $class;
  271. }
  272. }
  273. return false;
  274. }
  275. /**
  276. * Register the autoloader with spl_autoload registry
  277. *
  278. * @return void
  279. */
  280. public function register()
  281. {
  282. spl_autoload_register(array($this, 'autoload'));
  283. }
  284. /**
  285. * Unregister the autoloader with spl_autoload registry
  286. *
  287. * @return void
  288. */
  289. public function unregister()
  290. {
  291. spl_autoload_unregister(array($this, 'autoload'));
  292. }
  293. /**
  294. * registerPaths
  295. *
  296. * @param array|Traversable $paths
  297. * @throws \InvalidArgumentException
  298. * @return ModuleAutoloader
  299. */
  300. public function registerPaths($paths)
  301. {
  302. if (!is_array($paths) && !$paths instanceof Traversable) {
  303. require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  304. throw new Exception\InvalidArgumentException(
  305. 'Parameter to \\Zend\\Loader\\ModuleAutoloader\'s '
  306. . 'registerPaths method must be an array or '
  307. . 'implement the Traversable interface'
  308. );
  309. }
  310. foreach ($paths as $module => $path) {
  311. if (is_string($module)) {
  312. $this->registerPath($path, $module);
  313. } else {
  314. $this->registerPath($path);
  315. }
  316. }
  317. return $this;
  318. }
  319. /**
  320. * registerPath
  321. *
  322. * @param string $path
  323. * @param bool|string $moduleName
  324. * @throws \InvalidArgumentException
  325. * @return ModuleAutoloader
  326. */
  327. public function registerPath($path, $moduleName = false)
  328. {
  329. if (!is_string($path)) {
  330. require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  331. throw new Exception\InvalidArgumentException(sprintf(
  332. 'Invalid path provided; must be a string, received %s',
  333. gettype($path)
  334. ));
  335. }
  336. if ($moduleName) {
  337. if (in_array(substr($moduleName, -2), array('\\*', '\\%'))) {
  338. $this->namespacedPaths[substr($moduleName, 0, -2)] = static::normalizePath($path);
  339. } else {
  340. $this->explicitPaths[$moduleName] = static::normalizePath($path);
  341. }
  342. } else {
  343. $this->paths[] = static::normalizePath($path);
  344. }
  345. return $this;
  346. }
  347. /**
  348. * getPaths
  349. *
  350. * This is primarily for unit testing, but could have other uses.
  351. *
  352. * @return array
  353. */
  354. public function getPaths()
  355. {
  356. return $this->paths;
  357. }
  358. /**
  359. * Returns the base module name from the path to a phar
  360. *
  361. * @param string $pharPath
  362. * @return string
  363. */
  364. protected function pharFileToModuleName($pharPath)
  365. {
  366. do {
  367. $pathinfo = pathinfo($pharPath);
  368. $pharPath = $pathinfo['filename'];
  369. } while (isset($pathinfo['extension']));
  370. return $pathinfo['filename'];
  371. }
  372. /**
  373. * Normalize a path for insertion in the stack
  374. *
  375. * @param string $path
  376. * @param bool $trailingSlash Whether trailing slash should be included
  377. * @return string
  378. */
  379. public static function normalizePath($path, $trailingSlash = true)
  380. {
  381. $path = rtrim($path, '/');
  382. $path = rtrim($path, '\\');
  383. if ($trailingSlash) {
  384. $path .= DIRECTORY_SEPARATOR;
  385. }
  386. return $path;
  387. }
  388. }