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 :

[POO] Reference dynamique à $this [PHP 5.2]


Sujet :

Langage PHP

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut [POO] Reference dynamique à $this
    Bonjour,
    je développe un code qui doit me permettre selon un fichier de configuration d'appeler dynamiquement une méthode d'un objet PHP.

    Peu importe le fichier, en gros, je passe un nom de variable et le nom d'une méthode, et eventuellement une liste de parametres.

    Tout fonctionne très bien, sauf pour deux cas

    1- la pseudo variable this. Le code suivant (pour test), ne fonctionne pas et retourne "unknown this variable" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $a = "this"; // également essayé avec $a="$this"
    $b = $$a; // atendu: $a = $this
    l'erreur est provoquée dès l'instruction 2 - En utilisant call_user_func, je n'arrive pas à passer autre chose qu'une référence d'objet. Par exemple si j'ai besoin de passer comme objet qui retourne un objet, ca ne fonctionne pas. Le code serait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $obj = new Request();
    $a = "obj->getRequest"; // essayé avec "$this->getRequest()"
    $b = $$a; // erreur


    Quelqu'un a-t-il une solution ?

    Pour le moment ma seule solution est d'utiliser la fonction PHP "eval", mais je ne la trouve pas très adaptée à mon cas.

    Merci !

  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
    Te précipite pas, laisse un peu de temps pour rédiger

    Ou alors, ton problème serait peut être un souci d'accessibilité d'une méthode, en d'autre terme, il faudrait que la methode getRequest() soit static.
    Ce qui permettrait d'y accéder de la façon suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Request::getRequest();
    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
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    Salut,
    non, le but est de le faire en dynamique...

    Donc effectivement, ce que je veux faire est ce que tu écris, mais sans savoir à l'avance quelle variable "objet" ni quelle methode je vais utiliser.

  4. #4
    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
    Merd**, cette fois, c'est moi qui me précipite, j'ai modifié mon post au lieu de répondre

    Et une méthode static alors ?
    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]

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    Bon, voilà mon code qui fonctionne.
    Je voudrais simplement ne pas faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $phpEvalScript = '$object = '.$phpObj.';';
    $r = eval($phpEvalScript);
    le code qui fonctionne à tous les coups :
    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
    $phpObj = (string)$param['object']; // get object from param
    // put object reference into "$object" variable
    $phpEvalScript = '$object = '.$phpObj.';';
    $r = eval($phpEvalScript);
    if ($r != false || isset($r)==false)
    	{
    		$phpMethod = (string)$param['method'];
    		$phpMethParams = array();
     
    		// read method params if any
    		foreach ($param->children() as $chilParam){
    			$p = (string)$childParam;
    			array_push($phpMethParams,$p);
    		}
    		// call php object method
    		$phpResult = call_user_func(array($object,$phpMethod));
    		if (isset($phpResult)) $jsonVal = Zend_Json_Encoder::encode($phpResult);
    	}

  6. #6
    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
    Qelle valeur (ou contenu) vaut : $phpObj ?
    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]

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    La variable $phpObj contient ce que j'ecris dans un fichier XML, soit le nom d'une variable PHP correspondant à un objet.

    En l'occurence je lui passe "$this" (ou juste "this", mais ca ne marche pas mieux).

    Mais $phpObj peut contenir n'importe quel autre nom, par exemple "$mysql", "$toto" etc...

    Donc si $phpObj contient une variable, par exemple "toto" (qui serait instanciée dans le code), $a = $$phpObj fonctionne, mais pas avec "this".

    Et de toutes façons, je viens de voir que si je fais $phpObj = "toto->methodeA", le call_user_func( array($$phpObj,$method) ); ne fonctionne pas (en considerant que $toto->methodeA() retourne un objet)

    Je pense que j'ai vraiment besoin de faire un eval et de mettre le résultat dans une variable $object.

    En fait le but de tout ce code, est de passer des variables de mon controller PHP dans dans proprietes d'une classe javascript (oui, c'est un peu compliqué !)

  8. #8
    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
    Je vois un peu mieux.

    Donc si $phpObj contient une variable, par exemple "toto" (qui serait instanciée dans le code), $a = $$phpObj fonctionne, mais pas avec "this".

    Et de toutes façons, je viens de voir que si je fais $phpObj = "toto->methodeA", le call_user_func( array($$phpObj,$method) ); ne fonctionne pas (en considerant que $toto->methodeA() retourne un objet)
    Pourquoi utilise tu : $$phpObj (2 $$) au lieu de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $object = call_user_func(array($phpObj, $method));
    Ou alors :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $objDynamique = new $phpObj;
    $object = call_user_func(array($objDynamique, $method));
    Il me semble que les double $$ c'était la syntaxe Php4 pour accéder à un objet, mais Php4 j'ai jamais utilisé, donc je ne sais pas trop.
    En tout cas, j'ai jamais utiliser cette syntaxe (les 2 $$).
    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]

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    Ha oui, mais $phpObj est une chaine de caractere !! Donc le but du $$ est d'obtenir une reference à une variable (ou objet, c'est pareil). Et non, le $$ est aussi utilisé dans PHP5, cette technique est comparable aux pointeurs en C++.

    Il faut bien garder à l'esprit que ce que je veux, c'est obtenir une référence à une variable (ou objet) à partir de son nom (en chaine de caractere).

    Exemple basique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $a = 5;
    $b = "a"; // nom de variable PHP en chaine de caractere
    $c = $$b; // $c est une reférence à $a
    echo $c; // affiche 5
    Merci pour ton aide !

  10. #10
    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

    Exemple basique :
    $a = 5;
    $b = "a"; // nom de variable PHP en chaine de caractere
    $c = $$b; // $c est une reférence à $a
    echo $c; // affiche 5
    Ok, mais si je reprend un exemple de la doc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $monobjet = new maclasse();
    call_user_func(array($monobjet, 'dit_bonjour'));
    $monobjet est normalement une référence à maclasse() qui a été instancié juste avant.

    Dans ton cas, si l'objet est instancié avant, et que les 2 noms son les mêmes, elle sera prise en référence.
    Par contre, si le nom ($phpObjet) est différent du nom de l'instance, ou qu'il n'y pas eu d'instanciation, alors pour accéder à cette méthode il faudra la rendre static.
    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]

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    Oui, sauf que dans mon cas, la variable $monobjet est passée en chaine de caractere (nom de variable en fait) via $a="monobjet".

    C'est là, tout l'interet de $$ ! c'est que $f = $$a est équivalent au code en dur de $f = $monobjet (ouai, c'est subtile les pointeurs !), sauf que moi, à l'ecriture du code, je ne sais pas encore quelle variable (objet) je vais appeler.

    Et il n'y a pas de rapport avec le fait que ce soit static ou pas, c'est uniquement avec "this" que ca marche pas (et ca, je ne sais pas pourquoi).

    Enfin bon, ca marche tres bien avec la fonction "eval", donc je laisse comme ca.

  12. #12
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    $this n'est pas une variable normale. C'est un 'placeholder' manipulé par l'engine et qui référence l'objet courant. Ca ne fonctionne pas avec les "variable variable" (la syntaxe $$)

    Toujours est-il que ton problème est très simple à résoudre, sachant que $this ne se comporte pas comme tout le monde

    Sans eval() et grosso modo d'après ton code d'exemple, tu pourrais faire ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $phpObj = $param['object'] == 'this' ? $this : ${$param['object']};
    Vois-tu l'astuce ?

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    Salut metagoto,
    effectivement, je vois l'astuce, j'avais envisagé ce test pour identifier "this", mais j'ai un autre probleme.

    C'est que si dans mon parametrage je passe "this->getRequest()" (getRequest renvoie un objet), ton astuce ne fonctionne pas.

    Je pourrais aussi avoir "this->getRequest()->getObject()" et ainsi de suite...

    C'est pour ca que je ne trouve pas d'autre solution que "eval" !

  14. #14
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Tu n'auras effectivement pas d'autre choix que d'utiliser eval() si tu passes de véritable portions de code sous forme de chaine, car c'est de ça qu'il s'agit.

    Une autre possibilité probablement plus clean, serait de passer la liste des méthodes (par exemple getRequest, getObject) sous forme d'entités distinctes, genre dans un array (ou n'importe quel équivalent simplexml car c'est ce que tu utilises on dirait).

    Ensuite une boucle pour caller la méthode courante sur l'objet retourné par l'appel à la méthode précédente. Voici un code radipos en guise d'exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $methods = array('getRequest', 'getObject');
    $phpObj = $param['object'] == 'this' ? $this : ${$param['object']};
     
    function apply($obj, $method) {
      return $obj->$method();
    }
     
    $finalObj = array_reduce($methods, 'apply', $phpObj);
    $finalObj serait le résultat de "this->getRequest()->getObject()", mais sans utiliser eval(). On notera que j'ai utilisé array_reduce qui autorise de passer un objet initial en 3iem paramètre. Sur php5.2, ce 3iem paramètre ne peut être qu'un integer. Il faudra donc que tu transformes l'équivalent de array_reduce en une simple boucle foreach par exemple (ou n'importe quel autre technique pour passer l'obj initial, genre une property d'un functor, cad utiliser une méthode membre plutôt qu'une free function).

  15. #15
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    Super interessante cette méthode, c'est exactement ce que je cherchais !
    Je pense que je vais faire un "split" sur la chaine "->" pour avoir la liste des methodes s'il y en a plusieurs (la premiere occurence du split sera donc toujours la reference de l'objet).

    Du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    // à mettre dans une methode evidemment...
    function apply($obj, $method) {
      return $obj->$method();
    }
     
    $objects = split ('->',$param['object']);
    $phpObj = $objects[0] == 'this' ? $this : ${$objects[0]};
    for ($i=1;$i++;$i<sizeof($objects)){
       $finalObj = array_reduce($$objects[$i], 'apply', $finalObj);
    }
    Beaucoup plus clean que mon "eval", j'aime beaucoup plus ce style.

  16. #16
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2005
    Messages : 20
    Points : 8
    Points
    8
    Par défaut
    Alors mon code du dernier post était faux (pas eu le temps de le taper et tester !!), donc au cas où, je donne la version finale.
    Et encore merci à toi metaGoto pour ton aide précieuse !


    Alors, avec $param['object'] = "this->getRequest" (oui, vous aurez compris que j'utilise zend framework )

    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
    33
    34
    35
     
    $objectParam = (string)$param['object']; // get php object variable name from param
     
    // split param in case of method chain calls to get final object
    // and put object variable name into $objectParam
    $objects = preg_split('(->)',$objectParam);
    if ($objects!=false)
    {
    	$objectParam = $objects[0];
    	// remove first object from array for later chain method calls
    	unset ($objects[0]);
    	array_values($objects);
    }
     
    // does some tricks because we can't get a reference to "this" directly
    $phpObj = $objectParam == 'this'? $this:${$objectParam};
     
     
    // in case of methods call chains  : recursive method call to get the object reference
    if (sizeof($objects)!=0 && $objects!=false){
    	$this->_finalObject = $phpObj;
    	$phpObj = array_reduce($objects,array($this,'getPhpObj'),$phpObj);
    }
     
    // call method on object reference
    $phpMethod = (string)$param['method'];
    $phpMethParams = array();
     
    // read method params if any
    foreach ($param->children() as $chilParam){
    	$p = (string)$childParam;	array_push($phpMethParams,$p);
    }
    // call php object method
    $phpResult = call_user_func(array($phpObj,$phpMethod),$phpMethParams);
    $jsonVal = Zend_Json_Encoder::encode($phpResult);
    avec la méthode "getPhpObj" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    private function getPhpObj($object,$method){
    		return $object->$method();
    	}

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Poo reference d'une methode a un objet stocker dans $this
    Par magicshark dans le forum Langage
    Réponses: 4
    Dernier message: 30/04/2013, 22h42
  2. [POO] affectation dynamique d'une méthode à un objet
    Par Delphi-ne dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 17/02/2006, 21h17
  3. [POO] Variable Dynamique de Classe
    Par CNoob dans le forum Langage
    Réponses: 5
    Dernier message: 31/01/2006, 22h05
  4. Réponses: 6
    Dernier message: 24/01/2006, 18h50
  5. [POO] Modèle objet: this inutilisable dans certains cas?
    Par vlord dans le forum Général JavaScript
    Réponses: 13
    Dernier message: 13/08/2005, 10h41

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