Comment utiliser les espaces de noms PHP avec autoload?

j'obtiens cette erreur quand j'essaie d'utiliser autoload et namespaces:

erreur Fatale: Classe "Class1" introuvable dans la /usr/local/www/apache22/data/public/php5.3/test.php sur la ligne 10

quelqu'un peut-il me dire ce que je fais de mal?

Voici mon code:

Classe 1.php:

<?php

namespace PersonBarnesDavid
{
    class Class1
    {
        public function __construct()
        {
            echo __CLASS__;
        }
    }
}

?>

test.php:

<?php

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

use PersonBarnesDavid;

$class = new Class1();

?>
85
demandé sur hakre 2009-12-02 08:55:14

13 réponses

Class1 n'est pas dans la portée globale.

voir ci-dessous pour un exemple pratique:

<?php

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

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

Modifier (2009-12-14):

juste pour clarifier, mon usage de " use ... "était de simplifier l'exemple.

la variante était la suivante:

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

ou

use Person\Barnes\David\Class1;

// ...

$class = new Class1();
107
répondu tanerkuc 2016-11-06 20:11:48

comme mentionné Pascal MARTIN, vous devez remplacer le ' \ 'par DIRECTORY_SEPARATOR par exemple:

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

aussi je vous suggérerais de réorganiser la structure de dirrectory, pour rendre le code plus lisible. Cela pourrait être une alternative:

structure du répertoire:

ProjectRoot
 |- lib

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

<?php
namespace Person\Barnes\David
class Class1
{
    public function __construct()
    {
        echo __CLASS__;
    }
}
?>
  • faites le sous-répertoire pour chaque espace de noms que vous êtes définir.

Fichier: /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();
  • j'ai utilisé la recommandation php 5 pour la déclaration d'autoloader. Si vous êtes toujours avec PHP 4, remplacez-le par l'ancienne syntaxe: function _ _ autoload ($class)
24
répondu Kostanos 2013-05-14 01:01:43

votre fonction __autoload recevra le nom complet de la classe, y compris le nom de l'espace de noms.

cela signifie, dans votre cas, la fonction __autoload recevra Person\Barnes\David\Class1 ", et pas seulement Class1 ".

ainsi, vous devez modifier votre code de chargement automatique, pour traiter ce genre de nom "plus compliqué"; une solution souvent utilisée est d'organiser vos dossiers en utilisant un niveau de répertoire par "niveau" d'espaces de noms, et, quand, remplacer " \ " dans le nom d'espace de noms par DIRECTORY_SEPARATOR .

16
répondu Pascal MARTIN 2009-12-02 06:00:12

je fais quelque chose comme ceci: Voir cette GitHub Exemple

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
répondu tika 2018-07-09 21:21:58

j'ai trouvé cette gemme de 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
répondu boksiora 2015-02-15 20:20:26

je vois que les fonctions autoload ne reçoivent que le nom de classe "complet" - avec tous les espaces de noms qui le précèdent - dans les deux cas suivants:

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

je vois que les fonctions autoload ne reçoivent pas le nom de classe complet dans le cas suivant:

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

mise à JOUR: [c] est une erreur et n'est pas comment les espaces de travail de toute façon. Je peux dire qu'au lieu de [c], les deux cas suivants fonctionnent aussi bien:

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

Espérons que cette aide.

3
répondu Daniel Rhodes 2016-06-12 17:55:15

avait le même problème et vient de trouver ceci:

lorsque vous créez une structure de sous-dossiers correspondant aux espaces de noms des classes contenant, Vous n'aurez même pas à définir un autoloader.

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

Il a travaillé comme un charme

plus d'informations ici: http://www.php.net/manual/en/function.spl-autoload-register.php#92514

EDIT: cela cause des problèmes sur Linux à cause de oblique... Voir ici pour la solution de travail par immeëmosol

espace de Noms de chargement automatique fonctionne sous windows, mais pas sur Linux

1
répondu JohnWolf 2017-05-23 12:10:33

utiliser a un gotcha, bien qu'il soit de loin la méthode la plus rapide, il s'attend également à ce que tous vos noms de fichiers soient minuscules.

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

par exemple:

un fichier contenant la classe SomeSuperClass devrait être nommé somesuperclass.php, ceci est un gotcha lorsque vous utilisez un système de fichiers sensible à la casse comme Linux, si votre fichier s'appelle SomeSuperClass.php mais pas un problème sous Windows.

en utilisant _ _ autoload dans votre code mai fonctionne toujours avec les versions actuelles de PHP mais s'attend à ce que cette fonctionnalité soit dépréciée et finalement supprimée à l'avenir.

alors quelles sont les options qui restent:

cette version fonctionnera avec PHP 5.3 et au-dessus et permet les noms de fichiers SomeSuperClass.php et somesuperclass.php. Si vous utilisez 5.3.2 et plus, cet autoloader fonctionnera encore plus rapidement.

<?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
répondu Michael Bush 2015-04-08 01:28:52

j'ai récemment trouvé la réponse de tanerkuc très utile! Je voulais juste ajouter que l'utilisation de strrpos() + substr() est légèrement plus rapide que explode() + end() :

spl_autoload_register( function( $class ) {
    $pos = strrpos( $class, '\' );
    include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php';
});
1
répondu Alan 2016-08-05 02:18:00

je vais jeter dans mes deux cents pour les débutants relatifs ou quoi d'autre voulant un simple spl_autoload_register () setup sans toute la théorie: Il suffit de créer un fichier php pour chaque classe, nommer que le fichier php le même que votre nom de classe, et de garder vos fichiers de classe dans le même répertoire que votre fichier php en question, puis cela fonctionnera:

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

googler les pièces à l'intérieur de cette fonction devrait répondre à la façon dont il fonctionne. PS: J'utilise Linux, et cela fonctionne sous Linux. Windows les gens doivent le tester en premier.

1
répondu 2016-08-22 05:45:38

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

vous voudrez mettre vos fichiers de classe dans un dossier nommé Classes, qui est dans le même répertoire que le point d'entrée dans votre application PHP. Si les classes utilisent namespaces, les namespaces seront convertis en structure de répertoire. Contrairement à beaucoup d'autres auto-loaders, les underscores ne seront pas convertis en structures de répertoires (il est difficile de faire PHP < 5.3 pseudo-namespaces avec PHP > = 5.3 vrais 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');

vous voulez placer le code suivant dans votre script PHP principal (point d'entrée):

require_once("Classes/Autoloader.php");

voici un exemple de disposition de répertoire:

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 {}
1
répondu Yuvraj Singh Shekhawat 2017-10-26 07:33:30

j'utilise ce simple hack en une ligne:

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\','/',$name).'.php';
    });
1
répondu Prince Billy Graham 2018-08-29 06:52:50
<?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
répondu Nevil Saul Blemuss 2018-05-17 12:05:53