Wordpress - Problems with autoloading classes via sp_autoload_register / maybe interfering WP-specific autoloader

If you have unique namespace for your classes it works. I use this scheme:

  1. Stuff all your classes in namespace, let's say myplugin (you may have further namespaces of course, like myplugin\otherstuff\...

  2. Create autoloader that loads classes only in this namespace, you can can use this, put it on top of your plugin file:

    define("MYPLUGIN_DIR", plugin_dir_path(__FILE__));
    
    // Notice strlen(...) calls should be written as number for speed
    spl_autoload_register(function ($className) {           
        // Make sure the class included is in this plugins namespace
        if (substr($className, 0, strlen("myplugin\\")) === "myplugin\\") {
            // Remove myplugin namespace from the className
            // Replace \ with / which works as directory separator for further namespaces
            $classNameShort = str_replace("\\", "/", substr($className, strlen("myplugin\\")));
            include_once MYPLUGIN_DIR . "classes/$classNameShort.php";
        }
    });
    

That's it, it works fine for multiple plugins if you have different namespace for each (and you should anyway).


There is no built-in autoloader in WordPress. But other plugins or a theme might have registered an autoloader, and depending on the order of execution these are called earlier or later than yours.


Update 21. 08. 2014 This answer is no longer what I would recommend. Do use an autoloader if you need one.


The only way to make sure the called class is in your code’s responsibility is checking with file_exists() and testing the class name.

file_exists() is slow and its result is cached by the file system, so you cannot rely on it anyway.

I recommend not to use an autoloader. Use a plugin specific class loader instead.

Example:

/**
 * Load a class from /php/ directory.
 *
 * There is no file_exists() check to improve performance.
 *
 * @param  string  $class         Class name
 * @param  boolean $create_object Return an object or TRUE
 * @return bool|$class
 */
function t5_es_load_class( $class, $create_object = FALSE )
{
    // create the path base just once
    static $base = FALSE;

    ! $base && $base = plugin_dir_path( __FILE__ ) . 'php';
    ! class_exists( $class ) && require "$base/class.$class.php";

    return $create_object ? new $class : TRUE;
}

Now you can use this function either to just include the class …

t5_es_load_class( 'T5_Metabox_Base' );
$metabox = new T5_Metabox_Base( 'preview' );

… or create an object …

$data               = t5_es_load_class( 'T5_Property_List', TRUE );
$data->plugin_url   = plugin_dir_url( __FILE__ );
$data->plugin_path  = plugin_dir_path( __FILE__ );

Faster, more reliable, more flexible.