0

How can I check if a class exists already in a folder then do not load this class again from another folder?

I have this folder structure for instance,

index.php
  code/
  local/

And I have these two identical classes in code/ and local/

from local/

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

from core,

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

So I need a script that can detects the class of Article in local/ - if it exits already in that folder than don't load the class again from core/ folder. Is it possible?

This is my autoload function in index.php for loading classes,

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

of course I get this error,

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

class_exists seems to be the answer I should look into, but how can I use it with the function above, especially with spl_autoload_register. Or if you have any better ideas?

NikiC
  • 100,734
  • 37
  • 191
  • 225
Run
  • 54,938
  • 169
  • 450
  • 748

1 Answers1

2

Okay, I misunderstood your question. This should do the trick.

<?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";
}

This is easily solved by using namespaces.

Your core file goes to /Core/Article.php:

namespace Core;

class Article {}

Your local file goes to /Local/Article.php:

namespace Local;

class Article {}

And then use a very simple autoloader, e.g.:

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

PHP loads your classes on demand, there's no need to load the files up front!

If you want to use an article simply do:

<?php

$coreArticle = new \Core\Article();
$localArticle = new \Local\Article();
Fleshgrinder
  • 15,703
  • 4
  • 47
  • 56
  • thanks but I would like to ignore the class in core folder if that class exists in local folder, becos the classes in the core folder are for future updates. the classes in the local are for local customization. does it make sense? – Run Jul 06 '14 at 11:28
  • I extended my answer. – Fleshgrinder Jul 06 '14 at 11:32
  • Sorry, so, I can't use `spl_autoload_register` anymore in your answer code? – Run Jul 06 '14 at 11:41
  • 1
    Sure you can, simply name the function something else and register it. The body of the function makes the difference. ;) – Fleshgrinder Jul 06 '14 at 11:45