Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 01-01-2010 10:21:20

eilijah
Membre
Date d'inscription: 17-02-2009
Messages: 20

__PHP_Incomplete_Class

Salut et Bonne année! big_smile

Je suis tombé sur ce problème pour un objet passé en session. Après maintes recherche j'ai fini par bidouiller pour le régler avec un :

Code:

$session->qr = unserialize(serialize($session->qr));

Mais bon ca me convient moyennement, mes compétences étant plus que limitées en ce qui concerne ZF j'imagine qu'il doit y'avoir d'autre moyens.
Pour le moment grâce au "Quickstart guid" dans mon bootstrap j'ai ceci :

Code:

    protected function _initAutoload()
    {
    // On enregistre les modules (les parties de notre application), souvenez-vous : Backend et Frontend
        $loader = new Zend_Application_Module_Autoloader(array(
            'namespace' => '',
            'basePath'  => APPLICATION_PATH));
        return $loader;
    }
    
    protected function _initSession()
    {
        // On initialise la session
        $session = new Zend_Session_Namespace('espritslibres', true);
        // chargement de la session dans le registre
        Zend_Registry::set('session', $session);
        return $session;
    }

Ce que je comprends donc c'est que le initSession initialise la session mais que l'autoloader va attendre un appel de la classe pour la charger ce qui fait que si dans mon contrôleur je souhaite créer un objet d'après un de mes modèles puis le passer en session bah forcement ma session ne connait pas la classe.

Je suis tomber sur ce post  : http://www.z-f.fr/forum/viewtopic.php?id=2082
Dans laquelle seikajin propose 3 solutions dont les 2 plus intéressantes sont :

Solution 1)  (ma préféré) tu convertis ton objet en stdClass object  avant de le mettre en session ainsi il peut voyager n'importe où (session échange de donnée sérialisés enregistrement dans un fichier etc.) on ne garde que les valeurs. mais tu perds la classe lorsque tu le récupère il te faut donc recréer l'instance si nécessaire.

Solution 2) mettre en marche le système autoload de Zend. la classe est chargée automatiquement par Zend à l'ouverture de la session et l'objet retrouve sa classe d'origine. Mais la classe sera systématiquement chargé même si tu ne t'en sert pas dans l'action courante. si tu ne fais pas correctement le ménage tu peut te retrouver à charger pas mal de chose inutile. (quelque soit la solution il faut toujours faire son ménage dans la session)

j'aimerai avoir des éclaircissements si possible sur ces 2 méthodes , comment convertir une classe en stdClass? Une fois que c'est fait j'imagine qu'il faudrait recréer une instance et faire une méthode spécifique pour reremplir l'instance?
Comment charger un certains nombre de classe au chargement de la session?

Enfin l'idéale ça serait qu'il y'ait un autre moyen parce que d'ici mon bidouillage parait presque plus simple, qu'en pensez vous? Comment pratiquez vous de votre coté?

PS: je suis sous ZF 1.9.6, et php 5.2.10

Dernière modification par eilijah (01-01-2010 10:31:22)

Hors ligne

 

#2 01-01-2010 13:41:16

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: __PHP_Incomplete_Class

Salut

pour la solution StdClass c'est très simple

Code:

$myObject = new MyClass();
$stdObj = (object)$myObject;

$stdObj est un objet de la classe StdClass. c'est une petit exception dans le cast de PHP qui normalement s'écrit

Code:

$myObject = new MyClass1();
$stdObj = (MyClass2)$myObject;

