IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Utilisation de l'autoload


Sujet :

Langage PHP

  1. #1
    Nouveau membre du Club
    Inscrit en
    Mai 2009
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 34
    Points : 26
    Points
    26
    Par défaut Utilisation de l'autoload
    Bonjour,

    J'ai un soucis avec la fonction magique __autoload en PHP 5.3 dans un cas précis.
    Je suis en local avec WampServer 2.0 (PHP 5.3.0) sous Windows Vista SP2.

    Voici un exemple tout simple pour bien vous illustrer le problème :

    /index.php :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <?php
    ini_set('display_errors', 1);
     
    /**
     * Se charge d'inclure le fichier correspondant à la classe appelée
     * si celle-ci n'existe pas encore
     */
    function __autoload($class) {
    	require_once dirname(__FILE__) . "/$class.class.php";
    }
     
    /**
     * Fonction utilisée pour la gestion des erreurs
     */
    function my_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
    	// la classe File n'existe pas lors du premier appel
    	// c'est donc __autoload qui va se charger de l'inclure
    	$file = new File( dirname(__FILE__) . '/log.txt' );
    	$file->write( date('d/m/Y H:i:s') . " -- $errno: $errstr [$errfile, line $errline]" );
    }
     
    /**
     * Définit la fonction "my_error_handler" en tant que gestionnaire d'erreur
     */
    set_error_handler('my_error_handler', -1);
     
    /**
     * Inclusion d'un fichier contenant une classe Foo
     * et l'instanciation d'un objet de celle-ci
     */
    include 'foo.php';
    ?>
    /foo.php :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <?php
    class Foo {}
     
    // le passage en référence d'une valeur retournée par "new"
    // déclenche une erreur de type "Deprecated" en PHP 5.3
    $foo =& new Foo();
    ?>
    /File.class.php
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    class File {
    	private $_path;
     
    	public function __construct($path) {
    		$this->_path = realpath($path);
    	}
     
    	public function write($data) {
    		$fp = fopen($this->_path, 'a');
    		return fwrite($fp, $data);
    	}
    }
    ?>
    Pour résumer vite fait ce qui se passe : une erreur "Deprecated" est lancée dans foo.php à cause du "=& new". La fonction "my_error_handler" est alors exécutée pour traiter l'erreur. Celle-ci fait appel à la classe File qui va donc être incluse grâce à la fonction __autoload. Mais justement le problème c'est que __autoload ne fait pas son travail et on se retrouve avec une erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Fatal error: Class 'File' not found in /foo.php on line 6
    À noter que si je déclenche un autre type d'erreur (par exemple : "trigger_error('test', E_USER_NOTICE);"), ça fonctionne parfaitement !

    J'ai mis la classe Foo et l'instanciation de l'objet dans un fichier à part car si je les met directement dans index.php (à la place de "include 'foo.php';" donc), c'est le gestionnaire d'erreur de PHP qui est utilisé et non "my_error_handler". Là non plus, je n'ai pas d'explication...

    Merci de vos réponses si vous voyez d'où vient le problème.

  2. #2
    Membre expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Points : 3 947
    Points
    3 947
    Par défaut
    Salut

    Je n'est pas vraiment d'explication aussi.
    Ce qui m'étonne, c'est que Php recherche la classe File dans foo.php.


    Je ne sais pas si il y aurait une cause à effet, mais attention à la "casse", ton fichier se nomme foo.php alors que le nom de la classe est Foo. L'autoad tient compte de la "casse" sur Linux, mais pas sur Windows.
    Vaut mieux renommer le fichier Foo.php


    Petite suggestion.
    Et si tu rajoute un code qui gère une éventuelle erreur sur la non existence d'une classe, ça donne quoi ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    function __autoload($class) {
        if (empty($class)) {
            trigger_error('ERREUR: Aucun nom de classe', E_USER_ERROR);
            exit();
        }
        elseif (file_exists(dirname(__FILE__).$class.'.class.php')) {
            require_once(dirname(__FILE__).$class.'.class.php');
        }
        else {
            trigger_error('ERREUR : Classe inexistante : '.$class, E_USER_ERROR);
            exit();
        }
    }
    Win XP | WampServer 2.2d | Apache 2.2.21 | Php 5.3.10 | MySQL 5.5.20
    Si debugger, c'est supprimer des bugs, alors programmer ne peut être que les ajouter [Edsger Dijkstra]

  3. #3
    Rédacteur
    Avatar de Halleck
    Homme Profil pro
    Consultant PHP
    Inscrit en
    Mars 2003
    Messages
    597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Consultant PHP

    Informations forums :
    Inscription : Mars 2003
    Messages : 597
    Points : 878
    Points
    878
    Par défaut
    Je vais peut-être dire une bêtise, mais il me semble de mémoire qu'il n'est pas possible de faire un autoload pour tout ce qui est "hors contexte normale" (ex: error_handler, register_shutdown_function()...). Il faut au début du code que tu fasse quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $rien = class_exists('File();
    unset($rien)
    DOnc si quelqu'un peut confirmer ça...
    Zend PHP Certified Engineer, Certifié Symfony2
    blog : blog.lepine.pro
    Secrétaire de l'AFUP (Association des Utilisateurs de PHP)

  4. #4
    Nouveau membre du Club
    Inscrit en
    Mai 2009
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 34
    Points : 26
    Points
    26
    Par défaut
    Alors Halleck, je n'ai absolument rien compris à ton truc mais ça fonctionne impeccable

    Alors un grand merci à toi car ça faisait plus d'une journée que je bloquais là dessus et je n'aurais pensé à ça.

    Si tu pouvais juste m'expliquer exactement pourquoi il y a besoin de ces lignes de codes !

    Sinon, pour répondre à RunCodePhp : l'autoload ne recherche pas la classe File dans foo.php. C'est juste que l'origine de l'erreur est le "=& new" que PHP 5.3 n'aime pas (Assigning the return value of new by reference is deprecated) et elle est catché par le gestionnaire d'erreur qui a ici été défini comme étant la fonction "my_error_handler". Et c'est dans cette fonction, lorsque l'on fait "$file = new File(...)" que ça déclenche l'erreur "Class 'File' not found". Mais j'avoue que je ne comprends pas pourquoi cette dernière est localisée au niveau du "=& new" au lieu du "new File(...)"... autant vous dire que j'ai mis un bon bout de temps avant de comprendre ce qui se passait (surtout que je n'étais pas un cas aussi simpliste que celui-là).

  5. #5
    Nouveau membre du Club
    Inscrit en
    Mai 2009
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 34
    Points : 26
    Points
    26
    Par défaut
    En fait c'est bon, j'ai compris ^^
    La fonction class_exists fait par défaut appel à autoload, donc le fait de l'appeler au début de mon code fera que la classe File sera tout de suite incluse.

    Par contre, pas besoin de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <?php
    $rien = class_exists('File');
    unset($rien);
    ?>
    Un simple...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <?php
    class_exists('File');
    ?>
    ... suffit.

    Par contre tu dis :
    il n'est pas possible de faire un autoload pour tout ce qui est "hors contexte normale"
    Or j'avais précisé qu'en déclenchant un autre type d'erreur, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <?php
    trigger_error('test', E_USER_NOTICE);
    ?>
    ça fonctionne très bien !
    C'est vraiment que avec "Deprecated" que ça bloque

  6. #6
    Rédacteur
    Avatar de Halleck
    Homme Profil pro
    Consultant PHP
    Inscrit en
    Mars 2003
    Messages
    597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Consultant PHP

    Informations forums :
    Inscription : Mars 2003
    Messages : 597
    Points : 878
    Points
    878
    Par défaut
    En fait, il y a différents niveaux dans PHP : un premier niveau dans lequel PHP s'exécute à proprement parler, et un second dans lequel il interprète ton code (en gros).

    Dans ce second niveau, PHP est capable de détecter l'"exception" de type "classe introuvable" ; c'est l'autoload : dès que l'"exception" est levée, la fonction __autoload est executée.

    Mais dans son premier niveau, il n'est plus possible de gérer cette "exception". Ce premier niveau, tu y accède à de rares occasions : quand tu définies ton gestionnaire d'erreur et quand tu fais un register_shutdown_function().

    Donc bref, dans ton error handler l'autoload ne passe pas.

    La solution consiste donc à charger la classe en mémoire dès le début avec le code que je t'ai fourni. Comme ça quand PHP passe un son premier niveau, la classe est déjà chargée et ton error handler peut l'utiliser.

    C'est plus clair ?

    PS: je n'ai aucune connaissance claire de la manière donc ça fonctionne à ce niveau, donc si quelqu'un de compétent peut confirmer/corriger ce que je dis...

    Edit: arf, tu t'es répondu avant moi
    Zend PHP Certified Engineer, Certifié Symfony2
    blog : blog.lepine.pro
    Secrétaire de l'AFUP (Association des Utilisateurs de PHP)

Discussions similaires

  1. [POO] Utilisation de l'autoload
    Par LDDL dans le forum Langage
    Réponses: 5
    Dernier message: 01/06/2010, 18h45
  2. Réponses: 4
    Dernier message: 11/01/2010, 11h04
  3. [ZF 1.8] Utiliser l'autoload pour mes classes
    Par guiyomh dans le forum MVC
    Réponses: 4
    Dernier message: 30/07/2009, 09h36
  4. Réponses: 2
    Dernier message: 20/03/2002, 23h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo