2009-12-02 13 views
80

Ich bekomme diese Fehlermeldung, wenn ich versuche automatisch geladen und Namespaces zu verwenden:Wie verwende ich PHP Namespaces mit Autoload?

Fatal error: Class 'Class1' not found in /usr/local/www/apache22/data/public/php5.3/test.php on line 10

Kann mir jemand sagen, was ich falsch mache?

Hier ist mein Code:

Class1.php:

<?php 

namespace Person\Barnes\David 
{ 
    class Class1 
    { 
     public function __construct() 
     { 
      echo __CLASS__; 
     } 
    } 
} 

?> 

test.php:

<?php 

function __autoload($class) 
{ 
    require $class . '.php'; 
} 

use Person\Barnes\David; 

$class = new Class1(); 

?> 

Antwort

97

Klasse1 ist nicht im globalen Gültigkeitsbereich.

Siehe unten für ein funktionierendes Beispiel:

<?php 

function __autoload($class) 
{ 
    $parts = explode('\\', $class); 
    require end($parts) . '.php'; 
} 

use Person\Barnes\David as MyPerson; 

$class = new MyPerson\Class1(); 

Edit (2009-12-14):

Nur um zu klären, meine Verwendung von "verwenden ... als" vereinfachen sollte das Beispiel.

Die Alternative war die folgende:

$class = new Person\Barnes\David\Class1(); 

oder

use Person\Barnes\David\Class1; 

// ... 

$class = new Class1(); 
+0

Danke, Ich habe nicht bemerkt, dass ich "... as" benutzen muss. –

+0

Keine Sorgen David. Siehe auch die Bearbeitung für eine Klarstellung. – tanerkuc

+1

Sie müssen nicht 'AS' verwenden. Das ist nicht, warum diese Lösung funktioniert Genauso gut könnte man: 'Person benutzen \ Barnes \ David \ Class1; '(was äquivalent zu' user \ Barnes \ David \ Class1 als Class1; ') ist. – cartbeforehorse

14

Ihre __autoload Funktion wird die gesamte Klasse-Namen, einschließlich der Namensraum-Namen erhalten .

Das bedeutet, in Ihrem Fall wird die __autoload Funktion 'Person\Barnes\David\Class1' empfangen und nicht nur 'Class1'.

Also müssen Sie Ihren Autoloading-Code ändern, um mit dieser Art von "komplizierteren" Namen umzugehen; Eine häufig verwendete Lösung besteht darin, Ihre Dateien mit einer Ebene des Verzeichnisses pro "Ebene" der Namespaces zu organisieren und beim automatischen Laden "\" im Namen des Namensbereichs durch DIRECTORY_SEPARATOR zu ersetzen.

+1

Das ist nicht das, was ich gefunden. Als ich die Anweisung gesetzt habe, stirb ($ class); in der __autoload -Funktion, druckte es 'Class1' ', nicht' Person \ Barnes \ David \ Class1 ' –

+0

True. $ Klassenparameter von Autoload ist der Klassenname wie in Konstruktor Call geschrieben. – tishma

+1

Downvote für * "Your' __autoload' Die Funktion erhält den vollständigen Klassennamen einschließlich des Namespace-Namens "*" - das ist nur dann der Fall, wenn Sie die Klasse, auf die Sie verweisen möchten, explizit verwendet haben, nicht, wenn Sie den Namespace nur "verwendet" haben Der Fehler des OP bestand darin, dass er den Namespace, der eine Klasse enthielt,'verwendete' und dann erwartete, dass seine Autoload-Funktion irgendwie den vollen Klassenpfad irgendwie durchbricht. Diese Antwort adressiert nicht wirklich den Fehler des OP. –

22

Wie Pascal MARTIN erwähnt, sollten Sie die '\' mit DIRECTORY_SEPARATOR zum Beispiel ersetzen:

$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; 
include($filename); 

Auch Ich würde vorschlagen, dass Sie die Dirrektoriestruktur reorganisieren, um den Code lesbarer zu machen. Dies könnte eine Alternative sein:

Verzeichnisstruktur:

ProjectRoot 
|- lib 

Datei: /ProjectRoot/lib/Person/Barnes/David/Class1.php

