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?


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 ().


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]

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.


10
Fajne rozwiązanie, bo podkreśla głupotę tego ograniczenia :)
— Ole

19

Co powiesz na:

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

: P


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();

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();

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.


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 ().


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.