Page 1 sur 2

__autoload, et SPL.

Posté : 20 juil. 2007, 14:04
par Hywan
Bonjour,

j'ai un soucis avec l'autoload.
Pour schématiser mon problème, on va dire que j'ai une classe A. Elle étend une classe B. Quand j'instancie un objet depuis A, j'aimerais qu'il se charge automatiquement grâce à l'autoload de la classe B. Donc, dans le constructeur de B, je mets spl_autoload_register(array($this, 'myAutoload'));. Pas de soucis.

En revanche, je dois créer plusieurs objets. C, D, E, tous étendus à B. Donc dans la pile de la spl_autoload, il enregistre toujours la même méthode de l'objet B. Pas de soucis. Sauf que j'ai d'autres arguments à prendre en compte, et SPL conserve ceux de ma première instance. Donc quand je suis à l'objet C, les paramètres pour l'autoload sont ceux de l'objet A.

J'ai pensé à spl_autoload_unregister();, mais ça ne change rien, et il ne fait même rien. Imaginons que je suis dans le cas C éténd B, je dis spl_autoload_unregister(array($this, 'myAutoload'));, le $this correspond à B qui est étendu par B, et par A. Si je pouvais supprimer B étendu par A, ce serait idéal. Ou alors vider la pile complètement.

Une autre solution ?

Posté : 20 juil. 2007, 22:48
par naholyr
Je dirais que tu ne prends pas le problème par le bon côté, car je ne suis pas convaincu qu'un système qui enregistre un autoload par objet soit un bon plan :?

Posté : 20 juil. 2007, 22:54
par Hywan
Oui, c'est ce que je pense.
Pour l'instant, j'ai « résolu » le problème avec une méthode. Mais ça ne me convient pas. Je vais tenter en dehors de l'objet, mais je risque de m'amuser un moment.

Si on pouvait passer des paramètres à la méthode qu'on enregistre avec spl_autoload, ce serait idéal ! On peut ? Je ne crois pas, le manuel ne dit rien.

Posté : 20 juil. 2007, 23:32
par titerm
la methode ou la fonction que tu enregistres pour l'autoload recoit automatiquement en parametre le nom de la classe ou de l'interface qui a déclanché la procédure d'autoload.

Un exemple.
define ('LIB' , "pathtoclass");
spl_autoload_register("myAutoloader");

function myAutoloader($class) {
	$final = LIB . $class .'.php';
	if(!is_readable($final)) {
		echo "Le fichier '$final' n'est pas lisible";
		return;
	}
	include $final;

	if(!class_exists($class,false) && !interface_exists($class,false)) {
		echo "Le fichier '$final' a été chargé mais aucune définition de la classe '$class' n'a été trouvée dedans";
	}
}

Posté : 21 juil. 2007, 11:48
par Hywan
Je parlais d'autres paramètres.

Posté : 21 juil. 2007, 13:13
par titerm
De quel autre parametre pourrais tu avoir besoin ???

A priori, l'autoloader est automatiquement appelé quand la définition d'un classe n'est pas connue. Et la seule chose dont a besoin la procédure, c'est le nom de la classe en question. Si tu as une classe C qui en étend une autre B qui en étend une autre A qui implément une interface I et que rien n'est connu, l'autoloader sera appelé automatiquement. D'abbord pour l'interface I, puis la classe A, B et enfin C.
J'ai du mal a comprendre ton soucis.

Posté : 21 juil. 2007, 13:30
par Hywan
Bah justement, j'ai l'impression qu'il ne reconnait pas mon __autoload ...
Je me replonge dans le problème aujourd'hui, je vous en dirais plus :)

Posté : 21 juil. 2007, 13:39
par titerm
bah si ton autoload est reconnu (fait un echo $class dedans) tu verras ce qu'il essai de charger

