views:

64

answers:

4

Hey everyone,

I am trying to convert several php scripts to use the __autoload function. Right now I can use the include and require functions like this:

require_once('path/to/script.php');

But inside of the __autoload function, I can't use the line above. I have to use this:

require_once('absolute/path/to/script.php');

Why does it seem as though the __autoload function doesn't use the include path I have specified in php.ini?

A: 

Not sure without seeing the whole set-up. My autoload function is within my global functions file, and looks like this:

function __autoload($class) {
    if (file_exists("includes/{$class}.php")) {
        require_once("includes/{$class}.php");
    }
    /**
     * Add any additional directories to search in within an else if statement here
     */
    else {
        // handle error gracefully
    }
}

I use a relative path because the script is included in my index.php file and all HTTP requests are passed through it.

Martin Bean
It seems like part of your answer was cut off for some reason. The part after "because" is missing.
nikic
Thanks! Don't know what happened there.
Martin Bean
A: 

I suspect your __autoload() function is in a separate file then the code which calls it. The path to the included files will be relative to the file which the __autoload() function declaration resides.

John Conde
I thought that too, but then I used the setting in the php.ini file called "auto_prepend_file" and the file that contained the __autoload function in the folder where all the relative paths begin and it still wouldn't work.
TheGNUGuy
-1 because I think this answer is wrong (correct me, if it is I, who is wrong): As far as I know the file is included relative to the exeucted script. That is, if an index.php is called, but the autoload resides in foo/bar/autoload.php, still the path would be resolved relative to index.php. PHP will only fall back to foo/bar as the very last step, after trying all include_paths.
nikic
+1  A: 

Don't use __autoload... It has a few drawbacks (including limiting yourself to one per execution). Use instead spl_autoload_register if you're on 5.2+.

So what I typically do, is have a class:

class AutoLoader {
    protected static $paths = array(
        PATH_TO_LIBRARIES,
    );
    public static function addPath($path) {
        $path = realpath($path);
        if ($path) {
            self::$paths[] = $path;
        }
    }
    public static function load($class) {
        $classPath = $class; // Do whatever logic here
        foreach (self::$paths as $path) {
            if (is_file($path . $classPath)) {
                require_once $path . $classPath;
                return;
            }
        }
    }
}
spl_autoload_register(array('AutoLoader', 'load'));

That way, if you add a library set, you can just "add it" to your paths by calling AutoLoader::AddPath($path);. This makes testing with your autoloader a LOT easier (IMHO).

One other note. Don't throw exceptions from the autoload class unless absolutely necessary. The reason is that you can install multiple autoloaders, so if you don't know how to load the file, another one may exist to load it. But if you throw an exception, it'll skip the other one...

Personally, I don't ever like to use relative paths with includes. Especially with multiple include directories (like pear), it makes it very difficult to know exactly which file is being imported when you see require 'foo/bar.php';. I prefer to define the absolute path in the beginning of the file set define('PATH_ROOT', dirname(__FILE__));, and then define all my other useful paths off of that directory (PATH_LIBRARIES, PATH_TEMPLATES, etc...). That way, everything is absolutely defined... And no need to deal with relative paths (like the issue you're having now)...

ircmaxell
A: 

It seems like . is not in your include path. So add it use:

set_include_path('.' . PATH_SEPARATOR . get_include_path());

Now PHP should look relative to the executed scripts directory, too. (Executed script here is something like index.php, not autoload.php.

But why don't use simply use a normal relative path like ./path/to/class.php?

nikic
`.` is in the path already. `.` is relative to the current working directory of the current file (in other words, it's equivalant to `dirname(__FILE__)`)... That's why it works fine from one file but not the other (because the relative working directory changes between them)...
ircmaxell
@ircmaxell: And you are **really** sure, that what you say is right? I had the experience, that PHP regards the directory as cwd, there the *originally* executed script lies, not there the file you include from lies. [More information (though German)](https://www.lima-city.de/thread/inclusion-path-resolution) and my [Path resolution class](http://github.com/nikic/prephp/blob/master/prephp/classes/Path.php). (The resolution class isn't yet perfect, though.)
nikic