phpslimautoloaderzend-autoloaderspl-autoloader

Slim framework - How to autoload Slim/Slim.php instead of using require?


How can I autoload Slim/Slim.php instead of using require?

// standard method
//require 'ext/Slim/Slim.php'; 

// autoload method:     
define ('WEBSITE_DOCROOT', str_replace('\\', '/', dirname(__FILE__)).'/');

// Instance of SplAutoload.
$SplAutoload = new SplAutoload();

// Load classes.
$SplAutoload->fetch([
    'ext/' // Slim/ is kept under ext/
]);

\Slim\Slim::registerAutoloader();

//Instantiate a Slim application:
$app = new \Slim\Slim();

//Define a HTTP GET route:
$app->get('/', function () {
    echo "Hello!";
});

$app->get('/hello/:name/', function ($name) {
    echo "Hello, $name";
});

//Run the Slim application:
$app->run();

I get this error,

Fatal error: Class 'Slim\Slim' not found in C:...

the SplAutoload class,

class SplAutoload
{
    /**
     * Set the property.
     */
    public $directories;

    public function fetch($directories) 
    {
        // Store the data into the property.
        $this->directories = $directories;

        // Register the classes that were loaded by __autoload as well.
        spl_autoload_register('__autoload');

        // When using spl_autoload_register() with class methods, it might seem that it can use only public methods, 
        // though it can use private/protected methods as well, if registered from inside the class:
        spl_autoload_register([$this,'getClass']);
    }

    private function getClass($className)
    {
        if(is_array($this->directories)): $mainDirectories =  $this->directories;
        else: $mainDirectories =  array($this->directories); endif;

        // Set other vars and arrays.
        $subDirectories = [];
        //print_r($mainDirectories);

        $namespace = "\\";
        $isNamespace = false;

        // When you use namespace in a class, you get something like this when you auto load that class \foo\tidy.
        // So use explode to split the string and then get the last item in the exloded array.
        $parts = explode($namespace, $className);

        // Check if the current class is a namespace class or not.
        if(strpos($className, $namespace) !== false) 
        {
            $isNamespace = true;
        }

        // Set the class file name.
        $filename = end($parts).'.php';

        // List any sub dirs in the main dirs above and store them in an array.
        foreach($mainDirectories as $mainDirectory)
        {
            // Check if the directory exists.
            // Create it if it doesn't.
            if (!file_exists(WEBSITE_DOCROOT.$mainDirectory)) 
            {
                mkdir(WEBSITE_DOCROOT.$mainDirectory, 0777);
            }

            // Must use absolute path to get the files when ajax is used.
            foreach(glob(WEBSITE_DOCROOT.$mainDirectory.'*', GLOB_ONLYDIR) as $dir) 
            {
                // Must trim off the WEBSITE_DOCROOT. 
                $subDirectories[] = preg_replace('~.*?(?=core|local)~i', '', str_replace('\\', '/', $dir)) .'/';
            }
        }

        // Mearge the main dirs with any sub dirs in them.
        $mergedDirectories = array_merge($mainDirectories,$subDirectories);

        // Loop the merge array and include the classes in them.
        foreach($mergedDirectories as $mainDirectory)
        {
            if(file_exists(WEBSITE_DOCROOT.$mainDirectory.$filename))
            {
                include_once WEBSITE_DOCROOT.$mainDirectory.$filename;

                // Check if the class has existed.
                if($isNamespace === false) if (class_exists($className)) break;
            }
        }
    }
}

or any other SPL autoloader that I should go for? zend-autoloader?


Solution

  • With the way your autoloader handles namespaces, you'll need to use this:

    $SplAutoload->fetch([
        'ext/Slim/' // Slim/ is kept under ext/
    ]);
    

    or change your autoloader so it includes the namespace as a directory.