php 从不同文件夹自动加载类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5280347/
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
Autoload classes from different folders
提问by laukok
This is how I autoload all the classes in my controllers
folder,
这就是我自动加载controllers
文件夹中所有类的方式,
# auto load controller classes
function __autoload($class_name)
{
$filename = 'class_'.strtolower($class_name).'.php';
$file = AP_SITE.'controllers/'.$filename;
if (file_exists($file) == false)
{
return false;
}
include ($file);
}
But I have classes in models
folder as well and I want to autoload them too - what should I do? Should I duplicate the autoload above and just change the path to models/
(but isn't this repetitive??)?
但是我在models
文件夹中也有类,我也想自动加载它们 - 我该怎么办?我应该复制上面的自动加载并将路径更改为models/
(但这不是重复的吗??)?
Thanks.
谢谢。
EDIT:
编辑:
these are my classes file names in the controller folder:
这些是我在控制器文件夹中的类文件名:
class_controller_base.php
class_factory.php
etc
these are my classes file names in the model folder:
这些是我在模型文件夹中的类文件名:
class_model_page.php
class_model_parent.php
etc
this is how I name my controller classes class usually (I use underscores and lowcaps),
这就是我通常命名控制器类的方式(我使用下划线和低大写字母),
class controller_base
{
...
}
class controller_factory
{
...
}
this is how I name my model classes class usually (I use underscores and lowcaps),
这就是我通常命名模型类的方式(我使用下划线和低大写字母),
class model_page
{
...
}
class model_parent
{
...
}
采纳答案by alex
You should name your classes so the underscore (_
) translates to the directory separator (/
). A few PHP frameworks do this, such as Zend and Kohana.
您应该命名您的类,以便下划线 ( _
) 转换为目录分隔符 ( /
)。一些 PHP 框架可以做到这一点,例如 Zend 和 Kohana。
So, you name your class Model_Article
and place the file in classes/model/article.php
and then your autoload does...
因此,您命名您的类Model_Article
并将文件放入其中classes/model/article.php
,然后您的自动加载...
function __autoload($class_name)
{
$filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)).'.php';
$file = AP_SITE.$filename;
if ( ! file_exists($file))
{
return FALSE;
}
include $file;
}
Also note you can use spl_autoload_register()
to make any function an autoloading function. It is also more flexible, allowing you to define multiple autoload type functions.
另请注意,您可以使用spl_autoload_register()
使任何函数成为自动加载函数。它也更灵活,允许您定义多个自动加载类型的函数。
If there must be multiple autoload functions, spl_autoload_register() allows for this. It effectively creates a queue of autoload functions, and runs through each of them in the order they are defined. By contrast, __autoload() may only be defined once.
如果必须有多个自动加载函数,spl_autoload_register() 允许这样做。它有效地创建了一个自动加载函数队列,并按照定义的顺序遍历每个函数。相比之下, __autoload() 只能定义一次。
Edit
编辑
Note :__autoloadhas been DEPRECATED as of PHP 7.2.0. Relying on this feature is highly discouraged. Please refer to PHP documentation for more details. http://php.net/manual/en/function.autoload.php
注意:从 PHP 7.2.0 起,__ autoload已被弃用。非常不鼓励依赖此功能。有关更多详细信息,请参阅 PHP 文档。http://php.net/manual/en/function.autoload.php
回答by br3nt
I see you are using controller_*****
and model_*****
as a class naming convention.
我看到您正在使用controller_*****
和model_*****
作为类命名约定。
I read a fantastic article, which suggests an alternative naming convention using php's namespace
.
我读了一篇很棒的文章,其中建议使用 php 的namespace
.
I love this solution because it doesn't matter where I put my classes. The __autoload
will find it no matter where it is in my file structure. It also allows me to call my classes whatever I want. I don't need a class naming convention for my code to work.
我喜欢这个解决方案,因为我把课放在哪里并不重要。该__autoload
会发现它,不管它在哪里我的文件结构。它还允许我随意调用我的课程。我的代码不需要类命名约定即可工作。
You can, for example, set up your folder structure like:
例如,您可以将文件夹结构设置为:
- application/
- controllers/
- Base.php
- Factory.php
- models/
- Page.php
- Parent.php
- controllers/
- 应用/
- 控制器/
- 基础文件
- 工厂.php
- 楷模/
- 页面.php
- 父.php
- 控制器/
Your classes can be set up like this:
您的课程可以这样设置:
<?php
namespace application\controllers;
class Base {...}
and:
和:
<?php
namespace application\models;
class Page {...}
The autoloader could look like this (or see 'a note on autoloading' at the end):
自动加载器可能看起来像这样(或者在最后看到“关于自动加载的说明”):
function __autoload($className) {
$file = $className . '.php';
if(file_exists($file)) {
require_once $file;
}
}
Then... you can call classes in three ways:
然后……您可以通过三种方式调用类:
$controller = new application\controllers\Base();
$model = new application\models\Page();
or,
或者,
<?php
use application\controllers as Controller;
use application\models as Model;
...
$controller = new Controller\Base();
$model = new Model\Page();
or,
或者,
<?php
use application\controllers\Base;
use application\models\Page;
...
$controller = new Base();
$model = new Page();
EDIT - a note on autoloading:
编辑 - 关于自动加载的说明:
My main auto loader looks like this:
我的主要自动装载机看起来像这样:
// autoload classes based on a 1:1 mapping from namespace to directory structure.
spl_autoload_register(function ($className) {
# Usually I would just concatenate directly to $file variable below
# this is just for easy viewing on Stack Overflow)
$ds = DIRECTORY_SEPARATOR;
$dir = __DIR__;
// replace namespace separator with directory separator (prolly not required)
$className = str_replace('\', $ds, $className);
// get full name of file containing the required class
$file = "{$dir}{$ds}{$className}.php";
// get file if it is readable
if (is_readable($file)) require_once $file;
});
This autoloader is a direct 1:1 mapping of class name to directory structure; the namespace is the directory path and the class name is the file name. So the class application\controllers\Base()
defined above would load the file www/application/controllers/Base.php
.
这个自动加载器是类名到目录结构的直接 1:1 映射;命名空间是目录路径,类名是文件名。所以application\controllers\Base()
上面定义的类将加载文件www/application/controllers/Base.php
。
I put the autoloader into a file, bootstrap.php, which is in my root directory. This can either be included directly, or php.ini can be modified to auto_prepend_fileso that it is included automatically on every request.
我将自动加载器放入一个文件 bootstrap.php 中,该文件位于我的根目录中。这可以直接包含,也可以将 php.ini 修改为auto_prepend_file以便在每个请求中自动包含它。
By using spl_autoload_registeryou can register multiple autoload functions to load the class files any which way you want. Ie, you could put some or all of your classes in one directory, or you could put some or all of your namespaced classes in the one file. Very flexible :)
通过使用spl_autoload_register,您可以注册多个自动加载函数,以您想要的任何方式加载类文件。即,您可以将部分或全部类放在一个目录中,也可以将部分或全部命名空间类放在一个文件中。非常灵活:)
回答by DerDu
I have to mention something about "good" autoload scripts and code structure, so read the following CAREFULLY
我不得不提一下“好的”自动加载脚本和代码结构,所以请仔细阅读以下内容
Keep in Mind:
记住:
- Classname ===Filename
- Only ONE class per file
- 类名===文件名
- 每个文件只有一个类
e.g: Example.php contains
例如:Example.php 包含
class Example {}
- Namespace ===Directory structure
- 命名空间===目录结构
e.g: /Path1/Path2/Example.php matches
例如:/Path1/Path2/Example.php 匹配
namespace Path1\Path2;
class Example {}
- There SHOULD be a Root-Namespace to avoid collisions
- 应该有一个根命名空间以避免冲突
e.g: /Path1/Path2/Example.php with root:
例如:/Path1/Path2/Example.php 与根:
namespace APP\Path1\Path2;
class Example {}
- NEVER use manually defined path or directory lists, just point the loader to the top most directory
- Keep the loader AS FAST AS POSSIBLE (because including a file is expensive enough)
- 切勿使用手动定义的路径或目录列表,只需将加载程序指向最顶层的目录
- 保持加载器尽可能快(因为包含一个文件足够昂贵)
With this in mind, i produced the following script:
考虑到这一点,我制作了以下脚本:
function Loader( $Class ) {
// Cut Root-Namespace
$Class = str_replace( __NAMESPACE__.'\', '', $Class );
// Correct DIRECTORY_SEPARATOR
$Class = str_replace( array( '\', '/' ), DIRECTORY_SEPARATOR, __DIR__.DIRECTORY_SEPARATOR.$Class.'.php' );
// Get file real path
if( false === ( $Class = realpath( $Class ) ) ) {
// File not found
return false;
} else {
require_once( $Class );
return true;
}
}
Where to place it..
放在哪里。。
- /Loader.php <-- there goes the loader
- /Controller/... <-- put ur stuff here
- /Model/... <-- or here, etc
- /...
- /Loader.php <-- 加载器
- /Controller/... <-- 把你的东西放在这里
- /Model/... <-- 或这里等
- /...
Remeber:
记住:
- if you use a root namespace, the loader has to be in this namespace too
- you may prefix $Class to match your needs (controller_base {} -> class_controller_base.php)
- you may change __DIR__ to an absolute path containing your class files (e.g. "/var/www/classes")
- if you don't use namespaces, all files has to be in the same directory together with the loader (bad!)
- 如果你使用根命名空间,加载器也必须在这个命名空间中
- 您可以为 $Class 添加前缀以满足您的需求(controller_base {} -> class_controller_base.php)
- 您可以将 __DIR__ 更改为包含类文件的绝对路径(例如“/var/www/classes”)
- 如果您不使用命名空间,则所有文件都必须与加载程序位于同一目录中(糟糕!)
Happy coding ;-)
快乐编码;-)
A little review at other answers: THIS IS JUST MY PERSONAL OPINION - NO OFFENSE INTENDED!
对其他答案的一点评论: 这只是我的个人意见 - 无意冒犯!
https://stackoverflow.com/a/5280353/626731@alex good solution, but don't make you class names pay for bad file structures ;-) this is job for namespaces
https://stackoverflow.com/a/5280353/626731@alex 很好的解决方案,但不要让类名为糟糕的文件结构付出代价;-) 这是命名空间的工作
https://stackoverflow.com/a/5280510/626731@Mark-Eirich it works, but its pretty nasty/ugly/slow/stiff[..] style to do it this way..
https://stackoverflow.com/a/5280510/626731@Mark-Eirich 它有效,但它的风格非常讨厌/丑陋/slow/stiff[..] 以这种方式做到这一点..
https://stackoverflow.com/a/5284095/626731@tealou for his problem to be solved this is the most clear approach so far :-) ..
https://stackoverflow.com/a/5284095/626731@tealou 要解决他的问题,这是迄今为止最清晰的方法:-) ..
https://stackoverflow.com/a/9628060/626731@br3nt this reflects my point of view, but please(!) .. dont use strtr!! .. which brings me to:
https://stackoverflow.com/a/9628060/626731@br3nt 这反映了我的观点,但是请(!)..不要使用 strtr !..这让我想到:
https://stackoverflow.com/a/11866307/626731@Iscariot .. to you, a little "you-know-bullshit-benchmark:
https://stackoverflow.com/a/11866307/626731@Iscariot .. 对你来说,有点“你知道的废话基准:
Time sprintf preg_replace strtr str_replace v1 str_replace v2
08:00:00 AM 1.1334 2.0955 48.1423 1.2109 1.4819
08:40:00 AM 1.0436 2.0326 64.3492 1.7948 2.2337
11:30:00 AM 1.1841 2.5524 62.0114 1.5931 1.9200
02:00:00 PM 0.9783 2.4832 52.6339 1.3966 1.4845
03:00:00 PM 1.0463 2.6164 52.7829 1.1828 1.4981
Average 1.0771 2.3560 55.9839 1.4357 1.7237
Method Times Slower (than sprintf)
preg_replace 2.19
strtr 51.97
str_replace v1 1.33
str_replace v2 1.6
Source: http://www.simplemachines.org/community/index.php?topic=175031.0
来源:http: //www.simplemachines.org/community/index.php?topic= 175031.0
Questions?.. (But he is in fact right about full path including)
问题?..(但他实际上对完整路径是正确的,包括)
https://stackoverflow.com/a/12548558/626731@Sunil-Kartikey https://stackoverflow.com/a/17286804/626731@jurrien
https://stackoverflow.com/a/12548558/626731@Sunil-Kartikey https://stackoverflow.com/a/17286804/626731@jurrien
NEVER loop in time critical environment! Don't search for files on os! - SLOW
切勿在时间关键的环境中循环!不要在 os 上搜索文件!- 减缓
https://stackoverflow.com/a/21221590/626731@sagits .. much better than Marks ;-)
https://stackoverflow.com/a/21221590/626731@sagits .. 比 Marks 好得多;-)
回答by Sunil Kartikey
function autoload($className)
{
//list comma separated directory name
$directory = array('', 'classes/', 'model/', 'controller/');
//list of comma separated file format
$fileFormat = array('%s.php', '%s.class.php');
foreach ($directory as $current_dir)
{
foreach ($fileFormat as $current_format)
{
$path = $current_dir.sprintf($current_format, $className);
if (file_exists($path))
{
include $path;
return ;
}
}
}
}
spl_autoload_register('autoload');
回答by laukok
Here is my solution,
这是我的解决方案,
/**
* autoload classes
*
*@var $directory_name
*
*@param string $directory_name
*
*@func __construct
*@func autoload
*
*@return string
*/
class autoloader
{
private $directory_name;
public function __construct($directory_name)
{
$this->directory_name = $directory_name;
}
public function autoload($class_name)
{
$file_name = 'class_'.strtolower($class_name).'.php';
$file = AP_SITE.$this->directory_name.'/'.$file_name;
if (file_exists($file) == false)
{
return false;
}
include ($file);
}
}
# nullify any existing autoloads
spl_autoload_register(null, false);
# instantiate the autoloader object
$classes_1 = new autoloader('controllers');
$classes_2 = new autoloader('models');
# register the loader functions
spl_autoload_register(array($classes_1, 'autoload'));
spl_autoload_register(array($classes_2, 'autoload'));
I'm not sure whether it is the best solution or not but it seems to work perfectly...
我不确定它是否是最好的解决方案,但它似乎工作得很好......
What do you think??
你觉得怎么样??
回答by sagits
My version of @Mark Eirich answer:
我的@Mark Eirich 版本回答:
function myload($class) {
$controllerDir = '/controller/';
$modelDir = '/model/';
if (strpos($class, 'controller') !== false) {
$myclass = $controllerDir . $class . '.php';
} else {
$myclass = $modelDir . $class . '.inc.php';
}
if (!is_file($myclass)) return false;
require_once ($myclass);
}
spl_autoload_register("myload");
In my case only controller class have the keyword in their name, adapt it for your needs.
在我的情况下,只有控制器类的名称中有关键字,请根据您的需要进行调整。
回答by Hymanson A. Mangallay
Simpliest answer I can give you without writing down those complex codes and even without using the namespace (if this confuses you)
我可以给你最简单的答案,而无需写下那些复杂的代码,甚至无需使用命名空间(如果这让你感到困惑)
Sample Code. Works 100%.
示例代码。工作 100%。
function __autoload($class_name){
$file = ABSPATH . 'app/models/' . $class_name . '.php';
if(file_exists($file)){
include $file;
}else{
$file = ABSPATH . 'app/views/' . $class_name . '.php';
if(file_exists($file)){
include $file;
}else{
$file = ABSPATH . 'app/controllers/' . $class_name . '.php';
include $file;
}
}
I guess the logic is explainable itself. Cheers mate! Hope this helps :)
我想这个逻辑本身是可以解释的。队友的欢呼声!希望这可以帮助 :)
回答by Mark Eirich
Here's what I'd do:
这是我要做的:
function __autoload($class_name) {
$class_name = strtolower($class_name);
$filename = 'class_'.$class_name.'.php';
if (substr($class_name, 0, 5) === 'model') {
$file = AP_SITE.'models/'.$filename;
} else $file = AP_SITE.'controllers/'.$filename;
if (!is_file($file)) return false;
include $file;
}
As long you name your files consistently, like class_controller_*.php
and class_model_*.php
, this should work fine.
只要您始终如一地命名您的文件,例如class_controller_*.php
和class_model_*.php
,这应该可以正常工作。
回答by Case
Everyone is is coping and pasting things from code they got off the internet (With the exception of the selected answer). They all use String Replace.
每个人都在处理和粘贴他们从互联网上获取的代码中的内容(所选答案除外)。他们都使用字符串替换。
String Replace is 4 times slower than strtr. You should use it instead.
字符串替换比 strtr 慢 4 倍。你应该改用它。
You should also use full paths when including classes with autoloading as it takes less time for the OS to resolve the path.
在包含具有自动加载功能的类时,您还应该使用完整路径,因为操作系统解析路径所需的时间更少。
回答by asi_x
__autoload() function should not be use because it is not encourged. Use spl_autoload(), spl_autoload_register() instead. __autoload() just can load one class but spl_autoload() can get more than 1 classes. And one thing more, in future __autoload() may deprecated. More stuff can be find on http://www.php.net/manual/en/function.spl-autoload.php
__autoload() 函数不应该被使用,因为它不被鼓励。使用 spl_autoload(), spl_autoload_register() 代替。__autoload() 只能加载一个类,而 spl_autoload() 可以加载 1 个以上的类。还有一件事,将来 __autoload() 可能会被弃用。更多内容可以在http://www.php.net/manual/en/function.spl-autoload.php上找到