pour caster un objet de MyClass1 vers MyClass2 avec StdClass (la classe de base de tous les objets il faut utiliser (object) à la place de (StdClass)

mis à par cette subtilité l'objet $stdObj mis en session est un objet dont la classe et la classe de base lorsqu'il sortira de session ce sera donc un objet de classe StdClass
pour lui restituer sa classe d'origine à la lecture de la session il faut
faire l'opération inverse

Code:

$myObject = (MyClass)$session->get("theObject");

voilà pour le principe. on peut améliorer la chose en étant prévoyant par exemple écrire un interface qui prévoit le typage détypage les classes qui l'implémentent ont une méthode toStdClass() qui retourne l'objet sous forme de StdClass et un constructeur (la littérature poo par de constructeur de recopie) qui prends un objet et le transforme en objet de la classe on a ainsi la possibilité de transformer les objet de la classe pour pouvoir les mettre en session ou autre (exp les envoyer dans un flux de donnée)

Code:

$myObject = new MyClass();
$stdObj = $myObject->toStdClass();

et

Code:

$myObject = new MyClass($session->get("theObject"));

cette solution offre l'avantage de permettre le transport des données seules, des objets. que ce soit par la session ou pour tout échange entre process. de plus les données sont directement exploitable dans l'échange. I.E. ont peut les lire et les utiliser sans avoir à les transformer. il n'y a que si on veux utiliser le type d'origine qu'il faut intervenir.

On peut noter au passage qu'il est possible d'utiliser une autre classe que la classe d'origine. imaginez par exemple une application php de RH qui utilise une classe Personne définissant une personne au sein de l'entreprise. cette application envois un par ce moyen un objet personne à une autre application qui va l'utiliser pour représenter un utilisateur à l'arrivé il suffit de transformer les données en Utilisateur.

la deuxième solution "Autoload" à l'avantage d'êtres très simple à mettre en oeuvre. mais il faut faire attention à ne pas mettre trop d'objets avec des classes différentes car alors toutes les classes et les classes parentes seront chargées. par exemple Ne pas mettre un Row-object issue de la basse de donnée
en effet celui-ci contient deux fois les données (avant et après modification des données) plus une référence à la Table d'où est issue l'objet (cet objet table sera donc copié en session) lui même contient un objet DB qui sera aussi copié en session. donc à l'ouverture de la session (donc dans chaque action) si c'est objet est présent dans la session ce sont toutes les classes Zend_Db qui seront chargées imaginé donc que vous ayez mis de nombreux objets vous allez charger une multitude de classes à chaque fois.
cette solution est donc à utiliser avec précaution.

enfin il y a une troisième voie. utiliser la sérialisation.
dans cette solution avant la mise en session on fait appel à une sérialisation (serialize de php, ou Json, ou XML et tout ce que vous pouvez imaginer de la sorte) on obtient donc une string qui représente l'objet.
c'est cette chaîne qui est mise en session ou dans le flux d'échange. nous n'avons donc plus d'objet en session mais des chaînes donc pas de pbp de classe. à la lecture de l'élément dans la session on désérialize (il faut soit avoir chargé les classe adéquates soit avoir un autoload)  c'est simple est efficace. mais les données de la session ne sont pas exploitable sans désérialiser.

http://sekaijin.ovh.org/?p=34
dans cet article je parle de l'utilisation de la session pas directement de ces méthodes mais l'exemple utilise la première approche.

A+JYT

Hors ligne

 

#3 03-01-2010 11:37:02

eilijah
Membre
Date d'inscription: 17-02-2009
Messages: 20

Re: __PHP_Incomplete_Class

Merci pour cette grande réponse Seikajin,

je suis passé sur ton blog c'est très intéréssant également! J'ai pas encore lut l'article que tu pointes la j'ai commencé par celui d'avant!

Bon quelques questions ta réponses m'a apporter egalement quelques question smile
Après un cast d'objet standard est ce que l'objet est plus leger que l'original ? (vu qu'il ne contient plus tout ce qui concerne la classe originale?)

Au sujet de la serialization il faut donc charger la classe durant le bootstrap en meme temps que l'intialisation de la session?
Ca reste un peu absurde pour des modules qui servent qu'une fois de temps en temps , y'a t il une solution pour ne charger la classe que dans certains cas?

Du coup cette histoire m'a fait pensé que pour mon appli il pourrait etre pratique de stocker un objet en BD. L'idée étant que lors d'un QCM si la personne s'en va, alors l'objet qcm est mit en DB avec son status (reponses des questions faites, question en cour, etc.).
Lorsque l'utilisateur se reconnecte, si le champ est plein, on recupére l'objet et il peut reprendre le questionnaire la ou il en était.
Bon je vois pas trop comment enregister l'objet "si il se deconnecte" (a moins de l'enregistrer a chaque question mais bon vla la charge sur la BD lol) mais pour le stockage vaudrait il mieux le "serializer" et le mettre sous forme de chaine? (ce qui me ramene au probleme de comment charger la classe dynamiquement !) ou est ce aussi bien de le mettre en tant que stdObj (est ce possible seulement? binaire?).

Je reconnais que ca fait beaucoup de questions , je vais expérimenter tout ca, mais si jamais vous avez des réponses ou des pistes merci d'avance!

cordialement, Eilijah

Dernière modification par eilijah (03-01-2010 11:40:40)

Hors ligne

 

#4 03-01-2010 13:28:44

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: __PHP_Incomplete_Class

un objet en php est en fait en mémoire une hash table en fait des couple clefs valeur
lorsque la valeur est un number  booléan la valeur est directement stockée en mémoire dans la valeur. lorsque c'est une string un tableau ou un objet la valeur est un pointeur vers une zone contenant les données.  donc un tableau ou un objet sont en fait très similaires. en plus de ça un objet contient un pointeur vers la définition de la classe.
(plus exactement vers le nom de la classe, toutes les classes définies sont listées par PHP dans une table il peu ainsi les retrouver)

l'objet à par le nom de la classe ne garde rien de la classe un StdClass object est exactement pareil il référence juste "StdClass"

si tu caste un objet en StdClass il sera identique à l'original à la référence de la classe près. je conseille de mettre en place une méthode toStdClass dans tes classes tu peux ainsi choisir quels sont les membres de tes objet que tu vas retourner et ainsi maîtriser ce qui vas transiter.

si tu serialise tu n'a pas besoin de charger les classes au bootstrap puisque ta session ne contient que des string
c'est lorsque dans ton code tu va lire une valeur dans la session que tu vas désérialiser et que tu auras donc besoin de charger les classes adéquates

pour finir oui la serialisation peut être utilisée pour stoquer des objet en base attention d'utiliser un conteneur assez grand (blob)

A+JYT

Hors ligne

 

#5 03-01-2010 17:13:35

eilijah
Membre
Date d'inscription: 17-02-2009
Messages: 20

Re: __PHP_Incomplete_Class

merci de tes reponses j'essairai d'implementé la method toStdObject , je te mettrais ce que j'ai fais pour que tu me dise ce que t'en pense smile

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages