spl_autoload_register issues

Hey,

I’m using spl_autoload_register in the incorrect manner it seems.


spl_autoload_register(array(__CLASS__, 'loadController'));
spl_autoload_register(array(__CLASS__, 'loadMapper'));

I have two static functions who have the correct path depending on the loader needed. The problem I’m having is that all required classes are going through the first loader only and throws a fatal error. Thus not allowing the second loader to execute. The way I have it understood is that spl_autoload allows stack able autoloaders.

Any one see where I went wrong?

Are your methods correctly returning false on an supported object request?

I’m not sure I’m understanding you correctly. Where exactly am I suppose to be returning false?

Originally this is what I had


/**
* First Attempt
*/
public static function register() {
    return spl_autoload_register(array(__CLASS__, 'loadController'),
                                           array(__CLASS__, 'loadMapper')
                                          );
}

/**
* First attempt didn't seem to work as expected so this kinda worked but it throws a fatal error if it can't load it within the first loader
*/

public static function register() {
    spl_autoload_register(array(__CLASS__, 'loadController'));
    spl_autoload_register(array(__CLASS__, 'loadMapper'));
}

public static function loadController($className) {
    //etc
}

public static function loadMapper($className) {
    //etc
}

And in my index file, I just instantiate an object of this class and do FrontController::register();

Where would I return false if needed?

As per the manual, your function(s) must return true on success or false on failure.

So, given your example, these would be the loadController and loadMapper methods.

So after I do the require I return true? That’s kinda odd don’t you think?

Something like this?


public static function loadController($className) {
    $file = $_SERVER['DOCUMENT_ROOT'].'/path/to/app/'.$className.'.php';

    if (file_exists($file) {
        require_once $file;
        return true;
    }
    return false;
} 

If this is correct then this is a little crazy.

If you take a look at my first attempt, wouldn’t spl_autoload_register work that way? Or would you think that it would need to be done like the 2nd attempt?

Odd? Not really, you have to supply a valid call back and your first attempt wasn’t. :slight_smile:

If I follow your code correctly, I’d be more inclided to do something like to following…


class ApplicationAutoloader
{
    static public function Register(){
        return spl_autoload_register(
            array(
                __CLASS__,
                'Load'
            )
        );
    }
    
    static public function Load($objectname){
        foreach(array('models', 'controllers') as $type){
            $file = APPLICATION_ROOT . DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR . $name . '.php';
            if(true === file_exists($file)){
                require_once($file);
                return true;
            }
        }
        return false;
    }
}

ApplicationAutoloader::Register();

where did the variable $name come from? Did you mean $objectname ?

And why is it an object? Isn’t spl_autoload looking for a class (name)?

Sorry, yup, typo. It should indeed be $objectname.

It can also look for interfaces, hence $objectname and not $classname. :smiley:

Right on.

I’m failing to see where the call back is here? I’m familiar with javascript call backs but it’s a no go for PHP.

On another note. I always define APPLICATION_ROOT myself for every project. Is this not necessary ? Is this constant already predefined by PHP?

Just to clarify, the registered autoload functions do not have to return true/false based on whether they have loaded the class or not. After executing each autoloader, the next autoloader only gets tried if the class does not exist.

Anthony may have gotten confused with the return values of the spl_autoload_register function itself, which will return false if called with the second parameter ($throw) as false (i.e. do not throw exceptions).

If that’s the case, then why didn’t spl_autoload_register recognize that there was a second loader that it could have tried instead of hanging up on the first one?

Thanks Salathe, I was indeed doing exactly that. :blush:

Here is a working example of what your trying to do. I’ve left the true and false return values in there, but as previously stated they are not required by spl_autoload_* to function.


<?php
error_reporting(-1);
ini_set('display_errors', true);

class Autoloader
{
    static public function Register(){
        #register model loader
        spl_autoload_register(
            array(
                __CLASS__,
                'loadModel'
            )
        );
        
        #register controller loader
        spl_autoload_register(
            array(
                __CLASS__,
                'loadController'
            )
        );
    }
    
    static public function loadModel($object){
        $file = sprintf('models/model.%s.php', $object);
        if(true === file_exists($file)){
            require_once($file);
            return true;
        }
        return false;
    }
    
    static public function loadController($object){
        $file = sprintf('controllers/controller.%s.php', $object);
        if(true === file_exists($file)){
            require_once($file);
            return true;
        }
        return false;
    }
}

Autoloader::Register();

$account = new Account();

That seems to work, I appreciate the response. I’m not sure where I went wrong with my second attempt, but I will go through it again.

Thank you really much! You helped me out of the problems.