高效的PHP自动加载和命名策略
和大多数networking开发人员一样,我现在非常享受固体MVC架构的好处。 使用PHP进行MVC时,自动加载显然非常方便。
我已经成为spl_autoload_register
的粉丝,只是简单地定义一个__autoload()
函数,因为如果您将不同的基本模块(每个模块都使用自己的自动加载)合并在一起,这显然更加灵活。 不过,我从来没有感觉到我写的加载函数。 它们涉及大量的string检查和目录扫描,以查找可能的类加载。
例如,假设我有一个基本path定义为PATH_APP
的应用程序,以及一个带有名为models
, views
和controllers
目录的简单结构。 我经常使用一个命名结构,在相应的目录下文件被命名为IndexView.php
和IndexController.php
,默认情况下,模型通常没有特定的scheme。 我可能有这样的结构的加载函数,这是获得注册与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; }
如果在此之后没有find,我可能有另一个function来扫描模型目录中的子目录。 但是,所有的if / else,string检查和目录扫描对我来说似乎是无效的,我想改进它。
我很好奇其他开发者可能使用的文件命名和自动加载策略。 我正在寻找专门用于高效自动加载的好技术,而不是自动加载的替代方法。
这就是我一直在使用的所有项目(从最后一个项目的源头中提取):
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,它位于当前包含path的每个目录中。
编辑:我只是想摆在那里,我用这个在开发效率,而不一定处理时间。 如果你的PEAR在你的道路上,那么你可以使用这些类,而不必在需要的时候包含它们。
我倾向于将我的类放在目录层次结构中,用下划线打破命名空间…如果需要,我可以保持文件结构的整洁,或者如果我想要注入一个没有嵌套目录的快速类文件(用于将一个或两个单独的课程添加到被告所在的图书馆,但不是我目前正在进行的项目的一部分。)
我登陆这个解决scheme:
我创build了一个遍历我的类库文件夹(包含单独模块/系统的子文件夹)的脚本,并分析查找类定义的文件内容。 如果它在php文件中find类定义(非常简单的正则expression式模式),它会创build一个符号链接:
class_name.php -> actual/source/file.php
这使我可以使用一个简单的自动加载函数,只需要类名称和主符号链接文件夹的path,而不必执行任何path/string操作。
最好的部分是我可以完全重新安排我的源代码或添加一个新的子系统,只需运行链接生成脚本,让所有内容自动加载。
如果你想效率,那么你根本不应该使用自动加载function。 自动加载function是为了懒惰。 包含文件时,您应该提供一个明确的包含文件path。 如果您的自动加载function可以find这些文件,那么你可以编码来明确地find它们。 当你在代码的视图部分工作,并且要加载一个新的视图类时,通过让自动加载函数处理它,它首先假设你的类是一个模型类? 这是无效的。 相反,你的代码应该是:
include_once $this->views_path . $class . '.php';
如果您需要多个“查看”path,请创build一个加载视图的函数:
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 .... }
无论如何,在包含发生的地方,您可以获得关于您想要加载的课程的最大/最准确的信息。 使用这些信息来完全加载类是唯一有效的类加载策略。 是的,你可能会得到更多的类variables或(天堂禁止)一些全局variables。 但是,这是一个更好的折衷scheme,而不是仅仅懒惰地扫描文件系统的一部分。