2

我目前正在用 PHP 对我的框架进行编程(主要是出于教育原因,以及打发时间的一种方式)。我写了一个自动加载器,它会自动扫描目录树并检测其中的所有类并创建一个如下格式的数组:

Array(
    'MyAwesomeClass' => 'path/to/file/in/some/subdirectory/MyAwesomeClass.php',
    'MyOtherAwesomeClass' => 'path/to/file/MyOtherAwesomeClass.php'
     // ....
);

起初,这非常整洁。因为我不需要担心我把课放在哪里。

但后来我发现这是非常资源密集的。所以我创建了一个缓存机制,并将索引序列化并保存到文件中。这将 PHP 脚本的响应时间减少了至少 50%。但它带来了一些问题。

在框架的其他类中,我经常使用如下内容:

class_exists('MyAwesomeClassController');

问题是如果我添加了新类MyAwesomeClassController,则该类尚未在索引中并class_exists返回 false。现在的问题是每次向框架添加新类时,我都必须删除缓存文件(让自动加载器重新创建索引)。

我尝试的另一件事(有点老套):在 Autoloader 类中,我检查了是否使用 class_exists() 调用了自动加载方法。如果是这种情况,我重新创建索引以查看是否可以在某处找到请求的类。但这似乎并不奏效,因为有时class_exists使用一个几乎不存在的类来调用,所以这与在每个请求上重新创建索引基本上是相同的解决方案。

有什么解决办法吗?还是我必须完全重写我的 Autoloader?

4

3 回答 3

1

我前段时间走这条路,得出了同样的结论:资源密集型。您实际上在这里所做的是构建某种链接器。

我切换到命名空间和地图的组合。我将一个命名空间映射到一个文件夹,当调用自动加载器时,它会剥离命名空间,查找相应的文件夹,并包含该文件。

我的地图看起来像这样(我选择 xml 作为格式):

<?xml version="1.0" encoding="UTF-8"?>
<autoloader>  
  <namespace id="Ganymedes\Core">/system/core</namespace>
  <namespace id="Ganymedes\Core\Debug">/system/core/debug</namespace>
</autoloader>  

和类加载器:

  public function ClassLoader( $class )
  {    
    if( class_exists( $class, false ))
      return true;

    $classparts = explode( '\\', $class );
    $classfile = '/' . strtolower( array_pop( $classparts )) . '.php';
    $namespace = implode( '\\', $classparts );

    if( isset( $this->namespaces[$namespace] )) {
      foreach ( $this->namespaces[$namespace] as $path ) 
        if( is_readable( $path . $classfile ))
          include_once $path . $classfile;

      return true;
    }

    return false;
  }    
于 2012-10-12T13:07:00.637 回答
1

也许我没有正确理解你想要做什么......但是get_include_path/set_include_path__autoload($class)内置函数有什么问题?

编辑解释我的评论:

在“header.php”(包含在每个脚本开头的文件)中:

set_include_path(get_include_path().PATH_SEPARATOR."my/first/directory"
                                   .PATH_SEPARATOR."my/second/directory"
                                   .PATH_SEPARATOR."this/is/another/directory"
                                   ...
                                   .PATH_SEPARATOR."and/here/is/the/last/one");

function __autoload($class) {
    require_once($class.".class.php");
}

自动加载功能检查路径中的每个目录,直到找到所需的文件。我从来没有检查过它的性能,但我猜它是相当微不足道的,除非你有 100 个目录。如果您有条理,您可以将您经常使用的(基)类放在第一个“额外”路径中,以便立即找到它们。

我刚刚注意到在线 PHP 手册中不再建议使用 __autoload,而应该使用 spl_autoload_register,但概念是相同的。

于 2012-10-12T13:09:26.880 回答
1

在您尝试加载的类应该始终存在的假设下,您的自动加载器可以执行以下操作:

  1. 在地图中查找类名(已缓存)。如果存在,则加载该文件。

  2. 如果它不存在,请执行另一次扫描并在新生成的映射中查找类名。如果存在,将新地图写入光盘并加载文件。

  3. 如果它仍然不存在,请发出警报。

第三步也可以通过引入负缓存来改进;如果该类存在于该地图中,则根据先前的尝试,您知道该类不存在。负缓存的寿命会更短,但足够长,不会破坏您的服务器。

您还可以考虑将离线创建缓存作为部署系统的一部分。

于 2012-10-12T14:12:02.067 回答