En PHP, pouvez-vous instancier un objet et appeler une méthode sur la même ligne?

126

Ce que je voudrais faire est quelque chose comme ceci:

$method_result = new Obj()->method();

Au lieu d'avoir à faire:

$obj = new Obj();
$method_result = $obj->method();

Le résultat n'a pas vraiment d'importance pour moi dans mon cas spécifique. Mais, y a-t-il un moyen de faire cela?

weotch
la source
4
btw, si vous n'utilisez pas 5.4 (ce que vous n'êtes probablement pas), vous pouvez définir une fonction d'assistance qui renvoie simplement un objet pour enchaîner des trucs ... fonction avec ($ obj) {return $ obj; } (choisi l'astuce de laravel: P) .. alors vous pouvez faire avec (new Obj) -> method ()
kapv89
BTW, si vous vous retrouvez à faire cela souvent, il vaut la peine de se demander s'il my_methodfaut plutôt le déclarer static.
ToolmakerSteve

Réponses:

167

La fonctionnalité que vous avez demandée est disponible à partir de PHP 5.4. Voici la liste des nouvelles fonctionnalités de PHP 5.4:

http://php.net/manual/en/migration54.new-features.php

Et la partie pertinente de la liste des nouvelles fonctionnalités:

L'accès des membres de la classe lors de l'instanciation a été ajouté, par exemple (new Foo) -> bar ().

Delian Krustev
la source
9
Notez que cela signifie également que vous pouvez le faire (new Foo)->propertysi vous le souhaitez.
dave1010
1
Notez que vous ne pouvez pas encore attribuer de propriétés de cette manière. (new Foo) -> property = 'propriété';
CMCDragonkai
7
@CMCDragonkai logiquement, cela a du sens; l'objet n'existe que pendant la durée de l'instruction (new Foo)->property- la valeur que vous stockez n'a nulle part où aller car l'objet n'existera plus après cela car il n'est stocké nulle part.
thomasrutter
1
@CMCDragonkai Vous pouvez attribuer des propriétés de cette façon en appelant les setters correspondants , tout ce que vous avez à faire est d'ajouter return $thisà vos setters. Cela vous permettra également d'enchaîner les setters.
iloo
J'ai une question. Y a-t-il un avantage à déclarer l'objet sur une ligne séparée et à l'enregistrer dans une variable, autre que de pouvoir réutiliser l'objet?
Tyler Swartzenburg
37

Vous ne pouvez pas faire ce que vous demandez; mais vous pouvez "tricher", en utilisant le fait qu'en PHP, vous pouvez avoir une fonction qui a le même nom qu'une classe; ces noms ne seront pas en conflit.

Donc, si vous avez déclaré une classe comme celle-ci:

class Test {
    public function __construct($param) {
        $this->_var = $param;
    }
    public function myMethod() {
        return $this->_var * 2;
    }
    protected $_var;
}

Vous pouvez ensuite déclarer une fonction qui renvoie une instance de cette classe - et qui porte exactement le même nom que la classe:

function Test($param) {
    return new Test($param);
}

Et maintenant, il devient possible d'utiliser un one-liner, comme vous l'avez demandé - la seule chose est que vous appelez la fonction, donc n'utilisez pas new:

$a = Test(10)->myMethod();
var_dump($a);

Et ça marche: ici, je reçois:

int 20

comme sortie.


Et, mieux, vous pouvez mettre du phpdoc sur votre fonction:

/**
 * @return Test
 */
function Test($param) {
    return new Test($param);
}

De cette façon, vous aurez même des indices dans votre IDE - au moins, avec Eclipse PDT 2.x; voir le screeshot:



Edit 2010-11-30: Juste pour information, une nouvelle RFC a été soumise, il y a quelques jours, qui propose d'ajouter cette fonctionnalité à l'une des futures versions de PHP.

Voir: Request for Comments: Instance et méthode call / property access

Donc, peut-être que faire des choses comme celles-ci sera possible dans PHP 5.4 ou dans une autre version future:

(new foo())->bar()
(new $foo())->bar
(new $bar->y)->x
(new foo)[0]
Pascal MARTIN
la source
19

Vous pouvez le faire plus universellement en définissant une fonction d'identité:

function identity($x) {
    return $x;
}

identity(new Obj)->method();

De cette façon, vous n'avez pas besoin de définir une fonction pour chaque classe.

Tom Pažourek
la source
10
Belle solution car elle souligne la stupidité de cette limitation :)
Ole
19

Que diriez-vous:

$obj = new Obj(); $method_result = $obj->method(); // ?

: P

Jeff
la source
16

Non, ce n'est pas possible.
Vous devez affecter l'instance à une variable avant de pouvoir appeler l'une de ses méthodes.

Si vous ne voulez vraiment pas faire cela, vous pouvez utiliser une usine comme le suggère ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();
Pim Jager
la source
4
La réponse de Pim est correcte. Sinon, vous pouvez utiliser des fonctions statiques si vous ne souhaitez pas créer une instance de l'objet
Mark
en utilisant cela, nous sommes obligés d'utiliser public static functionau lieu de public function. Est-il recommandé d'utiliser statique?
ichimaru le
6

Vous pouvez utiliser une méthode de fabrique statique pour produire l'objet:

ObjectFactory::NewObj()->method();
Ropstah
la source
3
Pas besoin d'une usine séparée; une méthode statique de la même classe accomplira la même chose.
Brilliand
3

Moi aussi, je cherchais un one-liner pour accomplir cela dans le cadre d'une seule expression pour convertir les dates d'un format à un autre. J'aime faire cela en une seule ligne de code car c'est une seule opération logique. Donc, c'est un peu cryptique, mais cela vous permet d'instancier et d'utiliser un objet date sur une seule ligne:

$newDateString = ($d = new DateTime('2011-08-30') ? $d->format('F d, Y') : '');

Une autre façon de convertir une ligne de chaînes de date d'un format à un autre consiste à utiliser une fonction d'assistance pour gérer les parties OO du code:

function convertDate($oldDateString,$newDateFormatString) {
    $d = new DateTime($oldDateString);
    return $d->format($newDateFormatString);
}

$myNewDate = convertDate($myOldDate,'F d, Y');

Je pense que l'approche orientée objet est cool et nécessaire, mais elle peut parfois être fastidieuse, nécessitant trop d'étapes pour accomplir des opérations simples.

CodeCavalier
la source
0

Je vois que c'est assez ancien au fil des questions, mais voici quelque chose qui, je pense, devrait être mentionné:

La méthode de classe spéciale appelée "__call ()" peut être utilisée pour créer de nouveaux éléments à l'intérieur d'une classe. Vous l'utilisez comme ceci:

<?php
class test
{

function __call($func,$args)
{
    echo "I am here - $func\n";
}

}

    $a = new test();
    $a->new( "My new class" );
?>

La sortie doit être:

I am here - new

Ainsi, vous pouvez tromper PHP en créant une "nouvelle" commande à l'intérieur de votre classe de niveau supérieur (ou de n'importe quelle classe en fait) et mettre votre commande include dans la fonction __call () pour inclure la classe que vous avez demandée. Bien sûr, vous voudrez probablement tester $ func pour vous assurer que c'est une "nouvelle" commande qui a été envoyée à la commande __call () et (bien sûr) vous pourriez avoir d'autres commandes aussi à cause du fonctionnement de __call ().

Mark Manning
la source
0

Nous pouvons simplement le faire

$method_result = (new Obj())->method();
Aruna Perera
la source