|
|
<?php |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace think; |
|
|
|
|
|
use think\exception\ClassNotFoundException; |
|
|
|
|
|
class Loader |
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
protected static $instance = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static $classMap = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static $namespaceAlias = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static $prefixLengthsPsr4 = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static $prefixDirsPsr4 = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static $fallbackDirsPsr4 = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static $prefixesPsr0 = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static $fallbackDirsPsr0 = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static $files = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function autoload($class) |
|
|
{ |
|
|
|
|
|
if (!empty(self::$namespaceAlias)) { |
|
|
$namespace = dirname($class); |
|
|
if (isset(self::$namespaceAlias[$namespace])) { |
|
|
$original = self::$namespaceAlias[$namespace] . '\\' . basename($class); |
|
|
if (class_exists($original)) { |
|
|
return class_alias($original, $class, false); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if ($file = self::findFile($class)) { |
|
|
|
|
|
if (!IS_WIN || pathinfo($file, PATHINFO_FILENAME) == pathinfo(realpath($file), PATHINFO_FILENAME)) { |
|
|
__include_file($file); |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static function findFile($class) |
|
|
{ |
|
|
|
|
|
if (!empty(self::$classMap[$class])) { |
|
|
return self::$classMap[$class]; |
|
|
} |
|
|
|
|
|
|
|
|
$logicalPathPsr4 = strtr($class, '\\', DS) . EXT; |
|
|
$first = $class[0]; |
|
|
|
|
|
if (isset(self::$prefixLengthsPsr4[$first])) { |
|
|
foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) { |
|
|
if (0 === strpos($class, $prefix)) { |
|
|
foreach (self::$prefixDirsPsr4[$prefix] as $dir) { |
|
|
if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) { |
|
|
return $file; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
foreach (self::$fallbackDirsPsr4 as $dir) { |
|
|
if (is_file($file = $dir . DS . $logicalPathPsr4)) { |
|
|
return $file; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (false !== $pos = strrpos($class, '\\')) { |
|
|
|
|
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) |
|
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DS); |
|
|
} else { |
|
|
|
|
|
$logicalPathPsr0 = strtr($class, '_', DS) . EXT; |
|
|
} |
|
|
|
|
|
if (isset(self::$prefixesPsr0[$first])) { |
|
|
foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) { |
|
|
if (0 === strpos($class, $prefix)) { |
|
|
foreach ($dirs as $dir) { |
|
|
if (is_file($file = $dir . DS . $logicalPathPsr0)) { |
|
|
return $file; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
foreach (self::$fallbackDirsPsr0 as $dir) { |
|
|
if (is_file($file = $dir . DS . $logicalPathPsr0)) { |
|
|
return $file; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return self::$classMap[$class] = false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function addClassMap($class, $map = '') |
|
|
{ |
|
|
if (is_array($class)) { |
|
|
self::$classMap = array_merge(self::$classMap, $class); |
|
|
} else { |
|
|
self::$classMap[$class] = $map; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function addNamespace($namespace, $path = '') |
|
|
{ |
|
|
if (is_array($namespace)) { |
|
|
foreach ($namespace as $prefix => $paths) { |
|
|
self::addPsr4($prefix . '\\', rtrim($paths, DS), true); |
|
|
} |
|
|
} else { |
|
|
self::addPsr4($namespace . '\\', rtrim($path, DS), true); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static function addPsr0($prefix, $paths, $prepend = false) |
|
|
{ |
|
|
if (!$prefix) { |
|
|
self::$fallbackDirsPsr0 = $prepend ? |
|
|
array_merge((array) $paths, self::$fallbackDirsPsr0) : |
|
|
array_merge(self::$fallbackDirsPsr0, (array) $paths); |
|
|
} else { |
|
|
$first = $prefix[0]; |
|
|
|
|
|
if (!isset(self::$prefixesPsr0[$first][$prefix])) { |
|
|
self::$prefixesPsr0[$first][$prefix] = (array) $paths; |
|
|
} else { |
|
|
self::$prefixesPsr0[$first][$prefix] = $prepend ? |
|
|
array_merge((array) $paths, self::$prefixesPsr0[$first][$prefix]) : |
|
|
array_merge(self::$prefixesPsr0[$first][$prefix], (array) $paths); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static function addPsr4($prefix, $paths, $prepend = false) |
|
|
{ |
|
|
if (!$prefix) { |
|
|
|
|
|
self::$fallbackDirsPsr4 = $prepend ? |
|
|
array_merge((array) $paths, self::$fallbackDirsPsr4) : |
|
|
array_merge(self::$fallbackDirsPsr4, (array) $paths); |
|
|
|
|
|
} elseif (!isset(self::$prefixDirsPsr4[$prefix])) { |
|
|
|
|
|
$length = strlen($prefix); |
|
|
if ('\\' !== $prefix[$length - 1]) { |
|
|
throw new \InvalidArgumentException( |
|
|
"A non-empty PSR-4 prefix must end with a namespace separator." |
|
|
); |
|
|
} |
|
|
|
|
|
self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length; |
|
|
self::$prefixDirsPsr4[$prefix] = (array) $paths; |
|
|
|
|
|
} else { |
|
|
self::$prefixDirsPsr4[$prefix] = $prepend ? |
|
|
|
|
|
array_merge((array) $paths, self::$prefixDirsPsr4[$prefix]) : |
|
|
|
|
|
array_merge(self::$prefixDirsPsr4[$prefix], (array) $paths); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function addNamespaceAlias($namespace, $original = '') |
|
|
{ |
|
|
if (is_array($namespace)) { |
|
|
self::$namespaceAlias = array_merge(self::$namespaceAlias, $namespace); |
|
|
} else { |
|
|
self::$namespaceAlias[$namespace] = $original; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function register($autoload = null) |
|
|
{ |
|
|
|
|
|
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); |
|
|
|
|
|
|
|
|
if (is_dir(VENDOR_PATH . 'composer')) { |
|
|
if (PHP_VERSION_ID >= 50600 && is_file(VENDOR_PATH . 'composer' . DS . 'autoload_static.php')) { |
|
|
require VENDOR_PATH . 'composer' . DS . 'autoload_static.php'; |
|
|
|
|
|
$declaredClass = get_declared_classes(); |
|
|
$composerClass = array_pop($declaredClass); |
|
|
|
|
|
foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { |
|
|
if (property_exists($composerClass, $attr)) { |
|
|
self::${$attr} = $composerClass::${$attr}; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
self::registerComposerLoader(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
self::addNamespace([ |
|
|
'think' => LIB_PATH . 'think' . DS, |
|
|
'behavior' => LIB_PATH . 'behavior' . DS, |
|
|
'traits' => LIB_PATH . 'traits' . DS, |
|
|
]); |
|
|
|
|
|
|
|
|
if (is_file(RUNTIME_PATH . 'classmap' . EXT)) { |
|
|
self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT)); |
|
|
} |
|
|
|
|
|
self::loadComposerAutoloadFiles(); |
|
|
|
|
|
|
|
|
self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static function registerComposerLoader() |
|
|
{ |
|
|
if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) { |
|
|
$map = require VENDOR_PATH . 'composer/autoload_namespaces.php'; |
|
|
foreach ($map as $namespace => $path) { |
|
|
self::addPsr0($namespace, $path); |
|
|
} |
|
|
} |
|
|
|
|
|
if (is_file(VENDOR_PATH . 'composer/autoload_psr4.php')) { |
|
|
$map = require VENDOR_PATH . 'composer/autoload_psr4.php'; |
|
|
foreach ($map as $namespace => $path) { |
|
|
self::addPsr4($namespace, $path); |
|
|
} |
|
|
} |
|
|
|
|
|
if (is_file(VENDOR_PATH . 'composer/autoload_classmap.php')) { |
|
|
$classMap = require VENDOR_PATH . 'composer/autoload_classmap.php'; |
|
|
if ($classMap) { |
|
|
self::addClassMap($classMap); |
|
|
} |
|
|
} |
|
|
|
|
|
if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) { |
|
|
self::$files = require VENDOR_PATH . 'composer/autoload_files.php'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public static function loadComposerAutoloadFiles() |
|
|
{ |
|
|
foreach (self::$files as $fileIdentifier => $file) { |
|
|
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { |
|
|
__require_file($file); |
|
|
|
|
|
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function import($class, $baseUrl = '', $ext = EXT) |
|
|
{ |
|
|
static $_file = []; |
|
|
$key = $class . $baseUrl; |
|
|
$class = str_replace(['.', '#'], [DS, '.'], $class); |
|
|
|
|
|
if (isset($_file[$key])) { |
|
|
return true; |
|
|
} |
|
|
|
|
|
if (empty($baseUrl)) { |
|
|
list($name, $class) = explode(DS, $class, 2); |
|
|
|
|
|
if (isset(self::$prefixDirsPsr4[$name . '\\'])) { |
|
|
|
|
|
$baseUrl = self::$prefixDirsPsr4[$name . '\\']; |
|
|
} elseif ('@' == $name) { |
|
|
|
|
|
$baseUrl = App::$modulePath; |
|
|
} elseif (is_dir(EXTEND_PATH . $name)) { |
|
|
$baseUrl = EXTEND_PATH . $name . DS; |
|
|
} else { |
|
|
|
|
|
$baseUrl = APP_PATH . $name . DS; |
|
|
} |
|
|
} elseif (substr($baseUrl, -1) != DS) { |
|
|
$baseUrl .= DS; |
|
|
} |
|
|
|
|
|
|
|
|
if (is_array($baseUrl)) { |
|
|
foreach ($baseUrl as $path) { |
|
|
if (is_file($filename = $path . DS . $class . $ext)) { |
|
|
break; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
$filename = $baseUrl . $class . $ext; |
|
|
} |
|
|
|
|
|
if (!empty($filename) && |
|
|
is_file($filename) && |
|
|
(!IS_WIN || pathinfo($filename, PATHINFO_FILENAME) == pathinfo(realpath($filename), PATHINFO_FILENAME)) |
|
|
) { |
|
|
__include_file($filename); |
|
|
$_file[$key] = true; |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common') |
|
|
{ |
|
|
$uid = $name . $layer; |
|
|
|
|
|
if (isset(self::$instance[$uid])) { |
|
|
return self::$instance[$uid]; |
|
|
} |
|
|
|
|
|
list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); |
|
|
|
|
|
if (class_exists($class)) { |
|
|
$model = new $class(); |
|
|
} else { |
|
|
$class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); |
|
|
|
|
|
if (class_exists($class)) { |
|
|
$model = new $class(); |
|
|
} else { |
|
|
throw new ClassNotFoundException('class not exists:' . $class, $class); |
|
|
} |
|
|
} |
|
|
|
|
|
return self::$instance[$uid] = $model; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '') |
|
|
{ |
|
|
list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); |
|
|
|
|
|
if (class_exists($class)) { |
|
|
return App::invokeClass($class); |
|
|
} |
|
|
|
|
|
if ($empty) { |
|
|
$emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix); |
|
|
|
|
|
if (class_exists($emptyClass)) { |
|
|
return new $emptyClass(Request::instance()); |
|
|
} |
|
|
} |
|
|
|
|
|
throw new ClassNotFoundException('class not exists:' . $class, $class); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common') |
|
|
{ |
|
|
$name = $name ?: Config::get('default_validate'); |
|
|
|
|
|
if (empty($name)) { |
|
|
return new Validate; |
|
|
} |
|
|
|
|
|
$uid = $name . $layer; |
|
|
if (isset(self::$instance[$uid])) { |
|
|
return self::$instance[$uid]; |
|
|
} |
|
|
|
|
|
list($module, $class) = self::getModuleAndClass($name, $layer, $appendSuffix); |
|
|
|
|
|
if (class_exists($class)) { |
|
|
$validate = new $class; |
|
|
} else { |
|
|
$class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); |
|
|
|
|
|
if (class_exists($class)) { |
|
|
$validate = new $class; |
|
|
} else { |
|
|
throw new ClassNotFoundException('class not exists:' . $class, $class); |
|
|
} |
|
|
} |
|
|
|
|
|
return self::$instance[$uid] = $validate; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected static function getModuleAndClass($name, $layer, $appendSuffix) |
|
|
{ |
|
|
if (false !== strpos($name, '\\')) { |
|
|
$module = Request::instance()->module(); |
|
|
$class = $name; |
|
|
} else { |
|
|
if (strpos($name, '/')) { |
|
|
list($module, $name) = explode('/', $name, 2); |
|
|
} else { |
|
|
$module = Request::instance()->module(); |
|
|
} |
|
|
|
|
|
$class = self::parseClass($module, $layer, $name, $appendSuffix); |
|
|
} |
|
|
|
|
|
return [$module, $class]; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function db($config = [], $name = false) |
|
|
{ |
|
|
return Db::connect($config, $name); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false) |
|
|
{ |
|
|
$info = pathinfo($url); |
|
|
$action = $info['basename']; |
|
|
$module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller(); |
|
|
$class = self::controller($module, $layer, $appendSuffix); |
|
|
|
|
|
if ($class) { |
|
|
if (is_scalar($vars)) { |
|
|
if (strpos($vars, '=')) { |
|
|
parse_str($vars, $vars); |
|
|
} else { |
|
|
$vars = [$vars]; |
|
|
} |
|
|
} |
|
|
|
|
|
return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars); |
|
|
} |
|
|
|
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function parseName($name, $type = 0, $ucfirst = true) |
|
|
{ |
|
|
if ($type) { |
|
|
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { |
|
|
return strtoupper($match[1]); |
|
|
}, $name); |
|
|
|
|
|
return $ucfirst ? ucfirst($name) : lcfirst($name); |
|
|
} |
|
|
|
|
|
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function parseClass($module, $layer, $name, $appendSuffix = false) |
|
|
{ |
|
|
|
|
|
$array = explode('\\', str_replace(['/', '.'], '\\', $name)); |
|
|
$class = self::parseName(array_pop($array), 1); |
|
|
$class = $class . (App::$suffix || $appendSuffix ? ucfirst($layer) : ''); |
|
|
$path = $array ? implode('\\', $array) . '\\' : ''; |
|
|
|
|
|
return App::$namespace . '\\' . |
|
|
($module ? $module . '\\' : '') . |
|
|
$layer . '\\' . $path . $class; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function clearInstance() |
|
|
{ |
|
|
self::$instance = []; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function __include_file($file) |
|
|
{ |
|
|
return include $file; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function __require_file($file) |
|
|
{ |
|
|
return require $file; |
|
|
} |
|
|
|