Après, il faut que tu soit strict dans tes regles de nommage de fichier.
Moi j'utilise l'autoload de la spl, j'ai plusieurs procédures d'autoload, 2 persos plus celle du zend framework. j'ai plusieurs centaines de classe et aucun pb.

Posté : 21 juil. 2007, 16:10
par Hywan
J'ai enfin trouvé mon problème.
Note : Exceptions thrown in __autoload function cannot be caught in the catch block and results in a fatal error.
J'avais compris que si une exception était lancée, on aurait une erreur fatale. Oui c'est le cas. Mais je pensais pas que le simple fait d'invoquer l'exception aurait le même comportement.

J'avais donc chercher autre chose, et je me suis méchament emmêler les pinceaux. Mais c'est bon, tout marche bien navette ;-)

Edit : Au passage, je me suis pris la tête car si une exception est lancée dans l'autoload, même les echo lancés avant l'exception ne sont pas affichés ...

Posté : 21 juil. 2007, 17:12
par Sékiltoyai
Note : Exceptions thrown in __autoload function cannot be caught in the catch block and results in a fatal error.
J'avais compris que si une exception était lancée, on aurait une erreur fatale. Oui c'est le cas. Mais je pensais pas que le simple fait d'invoquer l'exception aurait le même comportement.
Bah il n'y a aucune différence entre lancer une exception et ne pas la capturer. Le résultat est le même, elle va continuer à se répandre.
Mais si tu mets un try dans ta fonction, tu pourras la capturer.

Posté : 21 juil. 2007, 17:37
par Hywan
Oui, je devais être fatigué ... C'est surtout le fait qu'il m'affichait pas mon echo qui m'a conduit en erreur.

Posté : 21 juil. 2007, 19:20
par titerm
Sékiltoyai, le morceau de doc qu'il donne dit qu'une exception emise dans l'autoload ne peut pas etre capturé dans un bloc 'catch' et que le resultat est une erreur fatal.

Posté : 21 juil. 2007, 21:26
par Sékiltoyai
Sékiltoyai, le morceau de doc qu'il donne dit qu'une exception emise dans l'autoload ne peut pas etre capturé dans un bloc 'catch' et que le resultat est une erreur fatal.
C'est bizarre ca alors...

Posté : 21 juil. 2007, 22:51
par Hywan
Titerm a raison, je t'ai mal lu.
C'est ce qui m'a rendu fou, une erreur fatale efface les echos, et donc pas moyen de voir d'où venait mon erreur car j'avais pas fais attention à la note dans la documentation.

Moi qui prone toujours le manuel, ça m'apprendra :lol:.

En définitive : surtout pas d'exceptions dans l'autoload. Capturée ou jetée, dans aucun cas. J'ai juste fais un return false; si mon fichier n'existe pas, c'est tout.

On peut quand même lancer une exception avec une évaluation du code, mais jtrouvais ça trop crade, donc je l'ai pas fais. Vous pouvez voir les commentaires.
J'ai cru comprendre que la gestion des exceptions dans l'autoload était mal conçue car c'était un bug. Le bug peut être contourné avec eval. On peut s'attendre à une mise à jours pour les prochaines versions de PHP :).

Posté : 22 juil. 2007, 00:19
par titerm
En fait, moi j'ai mon propre gestionnaire d'exception. Il prend bien entendu en parametre une exception...

c'est qq chose du genre
function MyExceptionHandler(Exception $e) {
// mon systeme de dump 
}
et on l'enregistre via
set_exception_handler('MyExceptionHandler');

Ce qu'il est possible de faire alors dans l'autoload, c'est de simuler une exception.

Genre si je constate une erreur,

je fais un
MyExceptionHandler(new Exception("Le fichier '$final' n'est pas lisible"));
Ce qui instancie une nouvelle exeption mais ne la lance pas, et je la passe a mon exection Handler perso qui va faire mon dump perso. Au final, j'ai exactement le meme résultat visuelle mais je n'ai pas jeté d'exception.