Come si utilizzano gli spazi dei nomi PHP con il caricamento automatico?


104

Ottengo questo errore quando provo a utilizzare il caricamento automatico e gli spazi dei nomi:

Errore irreversibile: classe "Class1" non trovata in /usr/local/www/apache22/data/public/php5.3/test.php alla riga 10

Qualcuno può dirmi cosa sto sbagliando?

Ecco il mio codice:

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();

?>

Risposte:


119

Class1 non è nell'ambito globale.

Vedi sotto per un esempio funzionante:

<?php

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

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

Modifica (2009-12-14):

Giusto per chiarire, il mio uso di "usa ... come" era per semplificare l'esempio.

L'alternativa era la seguente:

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

o

use Person\Barnes\David\Class1;

// ...

$class = new Class1();

1
Non devi usare AS. Non è per questo che questa soluzione funziona. Potresti altrettanto facilmente fare: use Person\Barnes\David\Class1;(che è equivalente a use Person\Barnes\David\Class1 as Class1;).
cartbeforehorse

1
Grazie, funziona. Ma non riesco a capire perché possiamo semplicemente usare $ class = new Class1 (); quando abbiamo già definito "usa Persona \ Barnes \ David;" prima?
user345602

4
@ user346665 devi usare use Person\Barnes\David\Class1;per fare $class = new Class1();. Con use Person\Barnes\David;devi fare $class = new David\Class1();. La useparola chiave di per sé è l'equivalente di use Person\Barnes\David\Class1 as Class1;o use Person\Barnes\David as David;, rispettivamente, per ogni esempio.
Justin C

Per coloro che leggono nel 2018, utilizzare la soluzione @ prince-billy-graham con spl_autoload_register
Bruno de Oliveira,

26

Come accennato Pascal MARTIN, dovresti sostituire "\" con DIRECTORY_SEPARATOR ad esempio:

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

Inoltre ti suggerirei di riorganizzare la struttura della directory, per rendere il codice più leggibile. Questa potrebbe essere un'alternativa:

Struttura delle directory:

ProjectRoot
 |- lib

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

<?php
namespace Person\Barnes\David
class Class1
{
    public function __construct()
    {
        echo __CLASS__;
    }
}
?>
  • Crea la sottodirectory per ogni spazio dei nomi definito.

File: /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();
  • Ho usato la raccomandazione di php 5 per la dichiarazione del caricatore automatico. Se utilizzi ancora PHP 4, sostituiscilo con la vecchia sintassi: function __autoload ($ class)

18

La __autoloadfunzione riceverà il nome completo della classe, incluso il nome dello spazio dei nomi.

Ciò significa che, nel tuo caso, la __autoloadfunzione riceverà " Person\Barnes\David\Class1", e non solo Class1".

Quindi, devi modificare il tuo codice di autoloading, per gestire quel tipo di nome "più complicato"; una soluzione spesso utilizzata consiste nell'organizzare i file utilizzando un livello di directory per "livello" di spazi dei nomi e, durante il caricamento automatico, sostituire " \" nel nome dello spazio dei nomi con DIRECTORY_SEPARATOR.


1
Questo non è quello che ho trovato. Quando ho messo l'istruzione die ($ class); nella funzione __autoload, ha stampato "Class1" ", non" Person \ Barnes \ David \ Class1 "
David Barnes

Vero. $ class parametro di autoload è il nome della classe come scritto nella chiamata al costruttore.
tishma

1
Downvote per "La tua __autoloadfunzione riceverà il nome completo della classe, incluso il nome dello spazio dei nomi" - questo è vero solo se hai esplicitamente used la classe a cui stai cercando di fare riferimento, non se hai semplicemente used lo spazio dei nomi a cui appartiene. L'errore dell'OP era che aveva usecreato lo spazio dei nomi contenente una classe e quindi si aspettava che la sua funzione di caricamento automatico passasse magicamente in qualche modo all'intero percorso di classe. Questa risposta in realtà non affronta l'errore dell'OP.
Mark Amery

15

Faccio qualcosa del genere: vedi questo esempio di GitHub

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

3
Bello e semplice. Se uno dovrebbe cercare quello.)
dennis

