/fuel/core/classes/autoloader.php

https://github.com/Keilaron/TweetBeagle · PHP · 324 lines · 172 code · 31 blank · 121 comment · 17 complexity · f00f98a201598c72ac20b7a0642f3acb MD5 · raw file

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