it-swarm.com.de

Autoload Klassen aus verschiedenen Ordnern

So lade ich automatisch alle Klassen in meinem controllers Ordner,

# auto load controller classes
    function __autoload($class_name) 
    {
        $filename = 'class_'.strtolower($class_name).'.php';
        $file = AP_SITE.'controllers/'.$filename;

        if (file_exists($file) == false)
        {
            return false;
        }
        include ($file);
    }

Aber ich habe auch Klassen im Ordner models und ich möchte sie auch automatisch laden - was soll ich tun? Sollte ich den obigen Autoload duplizieren und einfach den Pfad in models/ Ändern (aber ist das nicht eine Wiederholung?)?

Vielen Dank.

EDIT:

dies sind meine Klassendateinamen im Controller-Ordner:

class_controller_base.php
class_factory.php
etc

dies sind meine Klassendateinamen im Modellordner:

class_model_page.php
class_model_parent.php
etc

so benenne ich meine Controller-Klassen normalerweise class (ich verwende Unterstriche und Lowcaps),

class controller_base 
{
...
}

class controller_factory
{
...
}

so benenne ich meine Modellklassen normalerweise class (ich benutze Unterstriche und Lowcaps),

class model_page 
    {
    ...
    }

    class model_parent
    {
    ...
    }
42
laukok

Sie sollten Ihre Klassen so benennen, dass der Unterstrich (_) In das Verzeichnis-Trennzeichen (/) Übersetzt wird. Einige PHP Frameworks wie Zend und Kohana tun dies.

Benennen Sie also Ihre Klasse Model_Article Und platzieren Sie die Datei in classes/model/article.php. Dann führt Ihr Autoload ...

function __autoload($class_name) 
{
    $filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)).'.php';

    $file = AP_SITE.$filename;

    if ( ! file_exists($file))
    {
        return FALSE;
    }
    include $file;
}

Beachten Sie auch, dass Sie spl_autoload_register() verwenden können, um jede Funktion zu einer Autoloading-Funktion zu machen. Es ist auch flexibler und ermöglicht Ihnen das Definieren mehrerer Autoload-Funktionen.

Wenn es mehrere Autoload-Funktionen geben muss, ermöglicht spl_autoload_register () dies. Es erstellt effektiv eine Warteschlange mit Autoload-Funktionen und durchläuft sie in der Reihenfolge, in der sie definiert sind. Im Gegensatz dazu darf __autoload () nur einmal definiert werden.

Bearbeiten

Hinweis: __ autoload wurde als PHP= 7.2.0. Unter Berufung auf Von dieser Funktion wird dringend abgeraten. Weitere Informationen finden Sie in der PHP Dokumentation. http://php.net/manual/en/function.autoload.php

27
alex

Ich sehe, dass Sie controller_***** Und model_***** Als Klassennamenskonvention verwenden.

Ich habe einen fantastischen Artikel gelesen, der eine alternative Namenskonvention mit PHPs namespace vorschlägt.

Ich liebe diese Lösung, weil es keine Rolle spielt, wo ich meine Klassen platziere. Das __autoload Findet es, egal wo es sich in meiner Dateistruktur befindet. Es erlaubt mir auch, meine Klassen so zu nennen, wie ich will. Ich benötige keine Klassennamenskonvention, damit mein Code funktioniert.

Sie können beispielsweise Ihre Ordnerstruktur wie folgt einrichten:

  • anwendung/
    1. controller /
      • Base.php
      • Factory.php
    2. modelle/Reifen.____.]
      • Seite.php
      • Parent.php

Ihre Klassen können wie folgt eingerichtet werden:

<?php
namespace application\controllers;
class Base {...}

und:

<?php
namespace application\models;
class Page {...}

Der Autoloader könnte so aussehen (oder am Ende einen Hinweis zum Autoloaden sehen):

function __autoload($className) {
    $file = $className . '.php';
    if(file_exists($file)) {
        require_once $file;
    }
}

Dann ... können Sie Klassen auf drei Arten aufrufen:

$controller = new application\controllers\Base();
$model = new application\models\Page();

oder,

<?php
use application\controllers as Controller;
use application\models as Model;

...

$controller = new Controller\Base();
$model = new Model\Page();

oder,

<?php
use application\controllers\Base;
use application\models\Page;

