Loader.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace think;
  12. use think\exception\ClassNotFoundException;
  13. class Loader
  14. {
  15. protected static $instance = [];
  16. // 类名映射
  17. protected static $map = [];
  18. // 命名空间别名
  19. protected static $namespaceAlias = [];
  20. // PSR-4
  21. private static $prefixLengthsPsr4 = [];
  22. private static $prefixDirsPsr4 = [];
  23. private static $fallbackDirsPsr4 = [];
  24. // PSR-0
  25. private static $prefixesPsr0 = [];
  26. private static $fallbackDirsPsr0 = [];
  27. // 自动加载的文件
  28. private static $autoloadFiles = [];
  29. // 自动加载
  30. public static function autoload($class)
  31. {
  32. // 检测命名空间别名
  33. if (!empty(self::$namespaceAlias)) {
  34. $namespace = dirname($class);
  35. if (isset(self::$namespaceAlias[$namespace])) {
  36. $original = self::$namespaceAlias[$namespace] . '\\' . basename($class);
  37. if (class_exists($original)) {
  38. return class_alias($original, $class, false);
  39. }
  40. }
  41. }
  42. if ($file = self::findFile($class)) {
  43. // Win环境严格区分大小写
  44. if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
  45. return false;
  46. }
  47. __include_file($file);
  48. return true;
  49. }
  50. }
  51. /**
  52. * 查找文件
  53. * @param $class
  54. * @return bool
  55. */
  56. private static function findFile($class)
  57. {
  58. if (!empty(self::$map[$class])) {
  59. // 类库映射
  60. return self::$map[$class];
  61. }
  62. // 查找 PSR-4
  63. $logicalPathPsr4 = strtr($class, '\\', DS) . EXT;
  64. $first = $class[0];
  65. if (isset(self::$prefixLengthsPsr4[$first])) {
  66. foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
  67. if (0 === strpos($class, $prefix)) {
  68. foreach (self::$prefixDirsPsr4[$prefix] as $dir) {
  69. if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) {
  70. return $file;
  71. }
  72. }
  73. }
  74. }
  75. }
  76. // 查找 PSR-4 fallback dirs
  77. foreach (self::$fallbackDirsPsr4 as $dir) {
  78. if (is_file($file = $dir . DS . $logicalPathPsr4)) {
  79. return $file;
  80. }
  81. }
  82. // 查找 PSR-0
  83. if (false !== $pos = strrpos($class, '\\')) {
  84. // namespaced class name
  85. $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
  86. . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);
  87. } else {
  88. // PEAR-like class name
  89. $logicalPathPsr0 = strtr($class, '_', DS) . EXT;
  90. }
  91. if (isset(self::$prefixesPsr0[$first])) {
  92. foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) {
  93. if (0 === strpos($class, $prefix)) {
  94. foreach ($dirs as $dir) {
  95. if (is_file($file = $dir . DS . $logicalPathPsr0)) {
  96. return $file;
  97. }
  98. }
  99. }
  100. }
  101. }
  102. // 查找 PSR-0 fallback dirs
  103. foreach (self::$fallbackDirsPsr0 as $dir) {
  104. if (is_file($file = $dir . DS . $logicalPathPsr0)) {
  105. return $file;
  106. }
  107. }
  108. return self::$map[$class] = false;
  109. }
  110. // 注册classmap
  111. public static function addClassMap($class, $map = '')
  112. {
  113. if (is_array($class)) {
  114. self::$map = array_merge(self::$map, $class);
  115. } else {
  116. self::$map[$class] = $map;
  117. }
  118. }
  119. // 注册命名空间
  120. public static function addNamespace($namespace, $path = '')
  121. {
  122. if (is_array($namespace)) {
  123. foreach ($namespace as $prefix => $paths) {
  124. self::addPsr4($prefix . '\\', rtrim($paths, DS), true);
  125. }
  126. } else {
  127. self::addPsr4($namespace . '\\', rtrim($path, DS), true);
  128. }
  129. }
  130. // 添加Ps0空间
  131. private static function addPsr0($prefix, $paths, $prepend = false)
  132. {
  133. if (!$prefix) {
  134. if ($prepend) {
  135. self::$fallbackDirsPsr0 = array_merge(
  136. (array) $paths,
  137. self::$fallbackDirsPsr0
  138. );
  139. } else {
  140. self::$fallbackDirsPsr0 = array_merge(
  141. self::$fallbackDirsPsr0,
  142. (array) $paths
  143. );
  144. }
  145. return;
  146. }
  147. $first = $prefix[0];
  148. if (!isset(self::$prefixesPsr0[$first][$prefix])) {
  149. self::$prefixesPsr0[$first][$prefix] = (array) $paths;
  150. return;
  151. }
  152. if ($prepend) {
  153. self::$prefixesPsr0[$first][$prefix] = array_merge(
  154. (array) $paths,
  155. self::$prefixesPsr0[$first][$prefix]
  156. );
  157. } else {
  158. self::$prefixesPsr0[$first][$prefix] = array_merge(
  159. self::$prefixesPsr0[$first][$prefix],
  160. (array) $paths
  161. );
  162. }
  163. }
  164. // 添加Psr4空间
  165. private static function addPsr4($prefix, $paths, $prepend = false)
  166. {
  167. if (!$prefix) {
  168. // Register directories for the root namespace.
  169. if ($prepend) {
  170. self::$fallbackDirsPsr4 = array_merge(
  171. (array) $paths,
  172. self::$fallbackDirsPsr4
  173. );
  174. } else {
  175. self::$fallbackDirsPsr4 = array_merge(
  176. self::$fallbackDirsPsr4,
  177. (array) $paths
  178. );
  179. }
  180. } elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
  181. // Register directories for a new namespace.
  182. $length = strlen($prefix);
  183. if ('\\' !== $prefix[$length - 1]) {
  184. throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
  185. }
  186. self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
  187. self::$prefixDirsPsr4[$prefix] = (array) $paths;
  188. } elseif ($prepend) {
  189. // Prepend directories for an already registered namespace.
  190. self::$prefixDirsPsr4[$prefix] = array_merge(
  191. (array) $paths,
  192. self::$prefixDirsPsr4[$prefix]
  193. );
  194. } else {
  195. // Append directories for an already registered namespace.
  196. self::$prefixDirsPsr4[$prefix] = array_merge(
  197. self::$prefixDirsPsr4[$prefix],
  198. (array) $paths
  199. );
  200. }
  201. }
  202. // 注册命名空间别名
  203. public static function addNamespaceAlias($namespace, $original = '')
  204. {
  205. if (is_array($namespace)) {
  206. self::$namespaceAlias = array_merge(self::$namespaceAlias, $namespace);
  207. } else {
  208. self::$namespaceAlias[$namespace] = $original;
  209. }
  210. }
  211. // 注册自动加载机制
  212. public static function register($autoload = '')
  213. {
  214. // 注册系统自动加载
  215. spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
  216. // 注册命名空间定义
  217. self::addNamespace([
  218. 'think' => LIB_PATH . 'think' . DS,
  219. 'behavior' => LIB_PATH . 'behavior' . DS,
  220. 'traits' => LIB_PATH . 'traits' . DS,
  221. ]);
  222. // 加载类库映射文件
  223. if (is_file(RUNTIME_PATH . 'classmap' . EXT)) {
  224. self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT));
  225. }
  226. // Composer自动加载支持
  227. if (is_dir(VENDOR_PATH . 'composer')) {
  228. self::registerComposerLoader();
  229. }
  230. // 自动加载extend目录
  231. self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);
  232. }
  233. // 注册composer自动加载
  234. private static function registerComposerLoader()
  235. {
  236. if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) {
  237. $map = require VENDOR_PATH . 'composer/autoload_namespaces.php';
  238. foreach ($map as $namespace => $path) {
  239. self::addPsr0($namespace, $path);
  240. }
  241. }
  242. if (is_file(VENDOR_PATH . 'composer/autoload_psr4.php')) {
  243. $map = require VENDOR_PATH . 'composer/autoload_psr4.php';
  244. foreach ($map as $namespace => $path) {
  245. self::addPsr4($namespace, $path);
  246. }
  247. }
  248. if (is_file(VENDOR_PATH . 'composer/autoload_classmap.php')) {
  249. $classMap = require VENDOR_PATH . 'composer/autoload_classmap.php';
  250. if ($classMap) {
  251. self::addClassMap($classMap);
  252. }
  253. }
  254. if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) {
  255. $includeFiles = require VENDOR_PATH . 'composer/autoload_files.php';
  256. foreach ($includeFiles as $fileIdentifier => $file) {
  257. if (empty(self::$autoloadFiles[$fileIdentifier])) {
  258. __require_file($file);
  259. self::$autoloadFiles[$fileIdentifier] = true;
  260. }
  261. }
  262. }
  263. }
  264. /**
  265. * 导入所需的类库 同java的Import 本函数有缓存功能
  266. * @param string $class 类库命名空间字符串
  267. * @param string $baseUrl 起始路径
  268. * @param string $ext 导入的文件扩展名
  269. * @return boolean
  270. */
  271. public static function import($class, $baseUrl = '', $ext = EXT)
  272. {
  273. static $_file = [];
  274. $key = $class . $baseUrl;
  275. $class = str_replace(['.', '#'], [DS, '.'], $class);
  276. if (isset($_file[$key])) {
  277. return true;
  278. }
  279. if (empty($baseUrl)) {
  280. list($name, $class) = explode(DS, $class, 2);
  281. if (isset(self::$prefixDirsPsr4[$name . '\\'])) {
  282. // 注册的命名空间
  283. $baseUrl = self::$prefixDirsPsr4[$name . '\\'];
  284. } elseif ('@' == $name) {
  285. //加载当前模块应用类库
  286. $baseUrl = App::$modulePath;
  287. } elseif (is_dir(EXTEND_PATH . $name)) {
  288. $baseUrl = EXTEND_PATH . $name . DS;
  289. } else {
  290. // 加载其它模块的类库
  291. $baseUrl = APP_PATH . $name . DS;
  292. }
  293. } elseif (substr($baseUrl, -1) != DS) {
  294. $baseUrl .= DS;
  295. }
  296. // 如果类存在 则导入类库文件
  297. if (is_array($baseUrl)) {
  298. foreach ($baseUrl as $path) {
  299. $filename = $path . DS . $class . $ext;
  300. if (is_file($filename)) {
  301. break;
  302. }
  303. }
  304. } else {
  305. $filename = $baseUrl . $class . $ext;
  306. }
  307. if (!empty($filename) && is_file($filename)) {
  308. // 开启调试模式Win环境严格区分大小写
  309. if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) {
  310. return false;
  311. }
  312. __include_file($filename);
  313. $_file[$key] = true;
  314. return true;
  315. }
  316. return false;
  317. }
  318. /**
  319. * 实例化(分层)模型
  320. * @param string $name Model名称
  321. * @param string $layer 业务层名称
  322. * @param bool $appendSuffix 是否添加类名后缀
  323. * @param string $common 公共模块名
  324. * @return Object
  325. * @throws ClassNotFoundException
  326. */
  327. public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
  328. {
  329. $guid = $name . $layer;
  330. if (isset(self::$instance[$guid])) {
  331. return self::$instance[$guid];
  332. }
  333. if (strpos($name, '\\')) {
  334. $class = $name;
  335. } else {
  336. if (strpos($name, '/')) {
  337. list($module, $name) = explode('/', $name, 2);
  338. } else {
  339. $module = Request::instance()->module();
  340. }
  341. $class = self::parseClass($module, $layer, $name, $appendSuffix);
  342. }
  343. if (class_exists($class)) {
  344. $model = new $class();
  345. } else {
  346. $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
  347. if (class_exists($class)) {
  348. $model = new $class();
  349. } else {
  350. throw new ClassNotFoundException('class not exists:' . $class, $class);
  351. }
  352. }
  353. self::$instance[$guid] = $model;
  354. return $model;
  355. }
  356. /**
  357. * 实例化(分层)控制器 格式:[模块名/]控制器名
  358. * @param string $name 资源地址
  359. * @param string $layer 控制层名称
  360. * @param bool $appendSuffix 是否添加类名后缀
  361. * @param string $empty 空控制器名称
  362. * @return Object|false
  363. * @throws ClassNotFoundException
  364. */
  365. public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
  366. {
  367. if (strpos($name, '\\')) {
  368. $class = $name;
  369. } else {
  370. if (strpos($name, '/')) {
  371. list($module, $name) = explode('/', $name);
  372. } else {
  373. $module = Request::instance()->module();
  374. }
  375. $class = self::parseClass($module, $layer, $name, $appendSuffix);
  376. }
  377. if (class_exists($class)) {
  378. return App::invokeClass($class);
  379. } elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) {
  380. return new $emptyClass(Request::instance());
  381. }
  382. }
  383. /**
  384. * 实例化验证类 格式:[模块名/]验证器名
  385. * @param string $name 资源地址
  386. * @param string $layer 验证层名称
  387. * @param bool $appendSuffix 是否添加类名后缀
  388. * @param string $common 公共模块名
  389. * @return Object|false
  390. * @throws ClassNotFoundException
  391. */
  392. public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
  393. {
  394. $name = $name ?: Config::get('default_validate');
  395. if (empty($name)) {
  396. return new Validate;
  397. }
  398. $guid = $name . $layer;
  399. if (isset(self::$instance[$guid])) {
  400. return self::$instance[$guid];
  401. }
  402. if (strpos($name, '\\')) {
  403. $class = $name;
  404. } else {
  405. if (strpos($name, '/')) {
  406. list($module, $name) = explode('/', $name);
  407. } else {
  408. $module = Request::instance()->module();
  409. }
  410. $class = self::parseClass($module, $layer, $name, $appendSuffix);
  411. }
  412. if (class_exists($class)) {
  413. $validate = new $class;
  414. } else {
  415. $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
  416. if (class_exists($class)) {
  417. $validate = new $class;
  418. } else {
  419. throw new ClassNotFoundException('class not exists:' . $class, $class);
  420. }
  421. }
  422. self::$instance[$guid] = $validate;
  423. return $validate;
  424. }
  425. /**
  426. * 数据库初始化 并取得数据库类实例
  427. * @param mixed $config 数据库配置
  428. * @param bool|string $name 连接标识 true 强制重新连接
  429. * @return \think\db\Connection
  430. */
  431. public static function db($config = [], $name = false)
  432. {
  433. return Db::connect($config, $name);
  434. }
  435. /**
  436. * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
  437. * @param string $url 调用地址
  438. * @param string|array $vars 调用参数 支持字符串和数组
  439. * @param string $layer 要调用的控制层名称
  440. * @param bool $appendSuffix 是否添加类名后缀
  441. * @return mixed
  442. */
  443. public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
  444. {
  445. $info = pathinfo($url);
  446. $action = $info['basename'];
  447. $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller();
  448. $class = self::controller($module, $layer, $appendSuffix);
  449. if ($class) {
  450. if (is_scalar($vars)) {
  451. if (strpos($vars, '=')) {
  452. parse_str($vars, $vars);
  453. } else {
  454. $vars = [$vars];
  455. }
  456. }
  457. return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars);
  458. }
  459. }
  460. /**
  461. * 字符串命名风格转换
  462. * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
  463. * @param string $name 字符串
  464. * @param integer $type 转换类型
  465. * @param bool $ucfirst 首字母是否大写(驼峰规则)
  466. * @return string
  467. */
  468. public static function parseName($name, $type = 0, $ucfirst = true)
  469. {
  470. if ($type) {
  471. $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
  472. return strtoupper($match[1]);
  473. }, $name);
  474. return $ucfirst ? ucfirst($name) : lcfirst($name);
  475. } else {
  476. return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
  477. }
  478. }
  479. /**
  480. * 解析应用类的类名
  481. * @param string $module 模块名
  482. * @param string $layer 层名 controller model ...
  483. * @param string $name 类名
  484. * @param bool $appendSuffix
  485. * @return string
  486. */
  487. public static function parseClass($module, $layer, $name, $appendSuffix = false)
  488. {
  489. $name = str_replace(['/', '.'], '\\', $name);
  490. $array = explode('\\', $name);
  491. $class = self::parseName(array_pop($array), 1) . (App::$suffix || $appendSuffix ? ucfirst($layer) : '');
  492. $path = $array ? implode('\\', $array) . '\\' : '';
  493. return App::$namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class;
  494. }
  495. /**
  496. * 初始化类的实例
  497. * @return void
  498. */
  499. public static function clearInstance()
  500. {
  501. self::$instance = [];
  502. }
  503. }
  504. /**
  505. * 作用范围隔离
  506. *
  507. * @param $file
  508. * @return mixed
  509. */
  510. function __include_file($file)
  511. {
  512. return include $file;
  513. }
  514. function __require_file($file)
  515. {
  516. return require $file;
  517. }