Können Sie in PHP ein Objekt instanziieren und eine Methode in derselben Zeile aufrufen?

126

Was ich gerne machen würde, ist ungefähr so:

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

Anstatt zu tun:

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

Das Ergebnis ist mir in meinem speziellen Fall eigentlich egal. Aber gibt es eine Möglichkeit, dies zu tun?

weotch
quelle
4
Übrigens, wenn Sie 5.4 nicht verwenden (was Sie wahrscheinlich nicht verwenden), können Sie eine Hilfsfunktion definieren, die nur ein Objekt zurückgibt, um Dinge zu verketten ... Funktion mit ($ obj) {return $ obj; } (nahm den Trick von Laravel: P) .. dann können Sie mit (neuen Obj) -> Methode ()
kapv89
Übrigens, wenn Sie dies häufig tun, lohnt es sich zu überlegen, ob my_methodstattdessen deklariert werden sollte static.
ToolmakerSteve

Antworten:

166

Die von Ihnen angeforderte Funktion ist in PHP 5.4 verfügbar. Hier ist die Liste der neuen Funktionen in PHP 5.4:

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

Und der relevante Teil aus der Liste der neuen Funktionen:

Der Zugriff von Klassenmitgliedern auf die Instanziierung wurde hinzugefügt, z. B. (neues Foo) -> bar ().

Delian Krustev
quelle
9
Beachten Sie, dass dies auch bedeutet, dass Sie dies tun können, (new Foo)->propertywenn Sie möchten.
Dave1010
1
Beachten Sie, dass Sie auf diese Weise noch keine Eigenschaften zuweisen können. (neues Foo) -> property = 'property';
CMCDragonkai
7
@CMCDragonkai logischerweise macht das Sinn; Das Objekt existiert nur für die Dauer der Anweisung (new Foo)->property- der Wert, den Sie speichern, kann nirgendwo hingehen, da das Objekt danach nicht mehr existiert, da es nirgendwo gespeichert wird.
Thomasrutter
1
@CMCDragonkai Sie können Eigenschaften auf diese Weise zuweisen, indem Sie die entsprechenden Setter aufrufen. Sie müssen lediglich return $thisIhre Setter hinzufügen . Auf diese Weise können Sie auch Setter verketten.
Iloo
Ich habe eine Frage. Hat es einen Vorteil, das Objekt in einer separaten Zeile zu deklarieren und in einer Variablen zu speichern, außer das Objekt wiederverwenden zu können?
Tyler Swartzenburg
37

Sie können nicht tun, was Sie verlangen; Sie können jedoch "betrügen", indem Sie in PHP eine Funktion verwenden, die denselben Namen wie eine Klasse hat. Diese Namen werden nicht in Konflikt geraten.

Wenn Sie also eine Klasse wie diese deklariert haben:

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

Sie können dann eine Funktion deklarieren, die eine Instanz dieser Klasse zurückgibt - und genau denselben Namen wie die Klasse hat:

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

Und jetzt wird es möglich, einen Einzeiler zu verwenden, wie Sie gefragt haben - nur rufen Sie die Funktion auf und verwenden daher nicht new:

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

Und es funktioniert: hier bekomme ich:

int 20

als Ausgabe.


Und besser, Sie können Ihre Funktion mit Phpdoc versehen:

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

Auf diese Weise haben Sie sogar Hinweise in Ihrer IDE - zumindest mit Eclipse PDT 2.x; siehe den Screeshot:



Bearbeiten 30.11.2010: Nur zur Information wurde vor einigen Tagen ein neuer RFC eingereicht, der vorschlägt, diese Funktion einer der zukünftigen Versionen von PHP hinzuzufügen.

Siehe: Anforderung von Kommentaren: Instanz- und Methodenaufruf / Eigenschaftszugriff

Vielleicht ist es in PHP 5.4 oder einer anderen zukünftigen Version möglich, solche Dinge zu tun:

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

Sie können dies universeller tun, indem Sie eine Identitätsfunktion definieren:

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

identity(new Obj)->method();

Auf diese Weise müssen Sie nicht für jede Klasse eine Funktion definieren.

Tom Pažourek
quelle
10
Schöne Lösung, da sie die Dummheit dieser Einschränkung betont :)
Ole
19

Wie wäre es mit:

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

: P.

Jeff
quelle
16

Nein das ist nicht möglich.
Sie müssen die Instanz einer Variablen zuweisen, bevor Sie eine ihrer Methoden aufrufen können.

Wenn Sie dies wirklich nicht tun möchten, können Sie eine Fabrik nutzen, wie Ropstah vorschlägt:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();
Pim Jäger
quelle
4
Pims Antwort ist richtig. Alternativ können Sie statische Funktionen verwenden , wenn Sie eine Instanz des Objekts erstellen nicht wünschen
Mark
Damit sind wir gezwungen zu verwenden public static function statt zu verwenden public function. Wird empfohlen, statisch zu verwenden?
Ichimaru
6

Sie können eine statische Factory-Methode verwenden, um das Objekt zu erstellen:

ObjectFactory::NewObj()->method();
Ropstah
quelle
3
Keine separate Fabrik erforderlich; Eine statische Methode in derselben Klasse führt dasselbe aus.
Brilliand
3

Auch ich suchte nach einem Einzeiler, um dies als Teil eines einzelnen Ausdrucks zum Konvertieren von Daten von einem Format in ein anderes zu erreichen. Ich mache das gerne in einer einzigen Codezeile, weil es eine einzige logische Operation ist. Dies ist also ein wenig kryptisch, aber Sie können ein Datumsobjekt innerhalb einer einzelnen Zeile instanziieren und verwenden:

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

Eine andere Möglichkeit, die Konvertierung von Datumszeichenfolgen von einem Format in ein anderes einzeilig durchzuführen, besteht in der Verwendung einer Hilfsfunktion zum Verwalten der OO-Teile des Codes:

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

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

Ich denke, der objektorientierte Ansatz ist cool und notwendig, aber manchmal kann er langwierig sein und zu viele Schritte erfordern, um einfache Operationen durchzuführen.

CodeCavalier
quelle
0

Ich sehe, dass dies in Bezug auf Fragen ziemlich alt ist, aber hier ist etwas, von dem ich denke, dass es erwähnt werden sollte:

Mit der speziellen Klassenmethode "__call ()" können neue Elemente innerhalb einer Klasse erstellt werden. Sie verwenden es so:

<?php
class test
{

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

}

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

Die Ausgabe sollte sein:

I am here - new

Auf diese Weise können Sie PHP dazu verleiten, einen "neuen" Befehl innerhalb Ihrer Klasse der obersten Ebene (oder einer beliebigen Klasse) zu erstellen, und Ihren Befehl include in die Funktion __call () einfügen, um die von Ihnen angeforderte Klasse einzuschließen. Natürlich möchten Sie wahrscheinlich $ func testen, um sicherzustellen, dass es sich um einen "neuen" Befehl handelt, der an den Befehl __call () gesendet wurde, und (natürlich) Sie könnten auch andere Befehle haben, weil __call () funktioniert.

Mark Manning
quelle
0

Wir können das einfach tun

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