...

$controller = new Base();
$model = new Page();

EDIT - ein Hinweis zum automatischen Laden:

Mein Haupt-Autolader sieht so aus:

// autoload classes based on a 1:1 mapping from namespace to directory structure.
spl_autoload_register(function ($className) {

    # Usually I would just concatenate directly to $file variable below
    # this is just for easy viewing on Stack Overflow)
        $ds = DIRECTORY_SEPARATOR;
        $dir = __DIR__;

    // replace namespace separator with directory separator (prolly not required)
        $className = str_replace('\\', $ds, $className);

    // get full name of file containing the required class
        $file = "{$dir}{$ds}{$className}.php";

    // get file if it is readable
        if (is_readable($file)) require_once $file;
});

Dieser Autoloader ist eine direkte 1: 1-Zuordnung des Klassennamens zur Verzeichnisstruktur. Der Namespace ist der Verzeichnispfad und der Klassenname ist der Dateiname. Die oben definierte Klasse application\controllers\Base() würde also die Datei www/application/controllers/Base.php Laden.

Ich habe den Autoloader in eine Datei namens bootstrap.php gestellt, die sich in meinem Stammverzeichnis befindet. Dies kann entweder direkt einbezogen werden, oder die php.ini kann in auto_prepend_file geändert werden, sodass sie bei jeder Anfrage automatisch einbezogen wird.

Mit spl_autoload_register können Sie mehrere Autoload-Funktionen registrieren, um die Klassendateien nach Belieben zu laden. Dh, Sie könnten einige oder alle Ihre Klassen in einem Verzeichnis ablegen, oder Sie könnten einige oder alle Ihrer Klassen mit Namensraum in einer Datei ablegen. Sehr flexibel :)

61
br3nt

Ich muss etwas über "gute" Autoload-Skripte und die Codestruktur erwähnen, lesen Sie also das Folgende VORSICHTIG


Merken Sie sich:

  • Klassenname === Dateiname
  • Nur EINE Klasse pro Datei

z.B.: Example.php enthält

class Example {}
  • Namespace === Verzeichnisstruktur

beispiel: /Path1/Path2/Example.php entspricht

namespace Path1\Path2;
class Example {}
  • Es SOLLTE einen Root-Namespace geben, um Kollisionen zu vermeiden

beispiel: /Path1/Path2/Example.php mit root:

namespace APP\Path1\Path2;
class Example {}
  • NIEMALS manuell definierte Pfad- oder Verzeichnislisten verwenden, sondern den Loader auf das oberste Verzeichnis richten
  • Halten Sie den Lader so schnell wie möglich (weil das Einfügen einer Datei teuer genug ist)

In diesem Sinne habe ich das folgende Skript erstellt:

function Loader( $Class ) {
    // Cut Root-Namespace
    $Class = str_replace( __NAMESPACE__.'\\', '', $Class );
    // Correct DIRECTORY_SEPARATOR
    $Class = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, __DIR__.DIRECTORY_SEPARATOR.$Class.'.php' );
    // Get file real path
    if( false === ( $Class = realpath( $Class ) ) ) {
        // File not found
        return false;
    } else {
        require_once( $Class );
        return true;
    }
}

Wo man es platziert ..

  • /Loader.php <- da geht der Loader
  • / Controller/... <- lege deine Sachen hier ab
  • / Model/... <- oder hier, etc
  • / ...

Erinnern Sie sich:

  • wenn Sie einen Root-Namespace verwenden, muss sich der Loader ebenfalls in diesem Namespace befinden
  • sie können $ Class entsprechend Ihren Anforderungen voranstellen (controller_base {} -> class_controller_base.php)
  • sie können __DIR__ in einen absoluten Pfad ändern, der Ihre Klassendateien enthält (z. B. "/ var/www/classes").
  • wenn Sie keine Namespaces verwenden, müssen sich alle Dateien zusammen mit dem Loader im selben Verzeichnis befinden (schlecht!)

Fröhliches Codieren ;-)


Ein kleiner Rückblick auf andere Antworten: DIESE IS NUR MEINE PERSÖNLICHE MEINUNG - KEINE VERSTÖSSLICHUNG VORGESEHEN!

https://stackoverflow.com/a/5280353/626731 @alex Gute Lösung, aber lassen Sie Klassennamen nicht für schlechte Dateistrukturen bezahlen ;-) Dies ist ein Job für Namespaces

