根命名空间是一个关键的概念,例如
\think\cache\driver\File
类为例,think
就是一个根命名空间,其对应的初始命名空间目录就是系统的类库目录(thinkphp/library/think
),我们可以简单的理解一个根命名空间对应了一个类库包
分析:
/thinkphp/base.php
// 载入Loader类
require __DIR__ . '/library/think/Loader.php';
// 注册自动加载
Loader::register();
/thinkphp/library/think/loader.php
// 注册自动加载机制
public static function register($autoload = '')
{
// 注册命名空间定义
/*
获取关联数组:$prefixDirPrs4 = array(
'think\'=>array('/thinkphp/library/think'),
'traits\'=>array("/thinkphp/library/traits")
);
*/
self::addNamespace([
'think' => __DIR__ . '/',
'traits' => __DIR__ . '/../traits/',
]);
...
// 注册命名空间
public static function addNamespace($namespace, $path = '')
{
if (is_array($namespace)) {
foreach ($namespace as $prefix => $paths) {
//$prefix等于'think\' 和 'traits\'
//$path 等于'/thinkphp/library/think' 和 "/thinkphp/library/traits"
self::addPsr4($prefix . '\\', rtrim($paths, DIRECTORY_SEPARATOR), true);
}
} else {
self::addPsr4($namespace . '\\', rtrim($path, DIRECTORY_SEPARATOR), true);
}
}
// 添加Psr4空间
private static function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
self::$fallbackDirsPsr4 = array_merge(
(array) $paths,
self::$fallbackDirsPsr4
);
} else {
self::$fallbackDirsPsr4 = array_merge(
self::$fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
//$prefix等于'think\' 和 'traits\'
//$path 等于'/thinkphp/think' 和 "/thinkphp/traits"
$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;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
self::$prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
self::$prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
self::$prefixDirsPsr4[$prefix] = array_merge(
self::$prefixDirsPsr4[$prefix],
(array) $paths
);
/*
获取关联数组:$prefixDirPrs4 = array(
'think\'=>array('/thinkphp/library/think'),
'traits\'=>array("/thinkphp/library/traits")
);
此时,类库目录和根命名空间绑定
*/
}
}
自动加载
分析:
/thinkphp/library/think/base.php
// 注册自动加载机制
public static function register($autoload = '')
{
// 注册系统自动加载
// spl_autoload_register — 注册给定的函数作为 __autoload 的实现
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
- 通过命名空间引入类
use think\cache\driver\File;
- /thinkphp/library/think/load.php
// 自动加载
//这时传入$class = 'think\cache\driver\File'
public static function autoload($class)
{
if (isset(self::$classAlias[$class])) {
return class_alias(self::$classAlias[$class], $class);
}
// $file = '/thinkphp/library/think/cache/driver/File.php'
if ($file = self::findFile($class)) {
// Win环境严格区分大小写
// pathinfo() 返回一个关联数组包含有 path 的信息。返回关联数组还是字符串取决于 options。
if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
return false;
}
//将绝对路径为"/thinkphp/library/think/cache/driver/File.php"的文件加载进来
__include_file($file);
return true;
}
}
......
/**
* 查找文件
* @access private
* @param string $class
* @return string|false
*/
//这时传入$class = 'think\cache\driver\File'
private static function findFile($class)
{
// 查找 PSR-4
// string strtr ( string $str , string $from , string $to ):转换指定字符
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
$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 . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
//返回$file = "/thinkphp/library/think/cache/driver/File.php"
return $file;
}
}
}
}
}
// 查找 PSR-4 fallback dirs
foreach (self::$fallbackDirsPsr4 as $dir) {
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
}
...
/**
* 作用范围隔离
*
* @param $file
* @return mixed
*/
function __include_file($file)
{
return include $file;
}