性能会在php中使用自动加载并搜索类文件吗?

时间:2008-09-25 19:18:35

标签: php performance

我总是在如何最好地将类包含到我的PHP代码中。路径通常是一个问题,但几分钟前,我发现this question显着有助于此。现在我正在阅读__autoload并认为它可以使我的应用程序开发过程变得更加容易。问题是我喜欢将文件夹结构保持为独立的功能区域,而不是将所有内容都放入通用/ lib文件夹中。因此,如果我覆盖自动加载以深入搜索包含所有子文件夹的类文件夹,我可以期待什么性能命中?

显然这将取决于文件夹结构的规模,深度和类的数量,但一般来说,我要求中等规模的项目会导致问题。

7 个答案:

答案 0 :(得分:6)

__ autoload很棒,但是在递归搜索功能中声明所有文件的成本很高。您可能希望查看构建用于自动加载的文件树。在我的框架中,我一直为其类命名文件,并使用为数据缓存的映射。

从第68行开始查看 http://trac.framewerk.org/cgi-bin/trac.fcgi/browser/trunk/index.php [死链接],了解如何做到这一点。

编辑:为了更直接地回答您的问题,无需缓存,您可以预期在中等到高流量的网站上出现性能损失。

答案 1 :(得分:5)

一个常见的模式(Pear,Zend Framework作为例子......)是为了让classname反映路径,所以Db_Adapter_Mysql将位于/Db/Adapter/Mysql.php,从某个地方添加到include-path

答案 2 :(得分:1)

有两种方法可以轻松完成此操作,首先,为您的类命名,以便他们定义查找位置的结构

function __autoload($classname)
{
    try
    {
        if (class_exists($classname, false) OR interface_exists($classname, false))
        {
            return;
        }

        $class = split('_', strtolower(strval($classname)));

        if (array_shift($class) != 'majyk')
        {
            throw new Exception('Autoloader tried to load a class that does not belong to us ( ' . $classname . ' )');
        }

        switch (count($class))
        {
            case 1: // Core Class - matches Majyk_Foo - include /core/class_foo.php
                $file = MAJYK_DIR . 'core/class_' . $class[0] . '.php';
            break;

            case 2: // Subclass - matches Majyk_Foo_Bar - includes /foo/class_bar.php
                $file = MAJYK_DIR . $class[0] . '/class_' . $class[1] . '.php';
            break;

            default:
                throw new Exception('Unknown Class Name ( ' . $classname .' )');
                return false;
        }

        if (file_exists($file))
        {
            require_once($file);

            if (!class_exists($classname, false) AND !interface_exists($classname, false))
            {
                throw new Exception('Class cannot be found ( ' . $classname . ' )');
            }
        }
        else
        {
            throw new Exception('Class File Cannot be found ( ' . str_replace(MAJYK_DIR, '', $file) . ' )');
        }

    }
    catch (Exception $e)
    {
        // spl_autoload($classname);
        echo $e->getMessage();
    }

}

或者,2,使用多个自动加载器。 PHP> = 5.1.2有SPL库,允许您添加多个自动加载器。你为每个路径添加一个,它会在它的路上找到它。或者只是将它们添加到包含路径并使用默认的spl_autoload()

一个例子

function autoload_foo($classname)
{
    require_once('foo/' . $classname . '.php');
}

function autoload_bar($classname)
{
    require_once('bar/' . $classname . '.php');
}

spl_autoload_register('autoload_foo');
spl_autoload_register('autoload_bar');
spl_autoload_register('spl_autoload'); // Default SPL Autoloader

答案 3 :(得分:1)

Autoload非常棒的PHP功能可以帮助你... 如果将使用如下智能分类法,性能不会受到影响: 1.每个库都保留在“包”文件夹中 2.通过用“/”替换类名中的“_”并在末尾添加“.php”来定位每个类。 class = My_App_Smart_Object file = packages / My / App / Smart / Object.php

这种方法的好处(几乎所有框架都使用)也是一个更智能的代码组织: - )

答案 4 :(得分:0)

在整个地方搜索文件会使事情变得更慢(更多的磁盘命中)。加载所有类以防您可能需要它们会使事情占用更多内存。指定每个文件中需要哪些类很难维护(即如果不再使用它们就不会被删除)。

真正的问题是哪一项对您更重要?最后,他们都是权衡,所以你必须选择一个。但是,有争议的是,第二个和第三个选项中的大部分开销都与实际编译代码有关。使用APC之类的东西可以显着减少加载和编译每个页面加载的每个类的开销。

考虑到使用APC,我可能会采用将代码划分为模块的方法(例如Web界面模块,数据库交互模块等),并让每个模块导入其模块的所有类,以及他们可能需要的其他模块的类。这是最后两个之间的权衡,我发现它足以满足我的需求。

答案 5 :(得分:0)

我倾向于使用一种简单的方法,其中__autoload()将哈希映射类名称引用到相对路径,该路径包含在使用简单脚本重新生成的文件中,该脚本本身执行递归搜索。

这要求在添加新的类文件或重构代码库时运行脚本,但它也避免了__autoload()中的“聪明”,这会导致不必要的stat()调用,并且它具有以下优点:我可以轻松地在我的代码库中移动文件,知道我需要做的就是运行一个脚本来更新自动加载器。

脚本本身递归检查我的includes /目录,并假设任何未在排除列表(自动加载器本身,以及我倾向于拥有的其他标准文件)中命名的PHP文件包含一个同名的类。

答案 6 :(得分:0)

Zend Framework的方法是根据PEAR文件夹标准(Class_Foo映射到/Class/Foo.php)进行自动加载,但是不使用set基本路径,而是使用include_path。

他们的方法的问题是没有办法预先检查文件是否存在,因此自动加载将尝试包含任何include_path中不存在的文件,错误输出,并且永远不会给任何其他自动加载功能注册使用spl_autoload_register有机会包含该文件。

所以稍微偏离是手动提供一个基本路径数组,其中自动加载可以期望找到以PEAR方式设置的类并且只是循环遍历基本路径:

<?php
//...
foreach( $paths as $path )
{
    if( file_exists($path . $classNameToFilePath) )
        include $path . $classNameToFilePath;
}
//...
?>

当然,你会有点搜索,但对于每个自动加载,你只会在最差的n次搜索中进行,其中n是你正在检查的基本路径的数量。

但如果你发现自己仍然不得不递归扫描目录,问题不是“自动加载是否会损害我的表现”,问题应该是“我为什么要在随机结构中丢弃我的类文件?”坚持PEAR结构将为您节省许多麻烦,即使您决定手动执行包含而不是自动加载,也不会猜测在执行include语句时类文件的位置。< / p>