https://stackoverflow.com/a/5280510/626731 @ Mark-Eirich es funktioniert, aber sein ziemlich böser/hässlicher/langsamer/steifer [..] Stil macht es so ..

https://stackoverflow.com/a/5284095/626731 @tealou für sein zu lösendes Problem ist dies der bisher klarste Ansatz :-) ..

https://stackoverflow.com/a/9628060/626731 @br3nt dies spiegelt meinen Standpunkt wider, aber bitte (!) .. benutze nicht strtr !! .. das bringt mich zu:

https://stackoverflow.com/a/11866307/626731 @Iscariot .. für Sie ein kleiner "Sie-wissen-Bullshit-Benchmark":

Time        sprintf preg_replace strtr    str_replace v1 str_replace v2
08:00:00 AM 1.1334  2.0955       48.1423  1.2109         1.4819
08:40:00 AM 1.0436  2.0326       64.3492  1.7948         2.2337
11:30:00 AM 1.1841  2.5524       62.0114  1.5931         1.9200
02:00:00 PM 0.9783  2.4832       52.6339  1.3966         1.4845
03:00:00 PM 1.0463  2.6164       52.7829  1.1828         1.4981
Average     1.0771  2.3560       55.9839  1.4357         1.7237


Method         Times Slower (than sprintf)
preg_replace   2.19
strtr          51.97
str_replace v1 1.33
str_replace v2 1.6

Quelle: http://www.simplemachines.org/community/index.php?topic=175031.

Fragen? .. (Aber er hat in der Tat Recht über den vollständigen Pfad einschließlich)

https://stackoverflow.com/a/12548558/626731 @ Sunil-Kartikey https://stackoverflow.com/a/17286804/626731 @jurrien

NIEMALS in einer zeitkritischen Umgebung schleifen! Suchen Sie nicht nach Dateien auf os! - SCHLEPPEND

https://stackoverflow.com/a/21221590/626731 @sagits .. viel besser als Marks ;-)

7
DerDu
function autoload($className)
{
//list comma separated directory name
$directory = array('', 'classes/', 'model/', 'controller/');

//list of comma separated file format
$fileFormat = array('%s.php', '%s.class.php');

foreach ($directory as $current_dir)
{
    foreach ($fileFormat as $current_format)
    {

        $path = $current_dir.sprintf($current_format, $className);
        if (file_exists($path))
        {
            include $path;
            return ;
        }
    }
}
}
spl_autoload_register('autoload');
4
Sunil Kartikey

Hier ist meine Lösung,

/**
     * autoload classes 
     *
     *@var $directory_name
     *
     *@param string $directory_name
     *
     *@func __construct
     *@func autoload
     *
     *@return string
    */
    class autoloader
    {
        private $directory_name;

        public function __construct($directory_name)
        {
            $this->directory_name = $directory_name;
        }

        public function autoload($class_name) 
        { 
            $file_name = 'class_'.strtolower($class_name).'.php';

            $file = AP_SITE.$this->directory_name.'/'.$file_name;

            if (file_exists($file) == false)
            {
                return false;
            }
            include ($file);
        }
    }

    # nullify any existing autoloads
    spl_autoload_register(null, false);

    # instantiate the autoloader object
    $classes_1 = new autoloader('controllers');
    $classes_2 = new autoloader('models');

    # register the loader functions
    spl_autoload_register(array($classes_1, 'autoload'));
    spl_autoload_register(array($classes_2, 'autoload'));

Ich bin nicht sicher, ob es die beste Lösung ist oder nicht, aber es scheint perfekt zu funktionieren ...

Was denkst du??

3
laukok

Meine Version von @Mark Eirich Antwort:

    function myload($class) {
      $controllerDir = '/controller/';
      $modelDir = '/model/';
      if (strpos($class, 'controller') !== false) {              
        $myclass = $controllerDir . $class . '.php';
      } else {
        $myclass = $modelDir . $class . '.inc.php';
      }
          if (!is_file($myclass)) return false;
          require_once ($myclass);

    }

    spl_autoload_register("myload");

In meinem Fall hat nur die Controller-Klasse das Schlüsselwort im Namen, passen Sie es an Ihre Bedürfnisse an.

