In PHP, puoi creare un'istanza di un oggetto e chiamare un metodo sulla stessa linea?


126

Quello che vorrei fare è qualcosa del genere:

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

Invece di dover fare:

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

Il risultato in realtà non mi interessa nel mio caso specifico. Ma c'è un modo per farlo?


4
tra l'altro, se non si utilizza 5.4 (cosa che probabilmente non si è), è possibile definire una funzione di supporto che restituisce semplicemente un oggetto alla catena ... funzione con ($ obj) {return $ obj; } (raccolto il trucco da laravel: P) .. quindi puoi fare con (nuovo Obj) -> metodo ()
kapv89

A proposito, se ti ritrovi a farlo spesso, vale la pena considerare se my_methoddebba invece essere dichiarato static.
ToolmakerSteve

Risposte:


167

La funzione richiesta è disponibile da PHP 5.4. Ecco l'elenco delle nuove funzionalità in PHP 5.4:

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

E la parte pertinente dall'elenco delle nuove funzionalità:

È stato aggiunto l'accesso dei membri della classe all'istanza, ad es. (Nuovo Foo) -> bar ().


9
Nota che questo significa anche che puoi farlo (new Foo)->propertyse lo desideri.
dave1010,

1
Si noti che non è ancora possibile assegnare proprietà in questo modo. (nuovo Foo) -> property = 'property';
CMCDragonkai,

7
@CMCDragonkai logicamente ha senso; l'oggetto esiste solo per la durata dell'istruzione (new Foo)->property- il valore che stai memorizzando non ha un posto dove andare perché l'oggetto non esisterà più dopo che non è memorizzato da nessuna parte.
thomasrutter,

1
@CMCDragonkai Puoi assegnare le proprietà in questo modo chiamando i setter corrispondenti , tutto quello che devi fare è aggiungere return $thisai tuoi setter. Questo ti permetterà anche di incastonare i setter.
iloo,

Ho una domanda. C'è qualche vantaggio nel dichiarare l'oggetto su una riga separata e salvarlo in una variabile, oltre a poter riutilizzare l'oggetto?
Tyler Swartzenburg,

37

Non puoi fare quello che stai chiedendo; ma puoi "imbrogliare", usando il fatto che, in PHP, puoi avere una funzione che ha lo stesso nome di una classe; quei nomi non saranno in conflitto.

Quindi, se hai dichiarato una classe come questa:

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

È quindi possibile dichiarare una funzione che restituisce un'istanza di quella classe - e ha esattamente lo stesso nome della classe:

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

E ora, diventa possibile usare un one-liner, come hai chiesto - l'unica cosa è che stai chiamando la funzione, quindi non usando new:

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

E funziona: ecco, sto ottenendo:

int 20

come uscita.


E, meglio, puoi mettere un po 'di phpdoc sulla tua funzione:

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

In questo modo, avrai anche suggerimenti nel tuo IDE, almeno con Eclipse PDT 2.x; vedi lo screeshot:



Modifica 30/11/2010: Solo per informazione, pochi giorni fa è stato presentato un nuovo RFC che propone di aggiungere questa funzionalità a una delle versioni future di PHP.

Vedere: Richiesta di commenti: chiamata di istanza e metodo / accesso alla proprietà

Quindi, forse fare cose come queste sarà possibile in PHP 5.4 o in un'altra versione futura:

(new foo())->bar()
(new $foo())->bar
(new $bar->y)->x
(new foo)[0]

19

Puoi farlo in modo più universale definendo una funzione di identità:

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

identity(new Obj)->method();

In questo modo non è necessario definire una funzione per ogni classe.


10
Bella soluzione in quanto enfatizza la stupidità di questa limitazione :)
Ole

19

Che ne dite di:

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

: P


16

No, non è possibile.
Devi assegnare l'istanza a una variabile prima di poter chiamare uno dei suoi metodi.

Se davvero non vuoi farlo, potresti usare una fabbrica come suggerisce ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();

4
La risposta di Pim è corretta. In alternativa, è possibile utilizzare le funzioni statiche se non si desidera creare un'istanza dell'oggetto
Mark

usando questo, siamo costretti a usare al public static functionposto di public function. Si consiglia di utilizzare statico?
ichimaru,

6

È possibile utilizzare un metodo factory statico per produrre l'oggetto:

ObjectFactory::NewObj()->method();

3
Non c'è bisogno di una fabbrica separata; un metodo statico nella stessa classe realizzerà la stessa cosa.
Brilliand,

3

Anch'io stavo cercando un one-liner per realizzare questo come parte di una singola espressione per convertire le date da un formato all'altro. Mi piace farlo in una singola riga di codice perché è una singola operazione logica. Quindi, questo è un po 'criptico, ma ti consente di creare un'istanza e utilizzare un oggetto data all'interno di una singola riga:

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

Un altro modo per convertire in una riga le stringhe di date da un formato a un altro è utilizzare una funzione di supporto per gestire le parti OO del codice:

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

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

Penso che l'approccio orientato agli oggetti sia interessante e necessario, ma a volte può essere noioso, richiedendo troppi passaggi per eseguire operazioni semplici.


0

Vedo che questo è piuttosto vecchio man mano che le domande vanno, ma ecco qualcosa che penso dovrebbe essere menzionato:

Il metodo di classe speciale chiamato "__call ()" può essere utilizzato per creare nuovi elementi all'interno di una classe. Lo usi in questo modo:

<?php
class test
{

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

}

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

L'output dovrebbe essere:

I am here - new

Pertanto, puoi ingannare PHP nel creare un "nuovo" comando all'interno della tua classe di livello superiore (o qualsiasi classe realmente) e inserire il tuo comando include nella funzione __call () per includere la classe che hai richiesto. Ovviamente, probabilmente vorrai testare $ func per assicurarti che sia un "nuovo" comando che è stato inviato al comando __call () e (ovviamente) potresti avere altri comandi anche a causa del funzionamento di __call ().


0

Semplicemente possiamo farlo

$method_result = (new Obj())->method();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.