web-dev-qa-db-fra.com

Comment puis-je utiliser PHP espaces de noms avec autoload?

Je reçois cette erreur lorsque j'essaie d'utiliser le chargement automatique et les espaces de noms:

Erreur fatale: Classe 'Class1' introuvable dans /usr/local/www/Apache22/data/public/php5.3/test.php on ligne 10

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

Voici mon code:

Classe1.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 n'est pas dans la portée globale.

Voir ci-dessous pour un exemple de travail:

<?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):

Pour clarifier, mon utilisation de "use ... as" était de simplifier l'exemple.

L'alternative était la suivante:

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

ou

use Person\Barnes\David\Class1;

// ...

$class = new Class1();
108
tanerkay

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 répertoires, 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__;
    }
}
?>
  • Créez le sous-répertoire pour chaque espace de noms défini.

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 5 pour la déclaration de l'autoloader. Si vous êtes toujours avec PHP 4, remplacez-le par l'ancienne syntaxe: function __autoload ($ class)
25
Kostanos

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

Cela signifie que, dans votre cas, la fonction __autoload recevra «Person\Barnes\David\Class1», et pas seulement «Class1».

Donc, vous devez modifier votre code de chargement automatique, pour traiter ce genre de nom "plus compliqué"; une solution souvent utilisée consiste à organiser vos fichiers en utilisant un niveau de répertoire par "niveau" d'espaces de nommage et, lors du chargement automatique, de remplacer "\" dans le nom de l'espace de nommage par DIRECTORY_SEPARATOR.

16
Pascal MARTIN

Je fais quelque chose comme ceci: Voir cet exemple 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___
}
10
tika

Je constate que les fonctions de chargement automatique 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 de chargement automatique 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();

UPDATE: [c] est une erreur et ce n'est pas comment les espaces de noms fonctionnent de toute façon. Je peux signaler que, au lieu de [c], les deux cas suivants fonctionnent également 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();

J'espère que cela t'aides.

3
Daniel Rhodes

J'ai trouvé ce petit bijou 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
boksiora

J'utilise ce hack simple en une ligne:

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

Utiliser a à coup sûr, bien que ce soit de loin la méthode la plus rapide, il s'attend également à ce que tous vos noms de fichiers soient en minuscules.

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

Par exemple:

Un fichier contenant la classe SomeSuperClass doit être nommé somesuperclass.php. Ceci est un piège si vous utilisez un système de fichiers sensible à la casse tel que Linux.

L'utilisation de __autoload dans votre code peut toujours fonctionner avec les versions actuelles de PHP, mais attendez-vous à ce que cette fonctionnalité devienne obsolète et soit finalement supprimée.

Alors quelles sont les options qui restent:

Cette version fonctionnera avec PHP 5.3 et versions ultérieures et autorise les noms de fichier SomeSuperClass.php et somesuperclass.php. Si vous utilisez les versions 5.3.2 et supérieures, cet autochargeur 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
Michael Bush

Je vais ajouter mes deux sous pour les débutants relatifs ou ce que je ne souhaite pas, une installation simple de spl_autoload_register () sans toute la théorie: vos fichiers de classe dans le même répertoire que votre fichier php en question, alors cela fonctionnera:

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

Googler les morceaux dans cette fonction devrait répondre à la façon dont cela fonctionne .. PS: J'utilise Linux, et cela fonctionne sous Linux. Les utilisateurs de Windows devraient d'abord le tester.

1
user6659166

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 qui les contiennent, vous n’aurez même jamais à définir un autochargeur.

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

Ça a marché comme sur des roulettes

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

EDIT: cela cause un problème sous Linux à cause de la barre oblique inverse ... Voir ici pour la solution de travail par immeëmosol

Namespace Autoload fonctionne sous Windows, mais pas sous Linux

1
JohnWolf

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
Alan

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

Vous souhaiterez placer vos fichiers de classe dans un dossier nommé Classes, qui se trouve dans le même répertoire que le point d’entrée de votre application PHP. Si les classes utilisent des espaces de noms, ceux-ci seront convertis dans la structure de répertoires. Contrairement à beaucoup d’autres chargeurs automatiques, les traits de soulignement ne seront pas convertis en structures de répertoires (il est difficile de créer des pseudo espaces PHP <5.3 avec des espaces de noms PHP> = 5.3).

<?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 voudrez 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
<?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