来自不同文件夹的自动加载类

时间:2011-03-12 03:26:19

标签: php oop autoload

这是我在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
    {
    ...
    }

12 个答案:

答案 0 :(得分:59)

我发现您使用controller_*****model_*****作为类命名约定。

我读了一个很棒的article,它建议使用php的namespace替代命名约定。

我喜欢这个解决方案,因为我把课程放在哪里并不重要。 __autoload无论在我的文件结构中的哪个位置都会找到它。它还允许我随意调用我的课程。我的代码不需要类命名约定。

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

  • 应用/
    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映射;命名空间是目录路径,类名是文件名。因此,上面定义的课程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;
    }
}

放置它的位置..

  • /Loader.php&lt; - 有装载机
  • / Controller / ...&lt; - 把你的东西放在这里
  • / Model / ...&lt; - 或者这里等
  • / ...

记住:

  • 如果您使用根命名空间,则加载程序也必须位于此命名空间中
  • 您可以为$ Class添加前缀以符合您的需求(controller_base {} - &gt; class_controller_base.php)
  • 您可以将__DIR__更改为包含您的类文件的绝对路径(例如“/ var / www / classes”)
  • 如果您不使用名称空间,则所有文件必须与加载程序一起位于同一目录中(不好!)

快乐编码; - )


其他答案的一点评论: 这只是我的个人意见 - 没有意图!

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_*.phpclass_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;}
    }



    }