代码之家  ›  专栏  ›  技术社区  ›  JoshReedSchramm

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

  •  9
  • JoshReedSchramm  · 技术社区  · 17 年前

    我一直在为如何在php代码中最好地包含类而挣扎。路径通常是一个问题,但几分钟前我发现 this question 这非常有帮助。现在我正在阅读有关自动加载的文章,并认为它可以使我的应用程序开发过程变得更加简单。问题是,我喜欢将文件夹结构保持为独立的功能区域,而不是将所有内容都放在general/lib文件夹中。所以,如果我覆盖autoload对一个类文件夹(包括所有子文件夹)进行深度搜索,我能期望什么样的性能?

    显然,这将取决于规模、文件夹结构的深度和类的数量,但通常我会问一个中等规模的项目,它会导致问题吗。

    7 回复  |  直到 9 年前
        1
  •  6
  •   Ben Everard    16 年前

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

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

        2
  •  5
  •   Greg    17 年前

    一种常见的模式(例如Pear、Zend Framework…)是使类名反映路径,因此Db_Adapter_Mysql将位于/Db/Adapter/Mysql.php中,从添加到include路径的某个地方开始。

        3
  •  1
  •   Mez    17 年前

    有两种方法可以很容易地做到这一点,首先,命名类,以便它们定义查找它们的结构

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

    一个例子

    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
    
        4
  •  1
  •   andy.gurin    17 年前

    如果使用如下智能分类法,性能不会受到影响: 1.每个库都保存在文件夹“包”中 2.通过将类名中的“\”替换为“/”并在末尾添加“.php”,可以定位每个类 类=我的应用程序智能对象

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

        5
  •  0
  •   Dan Udey    17 年前

    到处寻找文件会让事情变得更慢(更多的磁盘点击)。加载所有类以备需要,这会占用更多内存。在每个文件中指定所需的类很难维护(即,如果不再使用这些类,它们不会被删除)。

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

        6
  •  0
  •   Rob    17 年前

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

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

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

        7
  •  0
  •   dcousineau    17 年前

    Zend Framework的方法是基于PEAR文件夹标准(Class_Foo映射到/Class/Foo.php)进行自动加载,而不是使用设置基路径,而是使用include_路径。

    他们的方法存在的问题是,无法事先检查文件是否存在,因此自动加载将尝试包含任何包含路径中不存在的文件,出错,并且永远不会给任何其他使用spl_autoload_register注册的自动加载函数包含该文件的机会。

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

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

    但是,如果您发现自己仍然需要递归扫描目录,那么问题不是“自动加载会影响我的性能”,而是“为什么我要在随机结构中丢弃我的类文件?”坚持PEAR结构会让您省去很多麻烦,即使您决定手动执行include而不是自动加载,也不会在执行include语句时猜测类文件的位置。