<?php 
namespace Person\Barnes\David 
class Class1 
{ 
    public function __construct() 
    { 
     echo __CLASS__; 
    } 
} 
?> 
  • das Unterverzeichnis für jeden Namespace Stellen Sie definiert sind.

Datei: /ProjectRoot/test.php

define('BASE_PATH', realpath(dirname(__FILE__))); 
function my_autoloader($class) 
{ 
    $filename = BASE_PATH . '/lib/' . str_replace('\\', '/', $class) . '.php'; 
    include($filename); 
} 
spl_autoload_register('my_autoloader'); 

use Person\Barnes\David as MyPerson; 
$class = new MyPerson\Class1(); 
  • Ich verwendete PHP 5 recomendation für Autoloader Erklärung. Wenn Sie immer noch mit PHP 4 sind, ersetzen Sie es mit der alten Syntax: function __autoload ($ class)
3

Ich sehe, dass die Autoload-Funktionen nur den „voll“ classname erhalten - mit allen Namespaces es vorhergehenden - in der folgende zwei Fälle:

[a] $a = new The\Full\Namespace\CoolClass(); 

[b] use The\Full\Namespace as SomeNamespace; (at the top of your source file) followed by $a = new SomeNamespace\CoolClass(); 

ich sehe, dass die Autoload-Funktionen den vollständigen Klassennamen im folgenden Fall nicht erhalten:

[c] use The\Full\Namespace; (at the top of your source file) followed by $a = new CoolClass(); 

UPDATE: [c] ist ein Fehler und ist nicht, wie Namespaces Arbeit sowieso. Ich kann berichten, dass anstelle von [c] die folgenden zwei Fälle auch gut funktionieren:

[d] use The\Full\Namespace; (at the top of your source file) followed by $a = new Namespace\CoolClass(); 

[e] use The\Full\Namespace\CoolClass; (at the top of your source file) followed by $a = new CoolClass(); 

Hoffe, dass dies hilft.

+0

Als eine Randnotiz funktioniert das Schlüsselwort 'use' in der interaktiven PHP-Befehlszeilenschnittstelle nicht richtig (' php --interactive'); –

1

hatte das gleiche Problem und fand nur das:

Wenn Sie eine Unterordnerstruktur passend zu den Namensräumen der enthaltenen Klassen erstellen, werden Sie nie sogar einen Autoloader zu definieren.

spl_autoload_extensions(".php"); // comma-separated list 
    spl_autoload_register(); 

Es funktionierte wie ein Zauber

Mehr Infos hier: http://www.php.net/manual/en/function.spl-autoload-register.php#92514

EDIT: das verursacht Problem auf Linux wegen Backslash ... Siehe hier für Arbeitslösung von immeëmosol

Namespace Autoload works under windows, but not on Linux

3

Ich fand diesen Edelstein von Flysystem

spl_autoload_register(function($class) { 
    $prefix = 'League\\Flysystem\\'; 

    if (! substr($class, 0, 17) === $prefix) { 
     return; 
    } 

    $class = substr($class, strlen($prefix)); 
    $location = __DIR__ . 'path/to/flysystem/src/' . str_replace('\\', '/', $class) . '.php'; 

    if (is_file($location)) { 
     require_once($location); 
    } 
}); 
1

Die Verwendung hat ein Problem, obwohl es bei weitem die schnellste Methode ist, erwartet es auch alle Ihre Dateinamen in Kleinbuchstaben.

spl_autoload_extensions(".php"); 
spl_autoload_register(); 

Zum Beispiel:

Eine Datei, die Klasse SomeSuperClass enthalten müßte somesuperclass.php genannt wird, ist dies ein Gotcha wenn ein Groß- und Kleinschreibung Dateisystem wie Linux verwenden, wenn Sie Ihre Datei mit dem Namen wird SomeSuperClass.php aber unter Windows kein Problem.

Die Verwendung von __autoload in Ihrem Code funktioniert möglicherweise immer noch mit aktuellen PHP-Versionen, erwartet jedoch, dass diese Funktion veraltet und in der Zukunft endgültig entfernt wird.

Also, welche Möglichkeiten bleiben:

Diese Version funktioniert mit PHP 5.3 und höher und ermöglicht Dateinamen SomeSuperClass.php und somesuperclass.php. Wenn Sie 5.3.2 und höher verwenden, wird dieser Autoloader noch schneller arbeiten.

