与大多数网络开发人员一样,我非常享受固态MVC架构对网络应用和网站的好处。使用PHP进行MVC时,自动加载显然非常方便。
我只是简单地定义了一个__autoload()
函数而成为了spl_autoload_register
的粉丝,因为如果要合并每个使用自己自动加载的不同基本模块,这显然会更灵活。但是,我从来没有对我写的加载函数感到满意。它们涉及大量字符串检查和目录扫描,以便查找可能要加载的类。
例如,假设我的应用程序具有定义为PATH_APP
的基本路径,以及一个名为models
,views
和controllers
的目录的简单结构。我经常使用命名结构,在适当的目录中将文件命名为IndexView.php
和IndexController.php
,默认情况下模型通常没有特定的方案。我可能有一个像这样的结构的加载器函数,它被注册到spl_autoload_register
:
public function MVCLoader($class)
{
if (file_exists(PATH_APP.'/models/'.$class.'.php')) {
require_once(PATH_APP.'/models/'.$class.'.php');
return true;
}
else if (strpos($class,'View') !== false) {
if (file_exists(PATH_APP.'/views/'.$class.'.php')) {
require_once(PATH_APP.'/views/'.$class.'.php');
return true;
}
}
else if (strpos($class,'Controller') !== false) {
if (file_exists(PATH_APP.'/controllers/'.$class.'.php')) {
require_once(PATH_APP.'/controllers/'.$class.'.php');
return true;
}
}
return false;
}
如果之后没有找到,我可能还有另一个功能来扫描models目录中的子目录。但是,所有if / else-ing,字符串检查和目录扫描对我来说似乎效率低下,我想改进它。
我很好奇其他开发人员可能采用的文件命名和自动加载策略。我正在寻找专门用于高效自动加载的好技术,而不是自动加载的替代方案。
答案 0 :(得分:28)
这是我在所有项目中使用的内容(直接从最后一个项目的源代码中提升):
public static function loadClass($class)
{
$files = array(
$class . '.php',
str_replace('_', '/', $class) . '.php',
);
foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path)
{
foreach ($files as $file)
{
$path = "$base_path/$file";
if (file_exists($path) && is_readable($path))
{
include_once $path;
return;
}
}
}
}
如果我查找SomeClass_SeperatedWith_Underscores,它将查找SomeClass_SeperatedWith_Underscores.php,然后查找以当前包含路径中每个目录为根的SomeClass / SeperatedWith / Underscores.php。
编辑:我只是想把它用于开发效率,而不一定是处理时间。如果您的路径上有PEAR,那么您可以使用这些类,而不必在需要时包含它们。
我倾向于将我的类保存在目录层次结构中,使用下划线分解命名空间...这段代码可以让我保持文件结构的美观和整洁,如果我想要,或者注入一个没有嵌套目录的快速类文件,如果我想要(将一个或两个类添加到它是被告的库中,但不是我目前正在处理的项目的一部分。)
答案 1 :(得分:13)
我找到了这个解决方案:
我创建了一个遍历我的类库文件夹(包含单独模块/系统的子文件夹)的脚本,并解析文件内容以查找类定义。如果它在php文件中找到一个类定义(非常简单的正则表达式模式),它会创建一个符号链接:
class_name.php -> actual/source/file.php
这让我可以使用一个简单的自动加载功能,它只需要类名和主符号链接文件夹的路径,而不必进行任何路径/字符串操作。
最好的部分是我可以完全重新安排我的源代码或添加一个新子系统,然后运行链接生成脚本以使所有内容自动加载。
答案 2 :(得分:8)
如果您想要效率,那么您根本不应该使用自动加载功能。自动加载功能是懒惰的。当您包含文件时,您应该提供包含文件的显式路径。如果您的自动加载功能可以找到这些文件,那么您可以编写代码以明确地找到它们。当您处理代码的视图部分并且即将加载新的视图类时,通过让自动加载功能处理它,它首先假定您的类是模型类?那效率很低。相反,您的代码应该只是:
include_once $this->views_path . $class . '.php';
如果您需要多个“视图”路径,请创建一个加载视图的函数:
public function load_view($class) {
// perhaps there's a mapping here instead....
foreach ($this->views_paths as $path) {
$filename = $path . $class . '.php';
if (file_exists($filename)) {
include_once $filename;
}
}
throw ....
}
在任何情况下,在包含发生的位置,您都可以获得有关要加载的类的最大/最准确的信息。使用该信息完全加载类是唯一有效的类加载策略。是的,你可能会得到更多的类变量或(天堂禁止)一些全局变量。但这是一个更好的权衡,而不仅仅是懒惰并为您的班级扫描部分文件系统。