2013-03-27 7 views
8

Ich habe diese Autoloader Klasse automatisch zu laden classes zunächst, aber jetzt möchte ich automatisch zu laden interfaces und abstracts auch.PHP: wie automatisch zu laden Schnittstellen und Abstracts

Also machte ich die Änderung nach dieser 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'; 

} 

ich es getestet, aber diese Autoloader Klasse Schnittstellen gar nicht laden. Irgendwelche Ideen was ich verpasst habe?

Zum Beispiel, das ist mein Interface-Datei,

interface_methods.php 

und deren Inhalt,

interface methods 
{ 
    public function delete(); 
} 

Unten ist mein ganzes dieses Autoloader Klasse.

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; 
    } 
} 
+0

Vielleicht fehlt mir etwas, aber wie können Sie 'ReflectionClass' auf einer Klasse/Schnittstelle verwenden, die Sie noch nicht (automatisch) geladen haben? – Uby

+0

Sie haben Recht. vielleicht sollte ich 'ReflectionClass' nicht in der Autoload-Klasse verwenden. aber wie kann ich autoload-schnittstellen und abstracts ist das hauptproblem. – laukok

+2

Da es sich um Autoloading handelt, können Sie keine Reflektion verwenden. Sie sollten "erraten", wo die Datei nach Klassen-/Schnittstellennamen ist. Normalerweise ist Namenskonvention die Lösung. PRS-0 könnte eine Option für Sie sein: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md – Uby

Antwort

10

PHP macht keinen Unterschied zwischen Klassen oder Interfaces oder abstrakten Klassen. Die Autoloader-Funktion, die Sie definieren, erhält immer den Namen der zu ladenden Sache, und keine Art von Hinweis darauf, welche es war.

So kann Ihre Benennungsstrategie nicht automatisch geladen werden, weil Sie Interfaces mit "interface_" und Klassen mit "class_" voranstellen. Ich persönlich finde eine solche Namenskonvention eher ärgerlich.

Auf der anderen Seite ist Ihr Autoloader völlig unperformant. Es scannt ganze Verzeichnisbäume rekursiv, nur um eine Klasse zu finden! Und die nächste Klasse muss die ganze Arbeit wieder tun, ohne den Vorteil, dass sie es vorher getan hat!

Bitte implementieren Sie einen PSR-0 Autoloader, wenn Sie es wirklich selbst machen wollen (und nicht Dinge wie composer verwenden, um es für Sie zu tun) und bleiben Sie bei diesem Namensschema für Klassen und Schnittstellen.

Und bitte wählen Sie ein Unterscheidungsmerkmal Klassenname Präfix oder Namespace, und als ersten Schritt überprüfen Sie in Ihrem Autoloader, ob die Klasse, die geladen werden soll, dieses Präfix hat. Kehre sofort zurück, wenn dies nicht der Fall ist. Dies befreit Sie davon, die Festplatte zu drehen und zu sehen, ob der Dateiname für die Klasse existiert.

Wenn das Präfix nicht übereinstimmt, ist es nicht "Ihre" Klasse, die geladen werden möchte, also kann Ihr Autoloader nicht wissen, wie es geht und sollte nicht einmal versuchen, aber ein anderer Autoloader, der registriert wurde, wird es wissen.

Verwandte Themen