如何在 PHP 中为多个目录使用 spl_autoload_register?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20681689/
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
How to use spl_autoload_register for multiple diectories in PHP?
提问by Radical_Activity
I'm actually trying to create a MVC framework for my own, however I'm having troubles with the Autoload. It's not a problem actually, but I'd like to ask the gurus, how are they using the spl_autoload_registerfunction when there are different directories.
我实际上是在尝试为我自己创建一个 MVC 框架,但是我在自动加载方面遇到了麻烦。其实这不是问题,但我想问一下大师,spl_autoload_register当存在不同的目录时,他们如何使用该功能。
Lets say we have the following directories:
假设我们有以下目录:
Controllers
Libs
Models
Each folder contains different classes, like:
每个文件夹包含不同的类,例如:
Controllers:
Main.php
File.php
About.php
Libs:
Main.php
Front_controller.php
Models:
Index.php
File.php
Login.php
You can notice that some file names might be found with the same name in different directories. Okay, so this is what I've tried so far:
您可以注意到,在不同的目录中可能会发现某些文件名具有相同的名称。好的,这是我迄今为止尝试过的:
spl_autoload_register(function ($class) {
$pathContorllers = 'Controllers/' . $class . '.php';
$pathLibs = 'Libs/' . $class . '.php';
$pathModels = 'Models/' . $class . '.php';
if (file_exists($pathContorllers)) {
require_once $pathContorllers;
} elseif (file_exists($pathLibs)) {
require_once $pathLibs;
} elseif (file_exists($pathModels )) {
require_once $pathModels ;
}
});
It is working well, however I'm sure that there is another way to make everything simpler. Can anyone suggest me how can I make this code better or simpler / what are gurus using in this situation?
它运行良好,但是我确信还有另一种方法可以使一切变得更简单。任何人都可以建议我如何使此代码更好或更简单/在这种情况下大师使用什么?
回答by Crackertastic
For the purpose of keeping individuals who may come across this answer from obtaining out-of-date information I have updated it in regards to the latest PSR autoloading standards. The original answer has been maintained for historical purposes and for those who are only interested in the PSR-0 autoloader.
为了防止可能遇到此答案的个人获取过时的信息,我已根据最新的 PSR 自动加载标准对其进行了更新。出于历史目的以及仅对 PSR-0 自动加载器感兴趣的人,保留了原始答案。
Updated Answer
更新答案
The PHP-FIGhas officially deprecated the PSR-0standard in favor of the alternative autoloader, PSR-4. Although the two are similar in some aspects they are also very different in others. (E.g.: the handling of underscores in class names.)
的PHP-图已经正式弃用的PSR-0赞成替代自动加载机的标准,PSR-4 。尽管两者在某些方面相似,但在其他方面也有很大不同。(例如:类名中下划线的处理。)
You may be thinking to yourself -- "I use PSR-0 now and it works fine."The truth of the matter is that PSR-0 will still work fine for certain projects. This is especially true when backwards compatibility with a package that doesn't use namespaces is concerned. PSR-0 is still a decent autoloading principle, but it has its own shortcomings.
您可能会想—— “我现在使用 PSR-0,它运行良好。” 事情的真相是,PSR-0 对于某些项目仍然可以正常工作。当涉及与不使用名称空间的包的向后兼容性时,尤其如此。PSR-0 仍然是一个不错的自动加载原理,但它有其自身的缺点。
Of course, if there is one thing that is a constant with programming, it is that code eventually changes and programming techniques continue to evolve. You can do yourself a favor today by preparing yourself for tomorrow. Therefore, if you are just starting a project or are trying to port a project to a newer version of PHP that can use namespaces, you should seriously consider using the PSR-4 autoloader.
当然,如果有一件事是编程不变的,那就是代码最终会发生变化,而编程技术也在不断发展。你可以通过为明天做好准备来帮助自己。因此,如果您刚刚开始一个项目或试图将项目移植到可以使用命名空间的较新版本的 PHP,您应该认真考虑使用 PSR-4 自动加载器。
It is also worth noting that if you are developing a project that does not use namespaces then PSR-4 does not apply to you. In this case PSR-0 or your own custom autoloader applies.
还值得注意的是,如果您正在开发一个不使用命名空间的项目,那么 PSR-4 不适用于您。在这种情况下,PSR-0 或您自己的自定义自动加载器适用。
Original Answer
原答案
If you want to go with namespaces in your classes, then the PSR-0route is a pretty good way to autoload. Basically your namespace represents you directory structure and classes can be loaded based on a convention.
如果你想在你的类中使用命名空间,那么PSR-0路由是一个很好的自动加载方式。基本上,您的命名空间代表您的目录结构,并且可以根据约定加载类。
If the PSR-0 method doesn't meet all your needs (or doesn't play nice with existing code) you can still add more functions with spl_autoload_registerand PHP will go through them one by one in an attempt to load classes.
如果 PSR-0 方法不能满足您的所有需求(或者不能很好地处理现有代码),您仍然可以添加更多函数,spl_autoload_registerPHP 将一一检查它们以尝试加载类。
Example usage:
用法示例:
First thing is first, if you aren't familiar with namespaces in PHPthen you will benefit from checking out the PHP manual on the subject. They can be a bit confusing at first, but their benefits are worth the initial confusion.
首先,如果您不熟悉PHP 中的命名空间,那么您将从查看有关该主题的 PHP 手册中受益。一开始它们可能有点混乱,但它们的好处值得一开始的混淆。
So I said that PSR-0 works by associating your namespaces with your directory structure. Let's use your directories for an example. You have in your root folder (wherever it may be) the following:
所以我说 PSR-0 的工作原理是将您的命名空间与您的目录结构相关联。让我们以您的目录为例。您的根文件夹(无论在哪里)中有以下内容:
Project directory: <- Let's call this directory "MyProject"
Controllers:
Main.php
File.php
About.php
Libs:
Main.php
Front_controller.php
Models:
Index.php
File.php
Login.php
index.php <- Let's say this is your entry point file, this is where you will be autoloading stuff from.
Now let's take a look at your controller Main.php. Two things to keep in mind is that the class name needs to be the name of the file and the namespace for that class is the directory path to that file. So Main.phpshould look something like this:
现在让我们看看你的控制器Main.php。要记住的两件事是类名必须是文件名,而该类的命名空间是该文件的目录路径。所以Main.php应该看起来像这样:
<?php
namespace MyProject\Controllers;
class Main {
//Field vars, contructor, methods, etc. all go here.
}
?>
You would do the same thing for your your Loginmodel
你会为你的Login模型做同样的事情
<?php
namespace MyProject\Models;
class Login {
//Field vars, contructor, methods, etc. all go here.
}
?>
Now in your index.phpfile (out in the root directory - MyProject) you would make your call to the spl_autoload_registerand give it the PSR-0 autoloader.
现在在您的index.php文件中(在根目录中 - MyProject),您将调用spl_autoload_register并为其提供 PSR-0 自动加载器。
spl_autoload_register( function ($className) {
$className = ltrim($className, '\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
});
//Now you can make your call to your objects without a bunch of include/require statements
$main = new \MyProject\Controllers\Main(); //Instantiates your 'Main' controller
$login = new \MyProject\Models\Login(); //Instantiates your 'Login' model
Hopefully that helps make better sense of it, and again, if you don't want to use namespaces you can always just keep adding closures into the SPL autoload stack. You can have 10 different autoloaders in there if you want and PHP will go through them one by one (in the order you defined them) using each function to try and load a class. However, a couple convention based autoloaders is a bit cleaner and more of a preferred method. Also keep in mind that the autoloader translates both namespace separators \and underscores _as a directory separator. So your Front_controller.phpwould not autoload as you would expect.
希望这有助于更好地理解它,同样,如果您不想使用名称空间,您可以随时将闭包添加到 SPL 自动加载堆栈中。如果你愿意,你可以在那里有 10 个不同的自动加载器,PHP 将使用每个函数一个一个地(按照你定义它们的顺序)尝试加载一个类。然而,几个基于约定的自动加载器更简洁,更像是一种首选方法。还要记住,自动加载器将命名空间分隔符\和下划线都转换_为目录分隔符。所以你Front_controller.php不会像你期望的那样自动加载。
回答by user3563950
The code below will help. But I'll advice you check on Namespaces.
下面的代码会有所帮助。但我建议你检查命名空间。
spl_autoload_register ( function ($class) {
$sources = array("Controllers/$class.php", "Lib/$class.php ", "Models/$class.php " );
foreach ($sources as $source) {
if (file_exists($source)) {
require_once $source;
}
}
});

