1

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

vahed
  • 161
  • 1
  • 2
  • 12
  • **ATTENTION VISITORS:** please do not use answers below. the entire approach in the question and the answers is horribly wrong. Please follow the duplicate link at the top instead – Your Common Sense Mar 31 '21 at 06:02

2 Answers2

6

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");
Mikk3lRo
  • 3,477
  • 17
  • 38
1

Your problem may actually be as simple as this:

Your basics.php is inside the folder CLASSES, so when you include or require files from within basics.php it starts in that folder.

So if you want to include files from ADMIN/TPL/SOME_FOLDER2 you actually need to "jump" up one level first, ie require '../ADMIN/TPL/SOME_FOLDER2/' . $file . '.php';

To avoid this kind of confusion I would recommend adding a constant to the beginning of index.php like this:

define('BASEPATH', __DIR__);

...and then prepending that to all require and include statements - ie:

class MyAutoLoader {
    public function __construct() {
        spl_autoload_register( array($this, 'load') );
        spl_autoload_register( array($this, 'load2') );
    }
    function load( $file ) {
        echo 'Try to call  ' . $file . '.php inside ' . __METHOD__ . '<br>';
        $classfile = BASEPATH . '/CLASSES/' . $file . '.php';
        if ( is_file( $classfile ) ) {
            require( $classfile );
        }
    }
    function load2( $file ) {
        echo 'Try to call  ' . $file . '.php inside ' . __METHOD__ . '<br>';
        $classfile = BASEPATH . '/ADMIN/TPL/SOME_FOLDER2/' . $file . '.php';
        if ( is_file( $classfile ) ) {
            require( $classfile );
        }
    }
}
Mikk3lRo
  • 3,477
  • 17
  • 38