it-swarm.com.de

Wie benutze ich? PHP Namespaces mit Autoload?

Ich erhalte diese Fehlermeldung, wenn ich versuche, Autoload und Namespaces zu verwenden:

Schwerwiegender Fehler: Klasse 'Klasse1' nicht gefunden in /usr/local/www/Apache22/data/public/php5.3/test.php in Zeile 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();

?>
86
David Barnes

Class1 ist nicht im globalen Bereich.

Siehe unten für ein Arbeitsbeispiel:

<?php

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

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

Bearbeiten (2009-12-14):

Zur Verdeutlichung diente die Verwendung von "use ... as" der Vereinfachung des Beispiels.

Die Alternative war folgende:

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

oder

use Person\Barnes\David\Class1;

// ...

$class = new Class1();
108
tanerkay

Wie bereits erwähnt, sollten Sie das "\" durch DIRECTORY_SEPARATOR ersetzen, zum Beispiel:

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

Außerdem würde ich Ihnen vorschlagen, die Verzeichnisstruktur neu zu organisieren, um den Code lesbarer zu machen. Dies könnte eine Alternative sein:

Verzeichnisaufbau:

ProjectRoot
 |- lib

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

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

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 habe PHP-5-Empfehlung für die Autoloader-Deklaration verwendet. Wenn Sie noch mit PHP 4 arbeiten, ersetzen Sie es durch die alte Syntax: function __autoload ($ class)
25
Kostanos

Ihre __autoload-Funktion erhält den vollständigen Klassennamen, einschließlich des Namensraumnamens.

Dies bedeutet, dass in Ihrem Fall die __autoload-Funktion 'Person\Barnes\David\Class1' und nicht nur 'Class1' empfängt.

Sie müssen also Ihren Autoloading-Code ändern, um mit diesem "komplizierteren" Namen umgehen zu können. Eine häufig verwendete Lösung besteht darin, Ihre Dateien mit einer Verzeichnisebene pro "Ebene" von Namespaces zu organisieren. Beim automatischen Laden ersetzen Sie "\" im Namensraumnamen durch DIRECTORY_SEPARATOR.

16
Pascal MARTIN

Ich mache so etwas: Siehe dieses GitHub-Beispiel

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___
}
10
tika

Ich sehe, dass die Autoload-Funktionen in den folgenden zwei Fällen nur den "vollständigen" Klassennamen erhalten - wobei alle Namespaces vorangestellt werden:

[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 im folgenden Fall NICHT den vollständigen Klassennamen erhalten:

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

UPDATE: [c] ist ein Fehler und funktioniert nicht so, wie Namespaces funktionieren. Ich kann berichten, dass anstelle von [c] auch die folgenden zwei Fälle 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 das hilft.

3
Daniel Rhodes

Ich habe dieses Juwel von Flysystem gefunden

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);
    }
});
3
boksiora

Ich benutze diesen einfachen Hack in einer Zeile:

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\\','/',$name).'.php';
    });
1

Using hat ein gotcha, während es bei weitem die schnellste Methode ist, erwartet es aber auch, dass alle Ihre Dateinamen Kleinbuchstaben sind.

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

Zum Beispiel:

Eine Datei mit der Klasse SomeSuperClass müsste somesuperclass.php heißen. Dies ist ein Problem, wenn Sie ein case-sensitive Dateisystem wie Linux verwenden, wenn Ihre Datei SomeSuperClass.php heißt, aber unter Windows kein Problem.

Die Verwendung von __autoload in Ihrem Code funktioniert möglicherweise immer noch mit aktuellen Versionen von PHP, es wird jedoch davon ausgegangen, dass diese Funktion in Zukunft nicht mehr verwendet wird.

Welche Optionen bleiben also:

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

<?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;
});
1
Michael Bush

Ich gebe meine zwei Cent für relative Anfänger oder was auch immer für ein einfaches spl_autoload_register () - Setup ohne alle Theorie ein: Erstellen Sie einfach eine PHP-Datei für jede Klasse Wenn Ihre Klassendateien sich im selben Verzeichnis wie die betreffende PHP-Datei befinden, funktioniert dies:

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

Das Googeln der Teile in dieser Funktion sollte beantworten, wie es funktioniert. PS: Ich verwende Linux, und das funktioniert unter Linux. Windows-Leute sollten es zuerst testen.

1
user6659166

hatte das gleiche Problem und fand gerade das:

Wenn Sie eine Unterordnerstruktur erstellen, die mit den Namespaces der enthaltenen Klassen übereinstimmt, müssen Sie niemals einen Autoloader definieren.

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

Es hat wie ein Zauber funktioniert

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

BEARBEITEN: dies verursacht unter Linux Probleme wegen des Backslash ... Siehe hier für eine funktionierende Lösung von immeëmosol

Namespace Autoload funktioniert unter Windows, aber nicht unter Linux

1
JohnWolf

Ich fand die Antwort von tanerkuc kürzlich sehr hilfreich! Ich wollte nur hinzufügen, dass die Verwendung von strrpos() + substr() etwas schneller ist als explode() + end():

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

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

Sie möchten Ihre Klassendateien in einem Ordner mit dem Namen Classes ablegen, der sich in demselben Verzeichnis befindet wie der Einstiegspunkt in Ihre Anwendung PHP. Wenn Klassen Namespaces verwenden, werden die Namespaces in die Verzeichnisstruktur konvertiert. Im Gegensatz zu vielen anderen Auto-Loadern werden Unterstriche nicht in Verzeichnisstrukturen konvertiert (es ist schwierig, PHP <5.3 Pseudo-Namespaces zusammen mit PHP> = 5.3 echten Namespaces).

<?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 möchten den folgenden Code in Ihr Hauptskript PHP einfügen (Einstiegspunkt):

require_once("Classes/Autoloader.php");

Hier ein Beispiel für ein Verzeichnislayout:

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 {}
<?php
spl_autoload_register(function ($classname){
   // for security purpose
   //your class name should match the name of your class "file.php"
   $classname = str_replace("..", "", $classname);
   require_once __DIR__.DIRECTORY_SEPARATOR.("classes/$classname.class.php");
});
try {
  $new = new Class1();
} catch (Exception $e) {
   echo "error = ". $e->getMessage();
}
?>
0