Search code examples
phpautoloader

PHP autoloader class to load files from two or three different path


I'm learning to use php autuoloader...
As much as I understand, we can use __autoloader or spl_autoloader_* to auto load files.
Assume this is my directories structure :

ROOT
  |
  |
  ADMIN
  |  |
  |  |
  |  DIST
  |     |
  |     SOME_FOLDER
  |     SOME_FOLDER
  |  TPL
  |     |
  |     |
  |     SOME_FOLDER1
  |           |
  |           test.php
  |     SOME_FOLDER2
  |           |
  |           example1.php
  |           example2.php
  |           example3.php
  |
  |
  CLASSES
       |
       basics.php
       class1.php
       class2.php
       class3.php
       class4.php
  |
  index.php


I made this class for autoload files in CLASSES directory :

basics.php :

class MyAutoLoader
{

    public function __construct()
    {

            spl_autoload_register( array($this, 'load') );

    }




    function load( $file )
    {
        //spl_autoload( 'load1' );

        echo 'Try to call  ' . $file . '.php inside ' . __METHOD__ . '<br>';

        require( $file . '.php' );

    }

}

and in index.php I will include basics.php and every thing is fine for files are stored in CLASSES folder...

require_once("CLASSES/basics.php");
$loaderObject = new MyAutoLoader();


with this code, I can declare class1 ... class3
Now I want to have an autoloder that could be load files in SOME_FOLDER2 which in this case are example1.php , example2.php and example3.php

I tried some cases but the files in SOME_FOLDER2 won't be load using autoloader.

My attempts :

I made a function named load2 in MyAutoLoader class that try to include files from SOME_FOLDER2

function load2( $file )
{
    //spl_autoload_register('load2');

    echo 'Inside LOADER2 ' . __METHOD__ . '<br>';

    require (  'ADMIN/TPL/' . $file . '.php' );

}



And I changed spl_autoload_register in MyAutoLoader constructor :

$allMethods = get_class_methods( 'MyAutoLoader' );
$allMethods = array_splice( $allMethods, 1 );

foreach( $allMethods as $method )
{

    spl_autoload_register( array($this, $method) );

}

But none of them didn't work for me...

Would you please tell me what's wrong in my code or what is my misunderstanding about auloader?

Thanks in Advance


Solution

  • I think your problem basically boils down to not checking if the file exists before requireing it... that will produce a fatal error if the file doesn't exist in the first folder that you attempt to include from.

    I don't know your use case, but here are some suggestions:

    Can you just use a single autoloader?

    function my_autoload($class_name) {
        if (is_file('CLASSES/' . $class_name . '.php')) {
            require_once 'CLASSES/' . $class_name . '.php';
        } else if (is_file('ADMIN/TPL/SOME_FOLDER2/' . $class_name . '.php')) {
            require_once 'ADMIN/TPL/SOME_FOLDER2/' . $class_name . '.php';
        }
    }
    spl_autoload_register("my_autoload");
    

    Or if you need to declare them independently (ie. two or more autoloaders):

    function classes_autoload($class_name) {
        if (is_file('CLASSES/' . $class_name . '.php')) {
            require_once 'CLASSES/' . $class_name . '.php';
        }
    }
    spl_autoload_register("classes_autoload");
    
    function admin_autoload($class_name) {
        if (is_file('ADMIN/TPL/SOME_FOLDER2/' . $class_name . '.php')) {
            require_once 'ADMIN/TPL/SOME_FOLDER2/' . $class_name . '.php';
        }
    }
    spl_autoload_register("admin_autoload");
    

    Or make your autoloader class generic:

    class MyAutoLoader {
        private $path;
        public function __construct($path) {
           $this->path = $path;
           spl_autoload_register( array($this, 'load') );
        }
    
        function load( $file ) {
            if (is_file($this->path . '/' . $file . '.php')) {
                require_once( $this->path . '/' . $file . '.php' );
            }
        }
    }
    $autoloader_classes = new MyAutoLoader('CLASSES');
    $autoloader_admin = new MyAutoLoader('ADMIN/TPL/SOME_FOLDER2');
    

    If you don't want to manually keep the list of child folders inside ADMIN/TPL up to date you could even do something like this to autoload from any of them (this obviously assumes that all subfolders of ADMIN/TPL contains classes):

    function my_autoload($class_name) {
        if (is_file('CLASSES/' . $class_name . '.php')) {
            require_once 'CLASSES/' . $class_name . '.php';
        } else {
            $matching_files = glob('ADMIN/TPL/*/' . $class_name . '.php');
            if (count($matching_files) === 1) {
                require_once $matching_files[0];
            } else if (count($matching_files) === 0) {
                trigger_error('Could not find class ' . $class_name . '!', E_USER_ERROR);
            } else {
                trigger_error('More than one possible match found for class ' . $class_name . '!', E_USER_ERROR);
            }
        }
    }
    spl_autoload_register("my_autoload");