自动加载来自不同文件夹的课程

这是我自动加载我的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文件夹中也有类,我也想自动加载它们 – 我该怎么做? 我应该复制上面的自动加载,只是改变pathmodels/ (但不是这个重复??)?

谢谢。

编辑:

这些是我的控制器文件夹中的类文件名:

 class_controller_base.php class_factory.php etc 

这些是我的模型文件夹中的类文件名:

 class_model_page.php class_model_parent.php etc 

这是我通常命名我的控制器类的类(我使用下划线和lowcaps)

 class controller_base { ... } class controller_factory { ... } 

这是我如何命名我的模型类类通常(我使用下划线和lowcaps),

 class model_page { ... } class model_parent { ... } 

您应该命名您的类,使下划线( _ )转换为目录分隔符( / )。 一些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()使任何函数成为自动加载函数。 它也更灵活,允许你定义多个自动加载types的函数。

如果必须有多个自动加载函数,spl_autoload_register()允许这样做。 它有效地创build一个自动加载函数队列,并按照它们定义的顺序遍历每个函数。 相反,__autoload()只能定义一次。

编辑

注意: __ autoload自PHP 7.2.0开始已经被拒绝。 依靠这个function是非常沮丧的。 有关更多详细信息,请参阅PHP文档。 http://php.net/manual/en/function.autoload.php

我看到你正在使用controller_*****model_*****作为类的命名约定。

我读了一篇精彩的文章 ,提出了一个使用php namespace的替代命名约定。

我喜欢这个解决scheme,因为我放课的地方并不重要。 __autoload会发现它,无论它在我的文件结构中。 无论我想要什么,它也允许我打电话给我的class级。 我不需要类的命名约定,我的代码工作。

例如,您可以设置您的文件夹结构,如:

  • 应用/
    1. 控制器/
      • Base.php
      • Factory.php
    2. 楷模/
      • page.php文件
      • Parent.php

你的课程可以像这样设置:

 <?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映射; 命名空间是目录path,类名是文件名。 所以上面定义的类application\controllers\Base()将加载文件www/application/controllers/Base.php

我把自动加载器放到一个文件bootstrap.php中,该文件位于我的根目录下。 这可以直接包含在内,也可以将php.ini修改为auto_prepend_file,以便在每个请求中自动包含它。

通过使用spl_autoload_register,您可以注册多个自动加载函数,以任何您想要的方式加载类文件。 也就是说,您可以将一些或全部类放在一个目录中,或者可以将一些或全部名称空间类放在一个文件中 。 非常灵活:)

我不得不提一些关于“好的”自动加载脚本和代码结构的东西,所以请仔细阅读以下内容


记住:

  • 类名===文件名
  • 每个文件只有一个类

例如:Example.php包含

 class Example {} 
  • 命名空间===目录结构

例如:/Path1/Path2/Example.php匹配

 namespace Path1\Path2; class Example {} 
  • 那里应该是一个根名字空间来避免冲突

例如:/ root1 / Path2 / Example.php root:

 namespace APP\Path1\Path2; class Example {} 
  • 切勿使用手动定义的path或目录列表,只需将加载器指向最上面的目录即可
  • 尽可能保持加载器(因为包含一个文件是足够昂贵的)

考虑到这一点,我产生了以下脚本:

 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; } } 

在哪里放置..

  • /Loader.php < – 有加载器
  • /控制器/ … < – 把你的东西放在这里
  • /型号/ … < – 或在这里等
  • / …

Remeber:

  • 如果您使用根名称空间,则加载器也必须位于该名称空间中
  • 你可以前缀$ Class来匹配你的需求(controller_base {} – > class_controller_base.php)
  • 你可以把__DIR__改成包含你的类文件的绝对path(例如“/ var / www / classes”)
  • 如果你不使用命名空间,那么所有的文件必须和loader一起放在同一个目录下(坏的)

快乐编码;-)


在其他答案稍微审查: 这只是我的个人意见 – 没有任何犯罪的目的!

https://stackoverflow.com/a/5280353/626731 @alex很好的解决scheme,但不要让你的类名支付不良的文件结构;-)这是名称空间的工作

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

有问题吗? (但他其实是正确的,包括全path)

https://stackoverflow.com/a/12548558/626731 @ Sunil-Kartikey https://stackoverflow.com/a/17286804/626731 @jurrien

永远不要在时间关键的环境中循环! 不要在操作系统上search文件! – 慢

https://stackoverflow.com/a/21221590/626731 @sagits ..比Marks好多了;-)

 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'); 

这是我的解决scheme,

 /** * 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')); 

我不确定这是否是最好的解决scheme,但似乎完美的工作…

你怎么看??

我的@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"); 

在我的情况下,只有控制器类名称中包含关键字,根据您的需要进行调整。

这是我会做的:

 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_*.phpclass_model_*.php ,这应该工作正常。

最简单的答案我可以给你没有写下这些复杂的代码,甚至没有使用命名空间(如果这使你困惑)

示例代码。 工程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; } } 

我想这个逻辑是可以解释的。 队友的欢呼声! 希望这可以帮助 :)

每个人都在应付和粘贴来自互联网上的代码的东西(除了选定的答案)。 他们都使用stringreplace。

stringreplace比strtr慢4倍。 你应该用它来代替。

包含具有自动加载的类时,还应该使用完整path,因为OS需要较less的时间来parsingpath。

__autoload()函数不应该被使用,因为它不被鼓励。 改用spl_autoload(),spl_autoload_register()。 __autoload()只能加载一个类,但spl_autoload()可以获得多于一个类。 还有一件事,将来__autoload()可能会被弃用。 更多的东西可以在http://www.php.net/manual/en/function.spl-autoload.phpfind

尽pipe这个脚本没有名称约定,这个线程已经有点老了,万一有人正在寻找一个可能的答案,这就是我所做的:

 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); } } 

不知道它是否真的是最佳的,但通过recursion读取dir来search文件夹。 通过创造性的str_replacefunction,你可以得到你的名字。

我用这个 基本上定义你的文件夹结构(MVC等)作为一个序列化数组中的常量。 然后在你的自动加载类中调用数组。 为我有效地工作。

你显然可以使用另一个函数创build文件夹数组,但是对于MVC,你也可以手动input。

为了这个工作,你需要调用你的类…… 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;} } }