Maxiumum

So i have started undertaking a task to build re-usable components. The first one i attempted to write is a Loader and all was going well just fixing some bugs from my test cases. And now i have an error for the life of me i cannot figure out where i went wrong.

All classes listed below.

bootstrap.php



/* root path */
define('PATH', str_replace('\\\\' , '/' , getcwd()) . '/');

/* root path */
define('PATH', str_replace('\\\\' , '/' , getcwd()) . '/');

/* loader namespace */
use Elements\\Loader as Loader;

/* get the autoload class */
require PATH . 'Loader/Autoload.php';

/* attempt to register  our firt class*/
$autoloader = new Loader\\Autoload;

/* register the class for autoloading
 * $autoloader->register('classname' , 'path to teh class' , 'class prefix or namespace') */
$autoloader->register('LoaderTest', PATH . 'Tests/LoaderTest' , 'Elements\\Tests');



autoloader.php


// the loader namespace
namespace Elements\\Loader;

// get the abstract loader
require 'Loader.php';

class Autoload extends Loader{
	
	// the autoload method using loader request method to load the class
	public function load($class){
		 $this->request($class);
	}
	
	// register the current autoloader
	public function start(){
		return \\spl_autoload_register(array($this => 'load'));
	}
	
	// regsiter class for autoloading
	public function register($class, $path , $prefix = ''){
		$this->register($prefix.$class, $path);
	}
}

abstract loader.php


namespace Elements\\Loader;

abstract class Loader{
	
	protected $_classes = array();
	
	abstract protected function load($class);
	
	protected function register(array $classes = array() , $overwrite = FALSE){
		if(! \\is_array($classes)){
			return FALSE;
		}
		
		if($overwrite === FALSE){
			$matched = \\array_intersect_assoc($classes , $this->classes);
			
			foreach($macthed as $key => $value){
				unset($classes[$key]);
			}
		}
		
		
		$this->_classes = \\array_merge($classes, $this->_classes);
		return TRUE;
	}
	
	protected function request($class , $return_obj = FALSE){
		if(!\\class_exists($class) or !\\interface_exists($class)){
			if(isset($this->_classes[$class])){
				$class = \\str_replace('.php' , '', $this->_classes[$class]);
				if(\\file_exists(\	rim($class, '/'). '.php')){
					require \	rim($class, '/') . '.php';
				}
			}
			
			if(\\class_exits($class, FALSE) or \\interface_exists($class, FALSE)){
				if($return_obj  === FALSE){
					return TRUE;
				}
				
				else{
					return new $class();
				}
			}
					
			else{
				exit("Loader Exception: could not load the requested class {$class}");
			}
		}
		
		return TRUE;
	}
	
	protected function delete($class){
		if(isset($this->_classes[$class])){
			unset($this->_classes[$class]);
			return TRUE;
		}
		
		return FALSE;
	}
	
	protected function getClasses(){
		return $this->_classes;
	}
	
}

What error are you getting?

Fatal error: Maximum function nesting level of ‘100’ reached

Hmm, out of curiosity, try changing any requires/includes to require_once/include_once and see what happens.

Actually, after (briefly) scanning through your code, you may want to take a look at:


// regsiter class for autoloading
    public function register($class, $path , $prefix = ''){
        $this->register($prefix.$class, $path);
    } 

I see this error most often with recursive functions that end up infinitely calling itself.

Seems quite complicated for something that can be so much simpler…If you have a simple naming scheme where namespace + class name form the directory structure then you can do just that. Or if you really need an index here are two ways to do it: Or at least how I would go about doing it. (PHP 5.3 or 5.4 required)


<?php

function __load ()
{
  spl_autoload_register(
    function ( $class ) {
      // Assuming this autoload file is at the root of the library.
      //   (lib/Zend/.load.php for example.) adjust __DIR__ accordingly
      $path = preg_replace( '~[/\\\\\\\\_]+~', '/', __DIR__ . "/$class.php" );
      if ( file_exists( $path ) )
        include $path;
    }
  );
}

__load();

#-------------------------------------------------------------------------------

function __load ()
{
  static $index;
  if ( !isset( $index ) ) {
    // Build the index here, any method you like.
    $index = array(
      'name\\space\\plus\\class\
ame' => '/path/to/class/name.php',
      'name\\space\\plus\\class\
ame2' => '/path/to/class/name2.php'
    );
  }
  
  spl_autoload_register(
    function ( $class ) use ( $index ) {
      if ( !isset( $index[ $class ] ) )
        return;
      
      // Assuming this autoload file is at the root of the library.
      //   (lib/Zend/.load.php for example.) adjust __DIR__ accordingly
      $path = $index[ $class ];
      $path = preg_replace( '~[/\\\\\\\\]+~', '/', __DIR__ . "/$path" );
      if ( file_exists( $path ) )
        include $path;
    }
  );
}

__load();

In production, if you are using an index I recommend you hardcode the classes to the path in the above array instead of dynamically at run time. Having it hardcoded is one more thing opcode can have an easier time caching.

Furthermore, spl_autoload takes care of determining if a class/interface exists and handles exception throwing, so you do not need to concern yourself with those.

That is a very interesting take on auto-loading by namespace. I truly admire the anonymous function route. I agree about the logic of this being extensive and maybe overly separated but the autoloader is only 1 supported driver. I also must support drivers for single class loading instances such as load by namespace, by directory, by PSR-0 standards. Thanks for the advice and the help with my error caused from recursion.