3

Ho trovato questo gioiello da 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);
    }
});

3

Vedo che le funzioni di caricamento automatico ricevono solo il nome di classe "completo" - con tutti gli spazi dei nomi che lo precedono - nei due casi seguenti:

[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();

Vedo che le funzioni di caricamento automatico NON ricevono il nome della classe completo nel seguente caso:

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

AGGIORNAMENTO: [c] è un errore e comunque non è il modo in cui funzionano gli spazi dei nomi. Posso segnalare che, invece di [c], funzionano bene anche i seguenti due casi:

[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();

Spero che questo ti aiuti.


Come nota a margine, la useparola chiave non funziona correttamente nell'interfaccia a riga di comando interattiva PHP ( php --interactive);
Andrew Larsson

3

Uso questo semplice trucco in una riga:

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

1

ha avuto lo stesso problema e ho appena trovato questo:

Quando crei una struttura di sottocartelle che corrisponde agli spazi dei nomi delle classi che li contengono, non dovrai nemmeno definire un caricatore automatico.

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

Ha funzionato come un fascino

Maggiori informazioni qui: http://www.php.net/manual/en/function.spl-autoload-register.php#92514

EDIT: questo causa problemi su Linux a causa del backslash ... Vedi qui per la soluzione di lavoro di immeëmosol

Il caricamento automatico dello spazio dei nomi funziona su Windows, ma non su Linux


1

L'uso ha un trucco, sebbene sia di gran lunga il metodo più veloce, si aspetta anche che tutti i nomi dei file siano minuscoli.

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

Per esempio:

Un file contenente la classe SomeSuperClass dovrebbe essere chiamato somesuperclass.php, questo è un trucco quando si usa un filesystem case sensitive come Linux, se il tuo file si chiama SomeSuperClass.php ma non è un problema sotto Windows.

L'uso di __autoload nel codice può ancora funzionare con le versioni correnti di PHP, ma si prevede che questa funzione diventi deprecata e infine rimossa in futuro.

Quindi quali opzioni sono rimaste:

Questa versione funziona con PHP 5.3 e versioni successive e consente nomi di file SomeSuperClass.php e somesuperclass.php. Se utilizzi 5.3.2 e versioni successive, questo caricatore automatico funzionerà ancora più velocemente.

<?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
come nota str_replace ([ '_','\\'] '/', $className );a margine , è due volte più veloce di due str_replace
Itay Moav -Malimovka

Finché non importa se il file php è in maiuscolo / minuscolo, le directory restano sensibili al maiuscolo / minuscolo
Mike

1

Di recente ho trovato molto utile la risposta di tanerkuc! Volevo solo aggiungere che l'uso di strrpos()+ substr()è leggermente più veloce di explode()+ end():

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

1

Metterò i miei due centesimi per i relativi principianti o quant'altro desiderino una semplice configurazione spl_autoload_register () senza tutta la teoria: crea semplicemente un file php per ogni classe, assegna a quel file php lo stesso nome della tua classe e mantieni i tuoi file di classe nella stessa directory del file php in questione, allora funzionerà:

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

Cercare su Google i pezzi all'interno di questa funzione dovrebbe rispondere a come funziona. PS: Uso Linux e funziona su Linux. Gli utenti di Windows dovrebbero prima provarlo.


1

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

Ti consigliamo di inserire i file di classe in una cartella denominata Classes, che si trova nella stessa directory del punto di ingresso nell'applicazione PHP. Se le classi utilizzano gli spazi dei nomi, gli spazi dei nomi verranno convertiti nella struttura della directory.

A differenza di molti altri caricatori automatici, i caratteri di sottolineatura non verranno convertiti in strutture di directory (è difficile eseguire pseudo spazi dei nomi PHP <5.3 insieme a PHP> = 5.3 spazi dei nomi reali).

<?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');

Ti consigliamo di inserire il seguente codice nel tuo script PHP principale (punto di ingresso):

require_once("Classes/Autoloader.php");

Ecco un esempio di layout di directory:

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

0
<?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();
}
?>

1
Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo sul perché e / o come questo codice risponde alla domanda ne migliora il valore a lungo termine.
Ethan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.