Question

I am using __autoload in my script to include classes as needed. My script uses cues in the class name to find the file containing it. If it ends in model it is in the model directory, controllers are in the controller directory, etc. I am starting to implement interfaces, and so need to adjust my autoloader.

Ideally, when an object is created the autoloader would determine the file-name of the object, where it is stored, and include the file. Then it would interrogate that class for what interfaces it implements, and then include those files automatically.

Something like

function __autoload($classname){
    echo $classname;
    include ("classes/$classname.php");
    $interfaces = class_implements($classname,FALSE);
    foreach($interfaces as $name){
        if(!class_exists($name,FALSE)){
        include("interfaces/".$name."inter.php");
        }
    }
}

Except when I do that I get the error

Cannot redeclare __autoload() (previously declared in W:\xampp\htdocs\test\auto.php:5) in W:\xampp\htdocs\test\auto.php on line 11

is it not possible to do this in the __autoload()? Should I just continue relying on naming conventions to differentiate between types of objects and where they are stored?

Was it helpful?

Solution

You cannot define a class, before the implemented interfaces are defined and additional any unknown interface will trigger the autoload function too. This means in line 3 when including the class it will trigger the autoload function again with the interfaces as $classname. Now when returning from the second __autoload()-call it will try to include the interfaces once more, which will fail because of "already defined".

Additional: Using __autoload() is deprecated against using spl_autoload_register()

OTHER TIPS

Use spl_autoload_register to register additional autoload functions. The autoload function you specify is a callback. That means you can pass it a method or class method. That way, you can add the extra autoloads to your various classes without having to fear for naming conflicts.

[edit]

It won't work this way. See the smart answer of KingCrunch.

Even if this would work, I 'd advise against it. By having a single autoload function, or maybe additional autoload functions per library or framework you use, you keep autoloading plain and simple. Adding extra functions may make debugging overly complex.

Since you're already relying on naming conventions for classes, just mod your existing __autoload to parse interface names too. If you name all your interfaces "I_something", it should be a straightforward change.

If you don't want to rely on naming conventions then you'll need to set up some kind of class and interface registry. The registry can be as simple as a hardcoded array, something like:

function __autoload($classname) {
    $classlist=array('MyClass1','path/to/file/myclass1.php',
                          'MyClass2','path/to/file/foo.php',
...
                         );

    $interfacelist=array('MyInterface1','path/to/file/bar1.php',
                              'I_foo','path/to/file/bibble.php',
...
                         );
            $path=$classname;
            if(array_key_exists($classname,$classlist)) {
                $path=PATH_CLASSES.$classlist[$classname];
            } else if(array_key_exists($classname,$interfacelist)) {
                $path=PATH_INTERFACES.$interfacelist[$classname];
            }
            if(file_exists($path)) {
                require_once($path);
            } else {
                $e=new Exception("Problem with path: $path");
            }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top