Czy w PHP można utworzyć instancję obiektu i wywołać metodę w tej samej linii?

126

Chciałbym zrobić coś takiego:

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

Zamiast robić:

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

W moim konkretnym przypadku wynik nie ma dla mnie znaczenia. Ale czy jest na to sposób?

weotch
źródło
4
btw, jeśli nie używasz 5.4 (którym prawdopodobnie nie jesteś), możesz zdefiniować funkcję pomocniczą, która po prostu zwraca obiekt do łańcucha rzeczy ... funkcja z ($ obj) {return $ obj; } (wziął trik z laravel: P) .. wtedy możesz zrobić z (nowy Obj) -> metoda ()
kapv89
Swoją drogą, jeśli często to robisz, warto się zastanowić, czy my_methodzamiast tego powinno zostać zadeklarowane static.
ToolmakerSteve

Odpowiedzi:

166

Funkcja, o którą prosiłeś, jest dostępna w PHP 5.4. Oto lista nowych funkcji w PHP 5.4:

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

I odpowiednia część z listy nowych funkcji:

Dodano dostęp do klasy podczas tworzenia instancji, np. (Nowy Foo) -> bar ().

Delian Krustev
źródło
9
Pamiętaj, że oznacza to również, że możesz to zrobić, (new Foo)->propertyjeśli chcesz.
dave1010
1
Pamiętaj, że nie możesz jeszcze przypisywać właściwości w ten sposób. (nowy Foo) -> property = 'property';
CMCDragonkai
7
@CMCDragonkai logicznie ma to sens; obiekt istnieje tylko na czas trwania instrukcji (new Foo)->property- przechowywana wartość nie ma dokąd pójść, ponieważ po tym obiekt nie będzie już istniał, ponieważ nie jest nigdzie przechowywany.
thomasrutter
1
@CMCDragonkai Możesz przypisać właściwości w ten sposób, wywołując odpowiednie setery , wszystko, co musisz zrobić, to dodać return $thisdo swoich seterów. Pozwoli to również na tworzenie łańcuchów.
iloo
Mam pytanie. Czy jest jakaś korzyść z zadeklarowania obiektu w oddzielnym wierszu i zapisania go w zmiennej, poza możliwością ponownego użycia obiektu?
Tyler Swartzenburg,
37

Nie możesz zrobić tego, o co prosisz; ale możesz "oszukiwać", wykorzystując fakt, że w PHP możesz mieć funkcję, która ma taką samą nazwę jak klasa; te nazwy nie będą kolidować.

Więc jeśli zadeklarowałeś taką klasę:

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

Następnie możesz zadeklarować funkcję, która zwraca instancję tej klasy - i ma dokładnie taką samą nazwę jak klasa:

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

A teraz staje się możliwe użycie jednowierszowego, tak jak prosiłeś - jedyną rzeczą jest to, że wywołujesz funkcję, a więc nie używasz nowego:

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

I działa: tutaj otrzymuję:

int 20

jako wyjście.


I lepiej, możesz umieścić phpdoc w swojej funkcji:

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

W ten sposób będziesz miał nawet wskazówki w swoim IDE - przynajmniej w Eclipse PDT 2.x; zobacz screeshot:



Edycja 2010-11-30: Tak dla informacji, kilka dni temu przesłano nowy dokument RFC, w którym proponuje się dodanie tej funkcji do jednej z przyszłych wersji PHP.

Zobacz: Żądanie komentarzy: dostęp do instancji i wywołania metody / właściwości

Może więc robienie takich rzeczy będzie możliwe w PHP 5.4 lub innej przyszłej wersji:

(new foo())->bar()
(new $foo())->bar
(new $bar->y)->x
(new foo)[0]
Pascal MARTIN
źródło
19

Możesz to zrobić bardziej uniwersalnie, definiując funkcję tożsamości:

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

identity(new Obj)->method();

W ten sposób nie musisz definiować funkcji dla każdej klasy.

Tom Pažourek
źródło
10
Fajne rozwiązanie, bo podkreśla głupotę tego ograniczenia :)
Ole
19

Co powiesz na:

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

: P

Jeff
źródło
16

Nie, to niemożliwe.
Musisz przypisać instancję do zmiennej, zanim będziesz mógł wywołać którąkolwiek z jej metod.

Jeśli naprawdę nie chcesz tego zrobić, możesz użyć fabryki, jak sugeruje ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();
Pim Jager
źródło
4
Odpowiedź Pima jest prawidłowa. Alternatywnie możesz użyć funkcji statycznych, jeśli nie chcesz tworzyć instancji obiektu
Mark
używając tego, jesteśmy zmuszeni używać public static functionzamiast public function. Czy zaleca się używanie statyczne?
ichimaru
6

Do utworzenia obiektu można użyć statycznej metody fabryki:

ObjectFactory::NewObj()->method();
Ropstah
źródło
3
Nie ma potrzeby posiadania oddzielnej fabryki; metoda statyczna w tej samej klasie osiągnie to samo.
Brilliand
3

Ja również szukałem jednej linijki, aby to osiągnąć jako część pojedynczego wyrażenia do konwersji dat z jednego formatu na inny. Lubię to robić w jednym wierszu kodu, ponieważ jest to pojedyncza operacja logiczna. Jest to więc trochę zagadkowe, ale pozwala na utworzenie wystąpienia i użycie obiektu daty w jednej linii:

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

Innym sposobem konwersji ciągów dat z jednego formatu na inny w jednym wierszu jest użycie funkcji pomocniczej do zarządzania częściami OO kodu:

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

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

Myślę, że podejście obiektowe jest fajne i konieczne, ale czasami może być żmudne, wymagające zbyt wielu kroków do wykonania prostych operacji.

CodeCavalier
źródło
0

Widzę, że jest to dość stare, ale oto coś, o czym myślę, że należy o tym wspomnieć:

Specjalna metoda klasy o nazwie „__call ()” może być używana do tworzenia nowych elementów wewnątrz klasy. Używasz tego w ten sposób:

<?php
class test
{

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

}

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

Wynik powinien być:

I am here - new

W ten sposób możesz oszukać PHP, aby stworzył "nowe" polecenie w swojej klasie najwyższego poziomu (lub w rzeczywistości dowolnej innej) i umieścić swoje polecenie include w funkcji __call (), aby uwzględnić klasę, o którą prosiłeś. Oczywiście, prawdopodobnie chciałbyś przetestować $ func, aby upewnić się, że jest to "nowe" polecenie, które zostało wysłane do polecenia __call () i (oczywiście) możesz mieć inne polecenia również ze względu na sposób działania __call ().

Mark Manning
źródło
0

Po prostu możemy to zrobić

$method_result = (new Obj())->method();
Aruna Perera
źródło