2
sagits

Einfachste Antwort, die ich Ihnen geben kann, ohne diese komplexen Codes aufzuschreiben und sogar ohne den Namespace zu verwenden (wenn Sie dies verwirrt)

Beispielcode. Funktioniert 100%.

function __autoload($class_name){
$file = ABSPATH . 'app/models/' . $class_name . '.php';
if(file_exists($file)){
    include $file;
}else{
    $file = ABSPATH . 'app/views/' . $class_name . '.php';
    if(file_exists($file)){
        include $file;
    }else{
        $file = ABSPATH . 'app/controllers/' . $class_name . '.php';
        include $file;
    }
}

Ich denke, die Logik ist selbst erklärbar. Prost Kumpel! Hoffe das hilft :)

Folgendes würde ich tun:

function __autoload($class_name) {
    $class_name = strtolower($class_name);
    $filename = 'class_'.$class_name.'.php';

    if (substr($class_name, 0, 5) === 'model') {
        $file = AP_SITE.'models/'.$filename;
    } else $file = AP_SITE.'controllers/'.$filename;

    if (!is_file($file)) return false;
    include $file;
}

So lange Sie Ihre Dateien konsistent benennen, wie class_controller_*.php und class_model_*.php, das sollte gut funktionieren.

1
Mark Eirich

Die Funktion __autoload () sollte nicht verwendet werden, da sie nicht unterstützt wird. Verwenden Sie stattdessen spl_autoload (), spl_autoload_register (). __autoload () kann nur eine Klasse laden, aber spl_autoload () kann mehr als 1 Klassen erhalten. Und eines mehr, in Zukunft könnte __autoload () veraltet sein. Weitere Informationen finden Sie unter http://www.php.net/manual/en/function.spl-autoload.php

0
asi_x

Obwohl dieses Skript nicht die Namenskonvention hat und dieser Thread bereits ein bisschen alt ist, habe ich Folgendes getan, falls jemand nach einer möglichen Antwort sucht:

function __autoload($name) {
    $dirs = array_filter(glob("*"), 'is_dir');

    foreach($dirs as $cur_dir) {
        dir_searcher($cur_dir, $name);
    }

}

function dir_searcher($cur_dir, $name) {

    if(is_file("$cur_dir/$name.php")) {
        require_once "$cur_dir/$name.php";
    }

    $dirs = array_filter(glob($cur_dir."/*"), 'is_dir');
    foreach($dirs as $cdir) {
        dir_searcher("$cdir", $name);
    }
}

ich bin mir nicht sicher, ob es wirklich optimal ist, aber es durchsucht die Ordner, indem es dir rekursiv liest. Mit einer kreativen str_replace-Funktion können Sie Ihre Namensfindung erhalten.

0
jurrien

Ich benutze das. Definieren Sie Ihre Ordnerstruktur (MVC usw.) als Konstante in einem serialisierten Array. Rufen Sie dann das Array in Ihrer Autoload-Klasse auf. Arbeitet effizient für mich.

Sie können das Ordner-Array natürlich auch mit einer anderen Funktion erstellen, aber für MVC können Sie es auch manuell eingeben.

Damit dies funktioniert, müssen Sie Ihre Klassen aufrufen ...... class.classname.php

  //in your config file
    //define class path and class child folders
    define("classPath","classes");
    define("class_folder_array", serialize (array ("controller", "model", "view")));


  //wherever you have your autoload class
    //autoload classes
    function __autoload($class_name) {
    $class_folder_array = unserialize (class_folder_array);
    foreach ($class_folder_array AS $folder){
        if(file_exists(classPath."/".$folder.'/class.'.$class_name.'.php')){require_once classPath."/".$folder.'/class.'.$class_name.'.php';break;}
    }



    }
0
Andy RS

Jeder kopiert und fügt Dinge aus dem Code ein, den er aus dem Internet erhalten hat (mit Ausnahme der ausgewählten Antwort). Sie alle verwenden String Replace.

Das Ersetzen von Zeichenfolgen ist viermal langsamer als strtr. Sie sollten es stattdessen verwenden.

Sie sollten auch vollständige Pfade verwenden, wenn Sie Klassen mit automatischem Laden einschließen, da das Betriebssystem weniger Zeit benötigt, um den Pfad aufzulösen.

0
Case