2008-10-10 4 views
9

un langage couramment utilisé dans les langages OO comme Python et Ruby est instanciation d'un objet et l'enchaînement des méthodes qui renvoient une référence à l'objet lui-même, tels que:Instance de classe "Inline" en PHP? (Pour la facilité de la méthode Chaining)

s = User.new.login.get_db_data.get_session_data 

En PHP, il est possible de reproduire ce comportement comme ceci:

$u = new User(); 
$s = $u->login()->get_db_data()->get_session_data(); 

Essayer les résultats suivants dans syntax error, unexpected T_OBJECT_OPERATOR:

$s = new User()->login()->get_db_data()->get_session_data(); 

Il semble que cela pourrait être accompli en utilisant des méthodes statiques, ce qui est probablement ce que je finirai par faire, mais je voulais vérifier le lazyweb: Y at-il réellement un moyen propre et simple d'instancier les classes PHP "inline" (comme le montre dans l'extrait ci-dessus) à cette fin?

Si je décide d'utiliser des méthodes statiques, est trop sorcerous d'avoir une méthode statique de classe retourne une instanciation de la classe elle-même? (Écrire efficacement mon propre constructeur-ce-qui-n'est-pas-un-constructeur?) Il se sent un peu sale, mais s'il n'y a pas trop d'effets secondaires effrayants, je pourrais le faire.

Je suppose que je pourrais aussi pré-instancier une UserFactory avec une méthode get_user(), mais je suis curieux de connaître les solutions à ce que j'ai demandé ci-dessus.

+4

Depuis PHP 5.4 les travaux suivants: '(new User()) -> login() -> ...', voir [Changelog PHP] (http://php.net/ChangeLog-5.php) pour 5.4 .0 * "Ajout d'un membre de classe à l'instanciation (par exemple (new foo) -> bar()) support "* – hakre

Répondre

12

Toutes ces solutions proposées compliquons votre code pour plier PHP pour accomplir une certaine finesse syntaxique. Vouloir que PHP soit quelque chose que ce n'est pas (comme le bien) est le chemin de la folie.

Je voudrais simplement utiliser:

$u = new User(); 
$s = $u->login()->get_db_data()->get_session_data(); 

Il est clair, relativement concise et implique pas magie noir qui peut introduire des erreurs.

Et bien sûr, vous pouvez toujours passer à Ruby ou Python. Cela changera votre vie.

  • Et oui, je suis dur sur PHP. Je l'utilise tous les jours. Je l'utilise depuis des années. La réalité est qu'il a accrété, plutôt que d'être conçu et cela se voit.
+0

Je préfère Ruby, puis Python, puis PHP, mais je programme régulièrement dans les trois. –

+1

Ouais ... la plus grande leçon que j'ai apprise avec PHP est que vous devez couper avec le grain. Travailler avec PHP et c'est génial, mais commencez à le vouloir être différent et vous allez creuser votre propre trou. –

+0

Eh bien au moins j'ai maintenant la confirmation que vous ne pouvez pas faire cela. Pouvez-vous m'indiquer où dans la référence du langage PHP qui dit pourquoi vous ne pouvez pas faire cela? Argh. –

8
<?php 

    class User 
    { 
     function __construct() 
     { 
     } 

     function Login() 
     { 
      return $this; 
     } 

     function GetDbData() 
     { 
      return $this; 
     } 

     function GetSession() 
     { 
      return array("hello" => "world"); 
     } 
    } 

    function Create($name) 
    { 
     return new $name(); 
    } 

    $s = Create("User")->Login()->GetDbData()->GetSession(); 

    var_dump($s); 
?> 

Ceci est une solution possible :) Bien sûr, vous devez choisir un meilleur nom pour la fonction ...

Ou si vous ne me dérange pas un peu de frais généraux:

<?php 

    class User 
    { 
     function __construct($test) 
     { 
      echo $test; 
     } 
... 
    } 

    function CreateArgs($name) 
    { 
     $ref = new ReflectionClass($name); 
     return $ref->newInstanceArgs(array_slice(func_get_args(), 1)); 
    } 

    $s = CreateArgs("User", "hi")->Login()->GetDbData()->GetSession(); 

    var_dump($s); 
?> 
+0

Merci, j'ai accepté la réponse de l'autre, mais si je pouvais en accepter deux, j'accepterais aussi la tienne. –

5

La seule façon d'obtenir quelque chose de similaire est avec une méthode statique d'usine ou de singleton. Par exemple:

class User 
{ 
    //... 
    /** 
    * 
    * @return User 
    */ 
    public static function instance() 
    { 
     $args = func_get_args(); 
     $class = new ReflectionClass(__CLASS__); 
     return $class->newInstanceArgs($args); 
    } 
    //... 
} 

qui utilise l'API de réflexion de PHP5 pour créer une nouvelle instance (en utilisant les args envoyés à :: instance()) et le retourne, vous permettant de faire l'enchaînement:

$s = User::instance()->login()->get_db_data()->get_session_data(); 

D'ailleurs, ce code est assez flexible pour que la seule chose que vous ayez à changer lorsque vous copiez cette méthode statique est le @return du commentaire PHPDoc.


Si vous souhaitez optimiser prématurément votre code comme notre ami Nelson, vous pouvez remplacer le contenu de l'utilisateur :: instance() avec:

return new self(); 
+1

L'utilisation de la réflexion ne vaut pas l'overhead lorsque vous faites l'approche de la méthode statique Vous ne devez pas ajouter un overhead lorsque l'overhead n'est pas nécessaire;) – nlaq

+0

Ou nous pouvons suivre les standards pour envoyer des arguments Vous n'avez pas besoin de mettre à jour constamment la méthode instance() lorsque vous modifiez le __construct() – dcousineau

+0

Il est simplement idiot de faire quelque chose en sachant que la même chose peut être faite plus rapidement: "prématurément optimiser" est différent de "faire preuve de bon sens". "Et ma solution ne nécessite pas de copier + coller le code non plus - Cependant je parie que nous pouvons tous les deux convenir qu'un modèle d'usine devrait être utilisé de toute façon :) – nlaq

5

Il n'y a aucune raison de coller ensemble un hack (pour contourner le problème de syntaxe) et le code de création d'objet lui-même.

Depuis une nouvelle expression ne peut pas être utilisé comme élément de gauche de votre opérateur objet, mais une expression d'appel de fonction peut, il vous suffit d'envelopper votre objet dans un appel à une fonction qui renvoie son propre argument:

function hack($obj) { return $obj; } 

$mail = hack(new Zend_Mail()) 
    -> setBodyText('This is the text of the mail.') 
    -> setFrom('[email protected]', 'Some Sender') 
    -> addTo('[email protected]', 'Some Recipient') 
    -> setSubject('TestSubject'); 
+0

Cette méthode fonctionne plutôt bien ... – Nick

3

Un raccourci simple à

$Obj = new ClassName(); 
$result = $Obj->memberFunction(); 

est

$result = (new ClassName())->memberFunction(); 
1
<?php 
//PHP 5.4+ class member access on instantiation support. 
$s = (new User())->login()->get_db_data()->get_session_data(); 
Questions connexes