PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/core/classes/autoloader.php

https://bitbucket.org/codeyash/bootstrap
PHP | 356 lines | 237 code | 21 blank | 98 comment | 10 complexity | 5a114815f021bb0f0be719a823d409be MD5 | raw file
Possible License(s): MIT, Apache-2.0
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * The Autloader is responsible for all class loading. It allows you to define
  15. * different load paths based on namespaces. It also lets you set explicit paths
  16. * for classes to be loaded from.
  17. *
  18. * @package Fuel
  19. * @subpackage Core
  20. */
  21. class Autoloader
  22. {
  23. /**
  24. * @var array $classes holds all the classes and paths
  25. */
  26. protected static $classes = array();
  27. /**
  28. * @var array holds all the namespace paths
  29. */
  30. protected static $namespaces = array();
  31. /**
  32. * Holds all the PSR-0 compliant namespaces. These namespaces should
  33. * be loaded according to the PSR-0 standard.
  34. *
  35. * @var array
  36. */
  37. protected static $psr_namespaces = array();
  38. /**
  39. * @var array list off namespaces of which classes will be aliased to global namespace
  40. */
  41. protected static $core_namespaces = array(
  42. 'Fuel\\Core'
  43. );
  44. /**
  45. * @var array the default path to look in if the class is not in a package
  46. */
  47. protected static $default_path = null;
  48. /**
  49. * @var bool whether to initialize a loaded class
  50. */
  51. protected static $auto_initialize = null;
  52. /**
  53. * Adds a namespace search path. Any class in the given namespace will be
  54. * looked for in the given path.
  55. *
  56. * @param string the namespace
  57. * @param string the path
  58. * @return void
  59. */
  60. public static function add_namespace($namespace, $path, $psr = false)
  61. {
  62. static::$namespaces[$namespace] = $path;
  63. if ($psr)
  64. {
  65. static::$psr_namespaces[$namespace] = $path;
  66. }
  67. }
  68. /**
  69. * Adds an array of namespace paths. See {add_namespace}.
  70. *
  71. * @param array the namespaces
  72. * @param bool whether to prepend the namespace to the search path
  73. * @return void
  74. */
  75. public static function add_namespaces(array $namespaces, $prepend = false)
  76. {
  77. if ( ! $prepend)
  78. {
  79. static::$namespaces = array_merge(static::$namespaces, $namespaces);
  80. }
  81. else
  82. {
  83. static::$namespaces = $namespaces + static::$namespaces;
  84. }
  85. }
  86. /**
  87. * Returns the namespace's path or false when it doesn't exist.
  88. *
  89. * @param string the namespace to get the path for
  90. * @return array|bool the namespace path or false
  91. */
  92. public static function namespace_path($namespace)
  93. {
  94. if ( ! array_key_exists($namespace, static::$namespaces))
  95. {
  96. return false;
  97. }
  98. return static::$namespaces[$namespace];
  99. }
  100. /**
  101. * Adds a classes load path. Any class added here will not be searched for
  102. * but explicitly loaded from the path.
  103. *
  104. * @param string the class name
  105. * @param string the path to the class file
  106. * @return void
  107. */
  108. public static function add_class($class, $path)
  109. {
  110. static::$classes[$class] = $path;
  111. }
  112. /**
  113. * Adds multiple class paths to the load path. See {@see Autoloader::add_class}.
  114. *
  115. * @param array the class names and paths
  116. * @return void
  117. */
  118. public static function add_classes($classes)
  119. {
  120. foreach ($classes as $class => $path)
  121. {
  122. static::$classes[$class] = $path;
  123. }
  124. }
  125. /**
  126. * Aliases the given class into the given Namespace. By default it will
  127. * add it to the global namespace.
  128. *
  129. * <code>
  130. * Autoloader::alias_to_namespace('Foo\\Bar');
  131. * Autoloader::alias_to_namespace('Foo\\Bar', '\\Baz');
  132. * </code>
  133. *
  134. * @param string $class the class name
  135. * @param string $namespace the namespace to alias to
  136. */
  137. public static function alias_to_namespace($class, $namespace = '')
  138. {
  139. empty($namespace) or $namespace = rtrim($namespace, '\\').'\\';
  140. $parts = explode('\\', $class);
  141. $root_class = $namespace.array_pop($parts);
  142. class_alias($class, $root_class);
  143. }
  144. /**
  145. * Register's the autoloader to the SPL autoload stack.
  146. *
  147. * @return void
  148. */
  149. public static function register()
  150. {
  151. spl_autoload_register('Autoloader::load', true, true);
  152. }
  153. /**
  154. * Returns the class with namespace prefix when available
  155. *
  156. * @param string
  157. * @return bool|string
  158. */
  159. protected static function find_core_class($class)
  160. {
  161. foreach (static::$core_namespaces as $ns)
  162. {
  163. if (array_key_exists($ns_class = $ns.'\\'.$class, static::$classes))
  164. {
  165. return $ns_class;
  166. }
  167. }
  168. return false;
  169. }
  170. /**
  171. * Add a namespace for which classes may be used without the namespace prefix and
  172. * will be auto-aliased to the global namespace.
  173. * Prefixing the classes will overwrite core classes and previously added namespaces.
  174. *
  175. * @param string
  176. * @param bool
  177. * @return void
  178. */
  179. public static function add_core_namespace($namespace, $prefix = true)
  180. {
  181. if ($prefix)
  182. {
  183. array_unshift(static::$core_namespaces, $namespace);
  184. }
  185. else
  186. {
  187. array_push(static::$core_namespaces, $namespace);
  188. }
  189. }
  190. /**
  191. * Loads a class.
  192. *
  193. * @param string $class Class to load
  194. * @return bool If it loaded the class
  195. */
  196. public static function load($class)
  197. {
  198. // deal with funny is_callable('static::classname') side-effect
  199. if (strpos($class, 'static::') === 0)
  200. {
  201. // is called from within the class, so it's already loaded
  202. return true;
  203. }
  204. $loaded = false;
  205. $class = ltrim($class, '\\');
  206. $namespaced = ($pos = strripos($class, '\\')) !== false;
  207. if (empty(static::$auto_initialize))
  208. {
  209. static::$auto_initialize = $class;
  210. }
  211. if (isset(static::$classes[$class]))
  212. {
  213. include str_replace('/', DS, static::$classes[$class]);
  214. static::init_class($class);
  215. $loaded = true;
  216. }
  217. elseif ($full_class = static::find_core_class($class))
  218. {
  219. if ( ! class_exists($full_class, false) and ! interface_exists($full_class, false))
  220. {
  221. include static::prep_path(static::$classes[$full_class]);
  222. }
  223. class_alias($full_class, $class);
  224. static::init_class($class);
  225. $loaded = true;
  226. }
  227. else
  228. {
  229. $full_ns = substr($class, 0, $pos);
  230. if ($full_ns)
  231. {
  232. foreach (static::$namespaces as $ns => $path)
  233. {
  234. $ns = ltrim($ns, '\\');
  235. if (stripos($full_ns, $ns) === 0)
  236. {
  237. $path .= static::class_to_path(
  238. substr($class, strlen($ns) + 1),
  239. array_key_exists($ns, static::$psr_namespaces)
  240. );
  241. if (is_file($path))
  242. {
  243. require $path;
  244. static::init_class($class);
  245. $loaded = true;
  246. break;
  247. }
  248. }
  249. }
  250. }
  251. if ( ! $loaded)
  252. {
  253. $path = APPPATH.'classes/'.static::class_to_path($class);
  254. if (file_exists($path))
  255. {
  256. include $path;
  257. static::init_class($class);
  258. $loaded = true;
  259. }
  260. }
  261. }
  262. // Prevent failed load from keeping other classes from initializing
  263. if (static::$auto_initialize == $class)
  264. {
  265. static::$auto_initialize = null;
  266. }
  267. return $loaded;
  268. }
  269. /**
  270. * Takes a class name and turns it into a path. It follows the PSR-0
  271. * standard, except for makes the entire path lower case, unless you
  272. * tell it otherwise.
  273. *
  274. * Note: This does not check if the file exists...just gets the path
  275. *
  276. * @param string $class Class name
  277. * @param bool $psr Whether this is a PSR-0 compliant class
  278. * @return string Path for the class
  279. */
  280. protected static function class_to_path($class, $psr = false)
  281. {
  282. $file = '';
  283. if ($last_ns_pos = strripos($class, '\\'))
  284. {
  285. $namespace = substr($class, 0, $last_ns_pos);
  286. $class = substr($class, $last_ns_pos + 1);
  287. $file = str_replace('\\', DS, $namespace).DS;
  288. }
  289. $file .= str_replace('_', DS, $class).'.php';
  290. if ( ! $psr)
  291. {
  292. $file = strtolower($file);
  293. }
  294. return $file;
  295. }
  296. /**
  297. * Prepares a given path by making sure the directory separators are correct.
  298. *
  299. * @param string $path Path to prepare
  300. * @return string Prepped path
  301. */
  302. protected static function prep_path($path)
  303. {
  304. return str_replace(array('/', '\\'), DS, $path);
  305. }
  306. /**
  307. * Checks to see if the given class has a static _init() method. If so then
  308. * it calls it.
  309. *
  310. * @param string the class name
  311. */
  312. protected static function init_class($class)
  313. {
  314. if (static::$auto_initialize === $class)
  315. {
  316. static::$auto_initialize = null;
  317. if (method_exists($class, '_init') and is_callable($class.'::_init'))
  318. {
  319. call_user_func($class.'::_init');
  320. }
  321. }
  322. }
  323. }