这是我的Web结构,
index.php
'core/model/'
'core/helper/'
'core/ext/'
我在model
文件夹下有这些类文件,
MyClass.php
MyClass2.php
classfour.php
我想通过自动加载类自动加载它们,
define ('WEBSITE_DOCROOT', str_replace('\', '/', dirname(__FILE__)).'/');
function autoloadMultipleDirectory($class_name)
{
// List all the class directories in the array.
$main_directories = array(
'core/model/',
'core/helper/',
'core/ext/'
);
$sub_directories = array();
$parts = explode('\', $class_name);
$file_name = end($parts).'.php';
foreach($main_directories as $path_directory)
{
$iterator = new RecursiveIteratorIterator
(
new RecursiveDirectoryIterator(WEBSITE_DOCROOT.$path_directory), // Must use absolute path to get the files when ajax is used.
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $fileObject)
{
if ($fileObject->isDir())
{
$sub_directories[] = preg_replace('~.*?(?=core|local)~i', '', str_replace('\', '/', $fileObject->getPathname())) .'/';
}
}
}
// Mearge the main dirs with any sub dirs in them.
$merged_directories = array_merge($main_directories,$sub_directories);
print_r($merged_directories);
// Loop the merge array and include the classes in them.
foreach($merged_directories as $path_directory)
{
if(file_exists(WEBSITE_DOCROOT.$path_directory.$file_name))
{
include WEBSITE_DOCROOT.$path_directory.$file_name;
}
}
}
实现
spl_autoload_register('autoloadMultipleDirectory');
//define classone
class classone { }
//define classtwo
class classtwo { }
//define classthree
class classthree { }
print_r(get_declared_classes());
结果
Array
(
[0] => stdClass
...
[131] => tidyNode
[132] => classone
[133] => classtwo
[134] => classthree
)
但classfour
,MyClass
&MyClass2
不在列表中。
而对于,
$test = new MyClass();
$test2 = new MyClass2();
$test3 = new classfour();
将导致重复取决于我实例化了多少个类,
Array
(
[0] => core/model/
[1] => core/helper/
[2] => core/ext/
)
Array
(
[0] => core/model/
[1] => core/helper/
[2] => core/ext/
)
Array
(
[0] => core/model/
[1] => core/helper/
[2] => core/ext/
)
在我的实时服务器中,我得到了更奇怪的结果,
Array
(
[0] => core/model/
[1] => core/helper/
[2] => core/ext/
[3] => core/model/./ (duplicated)
[4] => core/model/../ (duplicated)
[5] => core/helper/./ (duplicated)
[6] => core/helper/../ (duplicated)
[7] => core/ext/./ (duplicated)
[8] => core/ext/../ (duplicated)
)
知道为什么以及如何解决它吗?
编辑:
如果我手动包含类,
include 'core/model/MyClass.php';
include 'core/model/MyClass2.php';
include 'core/model/classfour.php';
print_r(get_declared_classes());
$test = new MyClass();
$test2 = new MyClass2();
$test3 = new classfour();
我得到正确的答案,
Array
(
[0] => stdClass
...
[131] => tidyNode
[132] => classone
[133] => classtwo
[134] => classthree
[135] => MyClass
[136] => MyClass2
[137] => classfour
)
classfour
、MyClass
和MyClass2
现在都在列表中。
怎么来了??
您在这里解决了一些不同的问题。
自动加载与手动加载...
注册自动加载函数时,只要实例化对象,就会调用该函数。在此函数中,您应该检查正在实例化的类并以某种方式提供相应的类定义,通常是通过包含相关的 php 文件。这很方便,因为您可以确保仅以 JIT 方式实际声明需要实例化的类。另请注意,如果您的类扩展了另一个类,则还将为父类调用 autoload 函数,以此类推,以此类推,以递归方式为所有祖先类调用。
这与手动包含类文件不同。一旦包含myfooclass.php
文件,就会声明相关的类,无论它以后是否被实例化。
。和get_declared_classes()
get_declared_classes()
执行其名称所暗示的:它返回一个数组,其中包含在调用它时已声明的所有类。换句话说,如果从脚本中的多个位置调用它,则可能会得到不同的结果,具体取决于当时声明的类。
复制
我可以在实时服务器的结果中看到重复的路径,但不能看到您描述它们的方式。例如,core/model/./
是core/model/
的副本,因为前者解析为后者。但是core/model/../
不是重复的,因为它解析为core/
(它只会在以后通过core/helper/../
和core/ext/../
复制)。
一个好的做法是使用realpath()
来解决此类问题(以及其他一些问题),并为您提供绝对的、规范的、现有的路径。此外,您应该在将路径插入$sub_directories
之前检查路径是否已存在:
if ($fileObject->isDir())
{
$pathname=$fileObject->getPathname();
$slashed=str_replace('\', '/', $pathname);
$filtered=preg_replace('~.*?(?=core|local)~i', '', $slashed) .'/';
$canonical=realpath($filtered);
if(!in_array($canonical,$sub_directories)) $sub_directories[] = $canonical;
}
。或者在使用前执行array_unique()
:
$merged_directories = array_merge($main_directories,$sub_directories);
$merged_directories = array_unique($merged_directories);
print_r($merged_directories);
当然,这些解决方案是被动的,不需要您更改应用程序逻辑。
另一个故障保护是使用 include_once
而不是 include
,以免意外包含同一个文件两次。
哦,还有最后一点:找到有问题的文件后,无需继续搜索。只需break
循环:
if(file_exists($path_directory.$file_name))
{
include_once $path_directory.$file_name;
break; // <-- no point going on
}