我有一个自定义算法来加载类。有$sourcePaths
-es,自动加载器会在其中查找所有 .php 文件,并从文件中收集类、接口。然后它存储在一个关联数组中$classes[class name] => absoule path
。稍后,当自动加载发生时,它会查看该类是否在数组中,如果不是,则该类不存在。到目前为止还可以。但是这里是命名空间。让我们看看命名空间Doctrine\ORM\Query;
和类Parameter { .... }
案例。首先我简单地处理它,因为它是 Doctrine\ORM\Query\Parameter ... 所以命名空间+类名。但后来new Query\Parameter
还是找不到这个。在命名空间中查找类的正确算法是什么?
收集的类:
foreach ($sourcePaths as $dir)
{
foreach (new DirectoryIterator($dir) as $fileinfo)
{
if (substr($fileinfo->getFilename(), -4) == '.php')
{
$absPath = str_replace('\\', '/', $dir.'/'.$fileinfo->getFilename());
foreach (getPhpClasses($absPath) as $item)
{
$autoloadClassPaths[$item] = $absPath;
}
}
}
}
此函数从 php 代码中获取内容:
function getPhpClasses ($filename)
{
$output = array();
$namespace = '';
$tokens = token_get_all(file_get_contents($filename));
for ($i = 2; $i < sizeof($tokens); $i++)
{
if (($tokens[$i - 2][0] == T_NAMESPACE) && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING)
{
$j = 0;
do
{
$namespace .= $tokens[$i + $j][1];
$j++;
} while ($tokens[$i + $j] != ';');
$namespace .= '\\';
}
if (($tokens[$i - 2][0] == T_CLASS || $tokens[$i - 2][0] == T_INTERFACE) && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING)
{
$output[] = $namespace.$tokens[$i][1];
}
}
return $output;
}