<?php 

if (function_exists ('stream_resolve_include_path') == false) { 
    function stream_resolve_include_path ($filename) { 
     $paths = explode (PATH_SEPARATOR, get_include_path()); 
     foreach ($paths as $path) { 
      $path = realpath ($path . PATH_SEPARATOR . $filename); 
      if ($path) { 
       return $path; 
      } 
     } 
     return false; 
    } 
} 

spl_autoload_register (function ($className, $fileExtensions = null) { 
    $className = str_replace ('_', '/', $className); 
    $className = str_replace ('\\', '/', $className); 
    $file = stream_resolve_include_path ($className . '.php'); 
    if ($file === false) { 
     $file = stream_resolve_include_path (strtolower ($className . '.php')); 
    } 
    if ($file !== false) { 
     include $file; 
     return true; 
    } 
    return false; 
}); 
+2

als eine Seitennotiz, 'str_replace (['_', '\\'] '/', $ Klassenname);' ist doppelt so schnell wie zwei str_replace –

+0

Solange es keine Rolle spielt, ob die PHP-Datei ist höher/Untergehäuse, die Verzeichnisse bleiben weiterhin case sensisive – Mike

10

ich etwas wie folgt aus:

spl_autoload_register('AutoLoader'); 

function AutoLoader($className) 
{ 
    $file = str_replace('\\',DIRECTORY_SEPARATOR,$className); 

    require_once 'classes' . DIRECTORY_SEPARATOR . $file . '.php'; 
    //Make your own path, Might need to use Magics like ___DIR___ 
} 
+2

Schön und einfach. Wenn man danach suchen sollte.) – dennis

1

ich kürzlich tanerkuc Antwort sehr hilfreich! Ich wollte nur hinzufügen, dass strrpos() + substr() ist etwas schneller als explode() + end() mit: ein einfaches spl_autoload_register() Einrichtung ohne die ganze Theorie für relative Anfänger in meinen zwei Cent

spl_autoload_register(function($class) { 
    $pos = strrpos($class, '\\'); 
    include ($pos === false ? $class : substr($class, $pos + 1)).'.php'; 
}); 
1

werfen werde ich oder was wollen: erstellen Sie einfach eine pHP-Datei für jede Klasse, Name, der die gleiche wie Ihre Klassennamen pHP-Datei, und halten Sie Ihre Klassendateien im selben Verzeichnis wie die pHP-Datei in Frage, dann wird diese Arbeit:

spl_autoload_register(function ($class_name) { 
    require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php'; 
}); 

die Googeln Stücke innerhalb dieser Funktion sho Wie antworte ich, wie es funktioniert. PS: Ich benutze Linux, und das funktioniert auf Linux. Windows-Leute sollten es zuerst ausprobieren.

1

https://thomashunter.name/blog/simple-php-namespace-friendly-autoloader-class/

Sie wollen werden Ihre Klassendateien in einen Ordner mit dem Namen Klassen setzen, die als Einstiegspunkt in Ihre PHP-Anwendung im selben Verzeichnis ist. Wenn Klassen Namespaces verwenden, werden die Namespaces in die Verzeichnisstruktur konvertiert. Anders als viele andere Auto-Loader werden Unterstriche nicht in Verzeichnisstrukturen umgewandelt (es ist schwierig, PHP-Pseudo-Namespaces mit PHP> = 5.3 echte Namespaces zu machen).

<?php 
class Autoloader { 
    static public function loader($className) { 
     $filename = "Classes/" . str_replace("\\", '/', $className) . ".php"; 
     if (file_exists($filename)) { 
      include($filename); 
      if (class_exists($className)) { 
       return TRUE; 
      } 
     } 
     return FALSE; 
    } 
} 
spl_autoload_register('Autoloader::loader'); 

Sie wollen werden den folgenden Code in die Haupt-PHP-Skript (Einstiegspunkt) platzieren:

require_once("Classes/Autoloader.php"); 

Hier ist ein Beispiel Verzeichnisstruktur:

index.php 
Classes/ 
    Autoloader.php 
    ClassA.php - class ClassA {} 
    ClassB.php - class ClassB {} 
    Business/ 
    ClassC.php - namespace Business classC {} 
    Deeper/ 
     ClassD.php - namespace BusinessDeeper classD {}