这是我在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);
}
但我也在models
文件夹中有课程,我也想自动加载它们 - 我该怎么办?我应该复制上面的自动加载,只需将路径更改为models/
(但这不是重复的吗?)?
感谢。
修改
这些是我在控制器文件夹中的类文件名:
class_controller_base.php
class_factory.php
etc
这些是我在模型文件夹中的类文件名:
class_model_page.php
class_model_parent.php
etc
这就是我通常命名控制器类的方法(我使用下划线和低音),
class controller_base
{
...
}
class controller_factory
{
...
}
这就是我通常命名我的模型类的方法(我使用下划线和低位),
class model_page
{
...
}
class model_parent
{
...
}
答案 0 :(得分:59)
我发现您使用controller_*****
和model_*****
作为类命名约定。
我读了一个很棒的article,它建议使用php的namespace
替代命名约定。
我喜欢这个解决方案,因为我把课程放在哪里并不重要。 __autoload
无论在我的文件结构中的哪个位置都会找到它。它还允许我随意调用我的课程。我的代码不需要类命名约定。
例如,您可以设置文件夹结构,如:
您的课程可以这样设置:
<?php
namespace application\controllers;
class Base {...}
和
<?php
namespace application\models;
class Page {...}
自动加载器可能看起来像这样(或者在最后看到“关于自动加载的说明”):
function __autoload($className) {
$file = $className . '.php';
if(file_exists($file)) {
require_once $file;
}
}
然后......您可以通过三种方式调用课程:
$controller = new application\controllers\Base();
$model = new application\models\Page();
,或者
<?php
use application\controllers as Controller;
use application\models as Model;
...
$controller = new Controller\Base();
$model = new Model\Page();
,或者
<?php
use application\controllers\Base;
use application\models\Page;
...
$controller = new Base();
$model = new Page();
编辑 - 关于自动加载的说明:
我的主要自动加载器如下所示:
// 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;
});
此自动加载器是类名到目录结构的直接1:1映射;命名空间是目录路径,类名是文件名。因此,上面定义的课程application\controllers\Base()
会加载文件www/application/controllers/Base.php
。
我将自动加载器放入一个文件bootstrap.php,该文件位于我的根目录中。这可以直接包含,也可以将php.ini修改为auto_prepend_file,以便在每个请求中自动包含它。
通过使用spl_autoload_register,您可以注册多个自动加载功能,以任何方式加载类文件。即,您可以将部分或全部课程放在一个目录中,也可以放置部分或全部namespaced classes in the one file。非常灵活:)
答案 1 :(得分:27)
您应该为您的类命名,以便下划线(_
)转换为目录分隔符(/
)。一些PHP框架就是这样做的,比如Zend和Kohana。
因此,您将课程命名为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;
}
另请注意,您可以使用spl_autoload_register()
使任何功能成为自动加载功能。它也更灵活,允许您定义多个自动加载类型功能。
如果必须有多个自动加载功能,spl_autoload_register()允许这样做。它有效地创建了一个自动加载功能队列,并按照它们的定义顺序遍历每个功能。相比之下,__ autoload()只能定义一次。
修改强>
注意: __ autoload 自PHP 7.2.0起已被弃用。非常不鼓励依赖此功能。有关更多详细信息,请参阅PHP文档。 http://php.net/manual/en/function.autoload.php
答案 2 :(得分:7)
我必须提一下“好”的自动加载脚本和代码结构,所以请仔细阅读以下内容
记住:
例如:Example.php包含
class Example {}
例如:/ Path1 / Path2 / Example.php匹配
namespace Path1\Path2;
class Example {}
例如:/Path1/Path2/Example.php with root:
namespace APP\Path1\Path2;
class Example {}
考虑到这一点,我制作了以下脚本:
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;
}
}
放置它的位置..
记住:
快乐编码; - )
其他答案的一点评论: 这只是我的个人意见 - 没有意图!
https://stackoverflow.com/a/5280353/626731 @alex很好的解决方案,但不要让你的类名为坏文件结构付费;-) 这是命名空间的工作
https://stackoverflow.com/a/5280510/626731 @ Mark-Eirich它有效,但是这种方式非常讨厌/丑陋/缓慢/僵硬[...]风格..
https://stackoverflow.com/a/5284095/626731 @tealou要解决他的问题这是迄今为止最明确的方法:-) ..
https://stackoverflow.com/a/9628060/626731 @ br3nt这反映了我的观点,但请(!)..不要使用strtr !! ..这让我:
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
来源:http://www.simplemachines.org/community/index.php?topic=175031.0
有问题吗? ..(但他实际上对完整路径是正确的)
https://stackoverflow.com/a/12548558/626731 @ Sunil-Kartikey https://stackoverflow.com/a/17286804/626731 @jurrien
永远不要在时间关键的环境中循环!不要在os上搜索文件! - 慢慢
https://stackoverflow.com/a/21221590/626731 @sagits ..比Marks好得多; - )
答案 3 :(得分:4)
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');
答案 4 :(得分:3)
这是我的解决方案,
/**
* 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'));
我不确定它是否是最佳解决方案,但似乎完美无缺......
你怎么看?
答案 5 :(得分:2)
我的版本@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");
在我的情况下,只有控制器类在其名称中包含关键字,根据您的需要进行调整。
答案 6 :(得分:2)
我能给你的最简单的答案,无需写下复杂的代码,甚至不使用命名空间(如果这让你感到困惑)
示例代码。 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;
}
}
我猜这个逻辑本身是可以解释的。队友的欢呼声!希望这会有所帮助:)
答案 7 :(得分:1)
这就是我要做的事情:
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;
}
只要您一致地命名文件,例如class_controller_*.php
和class_model_*.php
,这应该可以正常工作。
答案 8 :(得分:0)
每个人都在从他们从互联网上下载的代码中处理和粘贴事物(所选答案除外)。它们都使用String Replace。
String Replace比strtr慢4倍。你应该改用它。
在包含自动加载的类时,您还应该使用完整路径,因为操作系统解析路径所需的时间较短。
答案 9 :(得分:0)
__ autoload()函数,因为它没有被激怒。请改用spl_autoload(),spl_autoload_register()。 __autoload()只能加载一个类,但spl_autoload()可以获得多个类。还有一件事,将来__autoload()可能会被弃用。可以在http://www.php.net/manual/en/function.spl-autoload.php
上找到更多内容答案 10 :(得分:0)
尽管这个脚本没有名称约定,但这个帖子已经有点老了,万一有人正在寻找可能的答案,这就是我所做的:
function __autoload($name) {
$dirs = array_filter(glob("*"), 'is_dir');
foreach($dirs as $cur_dir) {
dir_searcher($cur_dir, $name);
}
}
function dir_searcher($cur_dir, $name) {
if(is_file("$cur_dir/$name.php")) {
require_once "$cur_dir/$name.php";
}
$dirs = array_filter(glob($cur_dir."/*"), 'is_dir');
foreach($dirs as $cdir) {
dir_searcher("$cdir", $name);
}
}
不确定它是否真的最佳,但它通过递归读取dir来搜索文件夹。借助创造性的str_replace功能,您可以获得自己的名字。
答案 11 :(得分:0)
我用这个。基本上将文件夹结构(MVC等)定义为序列化数组中的常量。然后在自动加载类中调用该数组。对我有效。
您显然可以使用其他功能创建文件夹数组,但对于MVC,您也可以手动输入。
为此,你需要调用你的类...... class.classname.php
//in your config file
//define class path and class child folders
define("classPath","classes");
define("class_folder_array", serialize (array ("controller", "model", "view")));
//wherever you have your autoload class
//autoload classes
function __autoload($class_name) {
$class_folder_array = unserialize (class_folder_array);
foreach ($class_folder_array AS $folder){
if(file_exists(classPath."/".$folder.'/class.'.$class_name.'.php')){require_once classPath."/".$folder.'/class.'.$class_name.'.php';break;}
}
}