无法重新声明类:如果已存在于文件夹中,如何自动加载类?

时间:2014-07-06 10:44:46

标签: php spl spl-autoload-register spl-autoloader

如何检查文件夹中是否存在 一个类 再次从另一个文件夹中加载此类?

我有这个文件夹结构,例如,

index.php
  code/
  local/

我在code/local/

中有两个相同的

来自本地/

class Article
{
    public function getArticle()
    {
        echo 'class from local';
    }
}

来自核心,

class Article
{
    public function getArticle()
    {
        echo 'class from core';
    }
}

所以我需要一个脚本,可以检测local/中的文章类 - 如果它已经退出该文件夹而不是从核心/再次加载该类文件夹。可能吗?

这是index.php中用于加载类的自动加载功能

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

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

    // Set other vars and arrays.
    $sub_directories = array();

    // When you use namespace in a class, you get something like this when you auto load that class \foo\tidy.
    // So use explode to split the string and then get the last item in the exloded array.
    $parts = explode('\\', $class_name);

    // Set the class file name.
    $file_name = end($parts).'.php';


    // List any sub dirs in the main dirs above and store them in an array.
    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()) 
            {
                // Replace any backslash to '/'.
                $pathnameReplace = str_replace('\\', '/', $fileObject->getPathname());
                //print_r($pathnameReplace);

                // Explode the folder path.
                $array = explode("/",$pathnameReplace);

                // Get the actual folder.
                $folder = end($array);
                //print_r($folder);

                // Stop proccessing if the folder is a dot or double dots.
                if($folder === '.' || $folder === '..') {continue;} 
                //var_dump($fileObject->getPathname());

                // Must trim off the WEBSITE_DOCROOT. 
                $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);


    // 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))
        {
            // There is no need to use include/require_once. Autoload is a fallback when the system can't find the class you are instantiating. 
            // If you've already included it once via an autoload then the system knows about it and won't run your autoload method again anyway. 
            // So, just use the regular include/require - they are faster.
            include WEBSITE_DOCROOT.$path_directory.$file_name;
        } 
    }
}

// Register all the classes.
spl_autoload_register('autoloadMultipleDirectory');
$article = new Article();
echo $article->getArticle();

当然我收到了这个错误,

Fatal error: Cannot redeclare class Article in C:\wamp\...\local\Article.php on line 3

class_exists似乎是我应该研究的答案,但我如何将其与上述函数一起使用,特别是spl_autoload_register。或者,如果你有更好的想法?

1 个答案:

答案 0 :(得分:2)

好的,我误解了你的问题。这应该可以解决问题。

<?php

function __autoload($class_name) {
  static $core = WEBSITE_DOCROOT . DIRECTORY_SEPARATOR . "core";
  static $local = WEBSITE_DOCROOT . DIRECTORY_SEPARATOR . "local";

  $file_name = strtr($class_name, "\\", DIRECTORY_SEPARATOR):
  $file_local = "{$local}{$file_name}.php";

  require is_file($file_local) ? $file_local : "{$core}{$file_name}.php";
}

使用命名空间可以轻松解决这个问题。

您的核心文件转到/Core/Article.php

namespace Core;

class Article {}

您的本地文件转到/Local/Article.php

namespace Local;

class Article {}

然后使用一个非常简单的自动加载器,例如:

function __autoload($class_name) {
  $file_name = strtr($class_name, "\\", DIRECTORY_SEPARATOR);
  require "/var/www{$file_name}.php";
}

PHP按需加载您的类,不需要预先加载文件!

如果您想使用文章,请执行以下操作:

<?php

$coreArticle = new \Core\Article();
$localArticle = new \Local\Article();