0

例如,这是我的网络结构,

index.php

  'core/model/' 
  'core/helper/'
  'core/ext/'

我在文件夹下有这些类文件model

MyClass.php
MyClass2.php
classfour.php

我想通过 Autoload 类自动加载它们,

define ('WEBSITE_DOCROOT', str_replace('\\', '/', dirname(__FILE__)).'/');

function autoloadMultipleDirectory($class_name) 
{
    // List all the class directories in the array.
    $main_directories = array(
        'core/model/',
        'core/helper/',
        'core/ext/'
    );

    $sub_directories = array();

    $parts = explode('\\', $class_name);

    $file_name = end($parts).'.php';

    foreach($main_directories as $path_directory)
    {
        $iterator = new RecursiveIteratorIterator
        (
            new RecursiveDirectoryIterator(WEBSITE_DOCROOT.$path_directory), // Must use absolute path to get the files when ajax is used.
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $fileObject) 
        {
            if ($fileObject->isDir()) 
            {
                $sub_directories[] = preg_replace('~.*?(?=core|local)~i', '', str_replace('\\', '/', $fileObject->getPathname())) .'/';
            }
        }
    }

    // Mearge the main dirs with any sub dirs in them.
    $merged_directories = array_merge($main_directories,$sub_directories);

    print_r($merged_directories);

    // Loop the merge array and include the classes in them.
    foreach($merged_directories as $path_directory)
    {
        if(file_exists(WEBSITE_DOCROOT.$path_directory.$file_name))
        {
            include WEBSITE_DOCROOT.$path_directory.$file_name;
        } 
    }
}

实施,

spl_autoload_register('autoloadMultipleDirectory');

//define classone
class classone { }

//define classtwo
class classtwo { }

//define classthree
class classthree { }

print_r(get_declared_classes());

结果,

Array
(
    [0] => stdClass
    ...
    [131] => tidyNode
    [132] => classone
    [133] => classtwo
    [134] => classthree
)

但是classfour, MyClass&MyClass2不在列表中。

而对于,

$test = new MyClass();

$test2 = new MyClass2();

$test3 = new classfour();

将导致重复取决于我实例化了多少类,

Array
(
    [0] => core/model/
    [1] => core/helper/
    [2] => core/ext/
)
Array
(
    [0] => core/model/
    [1] => core/helper/
    [2] => core/ext/
)
Array
(
    [0] => core/model/
    [1] => core/helper/
    [2] => core/ext/
)

在我的实时服务器中,我得到了更奇怪的结果,

Array
(
    [0] => core/model/
    [1] => core/helper/
    [2] => core/ext/
    [3] => core/model/./ (duplicated)
    [4] => core/model/../ (duplicated)
    [5] => core/helper/./ (duplicated)
    [6] => core/helper/../ (duplicated)
    [7] => core/ext/./ (duplicated)
    [8] => core/ext/../ (duplicated)
)

知道为什么以及如何解决它吗?

编辑:

如果我手动包含这些类,

 include 'core/model/MyClass.php';
 include 'core/model/MyClass2.php';
 include 'core/model/classfour.php';

print_r(get_declared_classes());

$test = new MyClass();

$test2 = new MyClass2();

$test3 = new classfour();

我得到正确答案,

Array
(
    [0] => stdClass
    ...
    [131] => tidyNode
    [132] => classone
    [133] => classtwo
    [134] => classthree
    [135] => MyClass
    [136] => MyClass2
    [137] => classfour
)

classfour, MyClass&MyClass2现在在列表中。

怎么来的!??

4

1 回答 1

2

您在这里解决了一些不同的问题。

自动加载与手动加载...

当你注册一个自动加载函数时,它会在你实例化一个对象时被调用。在此函数中,您应该检查正在实例化的类并以某种方式提供相应的类定义,通常是通过包含相关的 php 文件。这很方便,因为您确保仅以 JIT 方式实际声明需要实例化的类。另请注意,如果您的类扩展了另一个类,则还将为父类调用自动加载函数,并以递归方式为所有祖先类调用。

这与手动包含类文件不同。一旦包含一个myfooclass.php文件,就会声明相关的类,无论它是否稍后被实例化。

...和get_declared_classes()

get_declared_classes()顾名思义:它返回一个数组,其中包含您调用它时已声明的所有类。换句话说,如果您从脚本中的多个位置调用它,您可能会得到不同的结果,具体取决于当时声明的类。

重复

我可以在您的实时服务器的结果中看到重复的路径,但不是您描述它们的方式。例如,core/model/./是 的副本,core/model/因为前者解析为后者。Butcore/model/../不是重复的,因为它解析为core/(它只会在以后通过core/helper/../and重复core/ext/../)。

一个好的做法是使用realpath()可以解决此类问题(以及其他一些问题)并为您提供绝对的、规范化的现有路径。此外,您应该在将路径插入之前检查路径是否已经存在$sub_directories

if ($fileObject->isDir()) 
  {
  $pathname=$fileObject->getPathname();
  $slashed=str_replace('\\', '/', $pathname);
  $filtered=preg_replace('~.*?(?=core|local)~i', '', $slashed) .'/';
  $canonical=realpath($filtered);
  if(!in_array($canonical,$sub_directories)) $sub_directories[] = $canonical;
  }

...或者array_unique()在使用它之前做一个:

$merged_directories = array_merge($main_directories,$sub_directories);
$merged_directories = array_unique($merged_directories);
print_r($merged_directories);

当然,这些解决方案是被动的,不需要您更改应用程序逻辑。

另一个故障保护是使用include_once而不是,include以免意外包含相同的文件两次。

哦,最后一点:找到有问题的文件后,无需继续搜索。只是break循环:

    if(file_exists($path_directory.$file_name))
      {
      include_once $path_directory.$file_name;
      break; // <-- no point going on
      }
于 2013-11-01T11:38:08.953 回答