I have this autoloader class to autoload classes
initially, but now I want to autoload interfaces
and abstracts
as well.
So I made the change following this answer,
$reflection = new ReflectionClass($class_name);
# Return boolean if it is an interface.
if ($reflection->isInterface())
{
$file_name = 'interface_'.strtolower(array_pop($file_pieces)).'.php';
}
else
{
$file_name = 'class_'.strtolower(array_pop($file_pieces)).'.php';
}
I tested it but this autoloader class does not load interfaces at all. Any ideas what I have missed?
For instance, this is my interface file,
interface_methods.php
and its content,
interface methods
{
public function delete();
}
Below is my entire this autoloader class.
class autoloader
{
/**
* Set the property.
*/
public $directory;
public $recursive;
public function __construct($directory, $recursive = array('search' => 'models') )
{
# Store the data into the property.
$this->directory = $directory;
$this->recursive = $recursive;
# 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(array($this,'get_class'));
}
private function get_class($class_name)
{
# List all the class directories in the array.
if ($this->recursive)
{
$array_directories = self::get_recursive_directory($this->directory);
}
else
{
if (is_array($this->directory)) $array_directories = $this->directory;
else $array_directories = array($this->directory);
}
# Determine the class is an interface.
$reflection = new ReflectionClass($class_name);
$file_pieces = explode('\\', $class_name);
# Return boolean if it is an interface.
if ($reflection->isInterface())
{
$file_name = 'interface_'.strtolower(array_pop($file_pieces)).'.php';
}
else
{
$file_name = 'class_'.strtolower(array_pop($file_pieces)).'.php';
}
# Loop the array.
foreach($array_directories as $path_directory)
{
if(file_exists($path_directory.$file_name))
{
include $path_directory.$file_name;
}
}
}
public function get_recursive_directory($directory)
{
$iterator = new RecursiveIteratorIterator
(
new RecursiveDirectoryIterator($directory),
RecursiveIteratorIterator::CHILD_FIRST
);
# This will hold the result.
$result = array();
# Loop the directory contents.
foreach ($iterator as $path)
{
# If object is a directory and matches the search term ('models')...
if ($path->isDir() && $path->getBasename() === $this->recursive['search'])
{
# Add it to the result array.
# Must replace the slash in the class - dunno why!
$result[] = str_replace('\\', '/', $path).'/';
//$result[] = (string) $path . '/';
}
}
# Return the result in an array.
return $result;
}
}
The spl_autoload_register() function registers any number of autoloaders, enabling for classes and interfaces to be automatically loaded if they are currently not defined. By registering autoloaders, PHP is given a last chance to load the class or interface before it fails with an error.
Classes may implement more than one interface if desired by separating each interface with a comma. A class can implement two interfaces which define a method with the same name, only if the method declaration in both interfaces is identical.
PHP - Interfaces vs. All interface methods must be public, while abstract class methods is public or protected. All methods in an interface are abstract, so they cannot be implemented in code and the abstract keyword is not necessary. Classes can implement an interface while inheriting from another class at the same ...
Basically it says: "inside this directory, all namespaces are represented by sub directories and classes are <ClassName>. php files." Autoloading is PHP's way to automatically find classes and their corresponding files without having to require all of them manually.
PHP makes no difference between any class or interface or abstract class. The autoloader function you define always gets the name of the thing to autoload, and no kind of hint which one it was.
So your naming strategy cannot be autoloaded because you prefix interfaces with "interface_" and classes with "class_". Personally I find such a naming convention rather annoying.
On the other hand, your autoloader is completely unperformant. It scans whole directory trees recursively just to find one class! And the next class has to do all the work again, without the benefit of having done it before!
Please do implement a PSR-0 autoloader if you really want to do it on your own (and not use things like composer to do it for you) and stick to this naming scheme for classes and interfaces.
And please select a distinguishing classname prefix or namespace, and as a first step check inside your autoloader if the class to be loaded has this prefix. Return instantly if it has not. This frees you from having to spin the harddrive and see if the filename for the class exists.
If the prefix does not match, it is not "your" class that wants to be loaded, so your autoloader cannot know how to do it and shouldn't even try, but a different autoloader that was registered will know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With