高效的 PHP 自动加载和命名策略
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/791899/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Efficient PHP auto-loading and naming strategies
提问by zombat
Like most web developers these days, I'm thoroughly enjoying the benefits of solid MVC architecture for web apps and sites. When doing MVC with PHP, autoloading obviously comes in extremely handy.
像如今的大多数 Web 开发人员一样,我非常享受适用于 Web 应用程序和站点的可靠 MVC 架构的好处。使用 PHP 进行 MVC 时,自动加载显然非常方便。
I've become a fan of spl_autoload_registerover simply defining a single __autoload()function, as this is obviously more flexible if you are incorporating different base modules that each use their own autoloading. However, I've never felt great about the loading functions that I write. They involve a lot of string checking and directory scanning in order to look for possible classes to load.
我已经变得spl_autoload_register过于简单地定义单个__autoload()函数的粉丝,因为如果您合并不同的基本模块,每个模块都使用自己的自动加载,这显然更灵活。但是,我从来没有对我编写的加载函数感到满意。它们涉及大量的字符串检查和目录扫描,以寻找可能加载的类。
For example, let's say I have an app that has a base path defined as PATH_APP, and a simple structure with directories named models, viewsand controllers. I often employ a naming structure whereby files are named IndexView.phpand IndexController.phpinside the appropriate directory, and models generally have no particular scheme by default. I might have a loader function for this structure like this that gets registered with 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;
}
If it's not found after that, I might have another function to scan sub-directories in the models directory. However, all the if/else-ing, string checking and directory scanning seems inefficient to me, and I'd like to improve it.
如果之后没有找到,我可能还有另一个功能来扫描模型目录中的子目录。然而,所有的 if/else-ing、字符串检查和目录扫描对我来说似乎效率低下,我想改进它。
I'm very curious what file naming and autoloading strategies other developers might employ. I'm looking specifically for good techniques to employ for efficient autoloading, and not alternatives to autoloading.
我很好奇其他开发人员可能采用的文件命名和自动加载策略。我正在专门寻找用于高效自动加载的好技术,而不是自动加载的替代方法。
采纳答案by Mike Boers
This is what I have been using in all of my projects (lifted straight from the source of the last one):
这是我在所有项目中一直使用的内容(直接从上一个项目的来源中提取):
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;
}
}
}
}
If I look for SomeClass_SeperatedWith_Underscores it will look for SomeClass_SeperatedWith_Underscores.php followed by SomeClass/SeperatedWith/Underscores.php rooted at each directory in the current include path.
如果我查找 SomeClass_SeperatedWith_Underscores 它将查找 SomeClass_SeperatedWith_Underscores.php 后跟 SomeClass/SeperatedWith/Underscores.php 根植于当前包含路径中的每个目录。
EDIT:I just wanted to put out there that I use this for efficiency in development, and not necessarily processing time. If you have PEAR on your path then with this you can just use the classes and don't have to include them when you need them.
编辑:我只是想说明我使用它来提高开发效率,而不一定是处理时间。如果您的路径上有 PEAR,那么您可以使用这些类,而不必在需要时包含它们。
I tend to keep my classes in a hierarchy of directories, with underscores breaking up namespaces... This code lets me keep the file structure nice and tidy if I want, or to inject a quick class file without nested directories if I want (for adding a single class or two to a library that it is defendant on, but not part of the project I am currently working on.)
我倾向于将我的类保持在目录层次结构中,下划线打破命名空间......如果我愿意,这段代码让我可以保持文件结构整洁,或者如果我愿意,可以注入一个没有嵌套目录的快速类文件(对于将一个或两个类添加到它是被告的库中,但不是我目前正在进行的项目的一部分。)
回答by grossvogel
I landed on this solution:
我找到了这个解决方案:
I created a single script that traverses my class library folder (which contains subfolders for separate modules / systems), and parses the file contents looking for class definitions. If it finds a class definition in a php file (pretty simple regex pattern), it creates a symlink:
我创建了一个脚本,它遍历我的类库文件夹(其中包含用于单独模块/系统的子文件夹),并解析文件内容以查找类定义。如果它在 php 文件中找到一个类定义(非常简单的正则表达式模式),它会创建一个符号链接:
class_name.php -> actual/source/file.php
This lets me use a single, simple autoload function that needs only the class name and the path to the main symlink folder, and doesn't have to do any path/string manipulation.
这让我可以使用一个简单的自动加载函数,它只需要类名和主符号链接文件夹的路径,而不必进行任何路径/字符串操作。
The best part is that I can rearrange my source code completely or add a new subsystem and just run the link generating script to have everything autoloaded.
最好的部分是我可以完全重新排列我的源代码或添加一个新的子系统,只需运行链接生成脚本即可自动加载所有内容。
回答by jmucchiello
If you want efficiency then you shouldn't be using the autoload feature at all. The autoload feature is for being lazy. You should be providing an explicit path to your include files when you include them. If your autoload function can find these files then you could code to find them explicitly. When you are working on the view part of the code and about to load a new view class, by letting the autoload function handle it, it first assumes your class is a model class? That's inefficient. Instead your code should just be:
如果您想要效率,那么您根本不应该使用自动加载功能。自动加载功能是为了偷懒。当您包含它们时,您应该提供包含文件的显式路径。如果您的自动加载功能可以找到这些文件,那么您可以编写代码以明确地找到它们。当您处理代码的视图部分并准备加载新的视图类时,通过让自动加载函数处理它,它首先假定您的类是模型类?那是低效的。相反,您的代码应该是:
include_once $this->views_path . $class . '.php';
If you need multiple "view" paths, make a function that loads views:
如果您需要多个“视图”路径,请创建一个加载视图的函数:
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 ....
}
In any case, at the point where the include occurs, you have the greatest/most accurate information about the class you want to load. Using that information to load the class fully is the only efficient class loading strategy. Yes, you may end up with more class variables or (heaven forbid) some global variables. But that is a better tradeoff than just being lazy and scanning parts of the file system for your class.
在任何情况下,在包含发生的地方,您都有关于要加载的类的最大/最准确的信息。使用该信息完全加载类是唯一有效的类加载策略。是的,你最终可能会得到更多的类变量或(天堂禁止)一些全局变量。但这比只是懒惰并为您的班级扫描文件系统的一部分更好。

