【问题标题】:Efficient PHP auto-loading and naming strategies高效的 PHP 自动加载和命名策略
【发布时间】:2009-04-27 00:33:30
【问题描述】:

与当今的大多数 Web 开发人员一样,我非常享受可靠的 MVC 架构为 Web 应用程序和网站带来的好处。使用 PHP 进行 MVC 时,自动加载显然非常方便。

我已经成为spl_autoload_register 的粉丝,而不是简单地定义一个__autoload() 函数,因为如果您合并不同的基本模块,每个模块都使用自己的自动加载,这显然更灵活。但是,我从来没有对自己编写的加载函数感觉良好。它们涉及大量的字符串检查和目录扫描,以便寻找可能要加载的类。

例如,假设我有一个应用程序,它的基本路径定义为PATH_APP,以及一个简单的结构,其中包含名为modelsviewscontrollers 的目录。我经常使用一种命名结构,文件在适当的目录中被命名为IndexView.phpIndexController.php,默认情况下模型通常没有特定的方案。我可能有一个像这样的结构的加载器函数,它被spl_autoload_register注册:

public function MVCLoader($class)
{
    if (file_exists(PATH_APP.'/models/'.$class.'.php')) {
        require_once(PATH_APP.'/models/'.$class.'.php');
        return true;
    }
    else if (strpos($class,'View') !== false) {
        if (file_exists(PATH_APP.'/views/'.$class.'.php')) {
            require_once(PATH_APP.'/views/'.$class.'.php');
            return true;
        }
    }
    else if (strpos($class,'Controller') !== false) {
        if (file_exists(PATH_APP.'/controllers/'.$class.'.php')) {
            require_once(PATH_APP.'/controllers/'.$class.'.php');
            return true;
        }
    }
    return false;
}

如果之后没有找到,我可能有另一个功能来扫描模型目录中的子目录。但是,所有 if/else-ing、字符串检查和目录扫描对我来说似乎效率低下,我想改进它。

我很好奇其他开发人员可能会采用什么文件命名和自动加载策略。我正在专门寻找用于高效自动加载的好技术,而不是自动加载的替代方法。

【问题讨论】:

    标签: php naming-conventions spl-autoload-register


    【解决方案1】:

    这是我在所有项目中一直使用的(直接取自上一个项目的源代码):

    public static function loadClass($class)
    {
        $files = array(
            $class . '.php',
            str_replace('_', '/', $class) . '.php',
        );
        foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path)
        {
            foreach ($files as $file)
            {
                $path = "$base_path/$file";
                if (file_exists($path) && is_readable($path))
                {
                    include_once $path;
                    return;
                }
            }
        }
    }
    

    如果我查找 SomeClass_SeperatedWith_Underscores,它将查找 SomeClass_SeperatedWith_Underscores.php,然后是 SomeClass/SeperatedWith/Underscores.php,根目录在当前包含路径中的每个目录。

    编辑:我只是想说明一下,我用它来提高开发效率,而不一定是处理时间。如果您的路径上有 PEAR,那么您可以只使用这些类,而不必在需要时包含它们。

    我倾向于将我的类保存在目录层次结构中,下划线分解命名空间...如果我愿意,这段代码可以让我保持文件结构的整洁,或者如果我想注入一个没有嵌套目录的快速类文件想要(用于将一个或两个类添加到它是被告的图书馆,但不是我目前正在从事的项目的一部分。)

    【讨论】:

    • 我绝对喜欢下划线的方法。它使类到文件的翻译更加高效。
    • array_unique() 包裹在您的 $files 数组周围。如果类名中没有下划线,则您将每个文件尝试两次。
    【解决方案2】:

    我找到了这个解决方案:

    我创建了一个脚本,它遍历我的类库文件夹(其中包含单独模块/系统的子文件夹),并解析文件内容以查找类定义。如果它在 php 文件中找到类定义(非常简单的正则表达式模式),它会创建一个符号链接:

    class_name.php -> actual/source/file.php
    

    这让我可以使用一个简单的自动加载函数,它只需要类名和主符号链接文件夹的路径,而不必进行任何路径/字符串操作。

    最好的部分是我可以完全重新排列我的源代码或添加一个新的子系统,然后运行链接生成脚本来自动加载所有内容。

    【讨论】:

    • 这可能是我遇到过的最有创意的解决方案。好东西。只是出于好奇,这种方法的跨平台程度如何?
    • 自从我开始使用 linux 以来,我对 Windows 的主要抱怨之一就是缺少符号链接。据我所知,此解决方案仅适用于 unix。
    • 仅供参考,您可以使用 mklink 在 Windows 中创建符号链接:howtogeek.com/howto/windows-vista/…
    • @therefromhere:感谢您的链接!从 XP 时代开始就很少使用 Windows,但这绝对值得了解。
    • 不管怎样,自 Windows 2000 左右以来,符号链接一直在使用 NTFS 的 Windows 上工作。
    【解决方案3】:

    如果您想要提高效率,那么您根本不应该使用自动加载功能。自动加载功能是为了懒惰。包含它们时,您应该提供包含文件的显式路径。如果您的自动加载功能可以找到这些文件,那么您可以编写代码来明确地找到它们。当您处理代码的视图部分并即将加载新的视图类时,通过让自动加载函数处理它,它首先假设您的类是模型类?那是低效的。相反,您的代码应该是:

    include_once $this->views_path . $class . '.php';
    

    如果您需要多个“视图”路径,请创建一个加载视图的函数:

    public function load_view($class) {
        // perhaps there's a mapping here instead....
        foreach ($this->views_paths as $path) {
            $filename = $path . $class . '.php';
            if (file_exists($filename)) {
                include_once $filename;
            }
        }
        throw ....
    }
    

    在任何情况下,在包含发生的地方,您都拥有关于要加载的类的最丰富/最准确的信息。使用该信息完全加载类是唯一有效的类加载策略。是的,您最终可能会得到更多的类变量或(天堂禁止)一些全局变量。但这比只是懒惰并为您的班级扫描文件系统的某些部分更好。

    【讨论】:

    • 虽然您认为直接加载是最有效的整体是正确的,但它使代码更难维护。如果更改类或文件的名称怎么办?或者说我有可以由控制器加载的动态视图段,随着项目的进行,越来越多的视图类被创建。每次创建视图类时,我都不想返回并修改控制器以手动将其包含在可能使用的任何位置。我同意自动加载的效率低于直接加载,但我正在寻找最有效的自动加载。
    • 如果您必须在一个类投入生产后更改它的名称,那么您在编写代码之前就没有花足够的时间进行设计。如果效率很重要,那么提前花更多时间在维护上可以节省无限多的时间,而不是像自动加载这样的懒惰、根本不用考虑的功能。
    • 那么你的 load_view 函数与自动加载有什么不同呢?这正是自动加载的用途。
    • 我更喜欢显式操作而不是隐式操作。在文档页面上也有一些关于自动加载的警告,例如“注意:在 __autoload 函数中抛出的异常不能在 catch 块中捕获并导致致命错误。”强大的软件不会忽略(或者在这种情况下屏蔽并死掉)异常。
    • @Supericy 仅仅因为在开发过程中应该捕获某些东西并不意味着它会或不会在野外发生。您并不总是可以完全控制安装环境,因此您不应该依赖它来避免失败。
    猜你喜欢
    • 2011-08-06
    • 2015-07-15
    • 2012-05-21
    • 2013-10-24
    • 1970-01-01
    • 2013-11-25
    • 2014-04-13
    相关资源
    最近更新 更多