Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/242.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP spl_自动加载_寄存器导致类重复?_Php_Spl Autoload Register_Spl Autoloader - Fatal编程技术网

PHP spl_自动加载_寄存器导致类重复?

PHP spl_自动加载_寄存器导致类重复?,php,spl-autoload-register,spl-autoloader,Php,Spl Autoload Register,Spl Autoloader,这是我的网页结构,比如说 index.php 'core/model/' 'core/helper/' 'core/ext/' 我在model文件夹下有这些类文件 MyClass.php MyClass2.php classfour.php 我想通过自动加载类自动加载它们 define ('WEBSITE_DOCROOT', str_replace('\\', '/', dirname(__FILE__)).'/'); function autoloadMultipleDi

这是我的网页结构,比如说

index.php

  'core/model/' 
  'core/helper/'
  'core/ext/'
我在
model
文件夹下有这些类文件

MyClass.php
MyClass2.php
classfour.php
我想通过自动加载类自动加载它们

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
现在都在列表中


为什么

您在这里讨论的是一些不同的问题

自动加载与手动加载…

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

这与手动包含类文件不同。只要包含
myfooclass.php
文件,就会声明相关的类,而不管它是否在以后实例化

…和
获取声明的类()

get_declared_classes()
执行其名称所暗示的操作:它返回一个数组,其中包含在调用它时已声明的所有类。换句话说,如果从脚本中的多个位置调用它,很可能会得到不同的结果,这取决于当时声明的类

复制

我可以在live server的结果中看到重复的路径,但不是您描述它们的方式。例如,
core/model/
core/model/
的副本,因为前者解析为后者。但是
core/model/。/
不是重复的,因为它解析为
core/
(它只在以后通过
core/helper/。/
core/ext/。/
进行复制)

一个好的实践是使用它来解决这些问题(以及其他一些问题),并为您提供绝对的、规范化的、现有的路径。此外,在将路径插入
$sub_目录
之前,您应该检查路径是否已经存在:

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;
  }
…或在使用前执行以下操作:

$merged_directories = array_merge($main_directories,$sub_directories);
$merged_directories = array_unique($merged_directories);
print_r($merged_directories);
当然,这些解决方案是被动的,不需要更改应用程序逻辑

另一种故障保护方法是使用
include_once
而不是
include
,以避免意外地将同一文件包含两次

哦,还有最后一点:在找到有问题的文件后,就不需要继续搜索了。只需断开循环即可:

    if(file_exists($path_directory.$file_name))
      {
      include_once $path_directory.$file_name;
      break; // <-- no point going on
      }
if(文件存在($path\u directory.$file\u name))
{
包含一次$path\u目录。$file\u名称;

break;//我看到了三种不同的
print\r()
输出。这是可以解释的:这是因为autoload函数被调用了三次。我没有看到aledged“replication”问题。复制的内容和位置是什么?请看我上面的编辑。谢谢。在“将导致复制取决于我实例化了多少类”这句话的意思是你提供了三个
print\r()
输出。这就是我所指的。我从来没有说过你的自动加载函数会多次使用它,我说你会多次调用你的自动加载函数。不可能。每次你做一个
新的xyzClass()
它是隐式调用的。这是经过设计的。这正是您必须传递
$class\u name
参数的原因,以便它知道您尝试实例化的类。请查看我下面的回答是否涵盖了您的问题。非常感谢您的回答!非常感谢!!:D