Dalam PHP, dapatkah Anda membuat instance objek dan memanggil metode pada baris yang sama?

126

Yang ingin saya lakukan adalah sesuatu seperti ini:

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

Alih-alih harus melakukan:

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

Hasilnya sebenarnya tidak penting bagi saya dalam kasus khusus saya. Tetapi, adakah cara untuk melakukan ini?

weotch
sumber
4
btw, jika Anda tidak menggunakan 5.4 (yang Anda mungkin tidak), Anda dapat mendefinisikan fungsi pembantu yang hanya mengembalikan objek ke rantai hal-hal ... berfungsi dengan ($ obj) {return $ obj; } (mengambil trik dari laravel: P) .. maka Anda dapat melakukannya dengan (Obj baru) -> metode ()
kapv89
BTW, jika Anda sering melakukan hal ini, ada baiknya mempertimbangkan apakah my_methodharus diumumkan static.
ToolmakerSteve

Jawaban:

167

Fitur yang Anda minta tersedia dari PHP 5.4. Berikut adalah daftar fitur baru di PHP 5.4:

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

Dan bagian yang relevan dari daftar fitur baru:

Akses anggota kelas di instantiation telah ditambahkan, misalnya (Foo baru) -> bar ().

Delian Krustev
sumber
9
Perhatikan bahwa ini juga berarti Anda dapat melakukannya (new Foo)->propertyjika Anda mau.
dave1010
1
Perhatikan bahwa Anda belum dapat menetapkan properti dengan cara ini. (Foo baru) -> properti = 'properti';
CMCDragonkai
7
@ CMCDragonkai secara logis masuk akal; objek hanya ada selama durasi pernyataan (new Foo)->property- nilai yang Anda simpan tidak memiliki tempat lain karena objek tidak akan ada lagi setelah itu karena tidak disimpan di mana pun.
thomasrutter
1
@ CMCDragonkai Anda dapat menetapkan properti dengan cara ini dengan memanggil setter yang sesuai , yang perlu Anda lakukan adalah menambahkan return $thisseter Anda. Ini juga akan memungkinkan Anda untuk rantai setter.
iloo
Saya punya pertanyaan. Apakah ada manfaat untuk mendeklarasikan objek pada baris terpisah dan menyimpannya ke variabel, selain bisa menggunakan kembali objek?
Tyler Swartzenburg
37

Anda tidak dapat melakukan apa yang Anda minta; tetapi Anda dapat "menipu", menggunakan fakta bahwa, di PHP, Anda dapat memiliki fungsi yang memiliki nama yang sama dengan kelas; nama-nama itu tidak akan bertentangan.

Jadi, jika Anda mendeklarasikan kelas seperti ini:

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

Anda kemudian dapat mendeklarasikan fungsi yang mengembalikan instance kelas itu - dan memiliki nama yang persis sama dengan kelas:

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

Dan sekarang, menjadi mungkin untuk menggunakan satu-liner, seperti yang Anda minta - satu-satunya hal yang Anda panggil fungsi, sehingga tidak menggunakan yang baru:

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

Dan itu bekerja: ini, saya mendapatkan:

int 20

sebagai output.


Dan, lebih baik, Anda dapat menempatkan beberapa phpdoc pada fungsi Anda:

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

Dengan cara ini, Anda bahkan akan memiliki petunjuk dalam IDE Anda - setidaknya, dengan Eclipse PDT 2.x; lihat screeshot:



Sunting 2010-11-30: Sekadar informasi, RFC baru telah dikirimkan, beberapa hari yang lalu, yang mengusulkan untuk menambahkan fitur ini ke salah satu versi PHP yang akan datang.

Lihat: Permintaan Komentar: Mesin virtual dan panggilan metode / akses properti

Jadi, mungkin melakukan hal-hal seperti ini dimungkinkan di PHP 5.4 atau versi lain di masa depan:

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

Anda dapat melakukannya secara lebih universal dengan mendefinisikan fungsi identitas:

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

identity(new Obj)->method();

Dengan begitu Anda tidak perlu mendefinisikan fungsi untuk setiap kelas.

Tom Pažourek
sumber
10
Solusi yang bagus karena menekankan kebodohan batasan ini :)
Ole
19

Bagaimana tentang:

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

: P

Jeff
sumber
16

Tidak, ini tidak mungkin.
Anda perlu menetapkan turunan ke variabel sebelum Anda dapat memanggil metode apa pun itu.

Jika Anda benar-benar tidak ingin melakukan ini, Anda dapat menggunakan pabrik seperti yang disarankan ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();
Pim Jager
sumber
4
Jawaban Pim benar. Atau Anda dapat menggunakan fungsi statis jika Anda tidak ingin membuat turunan objek
Mark
menggunakan ini, kita memaksa untuk menggunakan public static functionbukan public function. Dianjurkan untuk menggunakan statis?
ichimaru
6

Anda bisa menggunakan metode pabrik statis untuk menghasilkan objek:

ObjectFactory::NewObj()->method();
Ropstah
sumber
3
Tidak perlu pabrik yang terpisah; metode statis di kelas yang sama akan mencapai hal yang sama.
Brilliand
3

Saya juga sedang mencari satu-liner untuk menyelesaikan ini sebagai bagian dari ekspresi tunggal untuk mengubah tanggal dari satu format ke format lainnya. Saya suka melakukan ini dalam satu baris kode karena ini adalah operasi logis tunggal. Jadi, ini sedikit samar, tetapi ini memungkinkan Anda membuat instance dan menggunakan objek tanggal dalam satu baris:

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

Cara lain untuk mengubah konversi string tanggal dari satu format ke format lainnya adalah menggunakan fungsi helper untuk mengelola bagian kode OO:

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

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

Saya pikir pendekatan berorientasi objek itu keren dan perlu, tetapi kadang-kadang bisa membosankan, membutuhkan terlalu banyak langkah untuk menyelesaikan operasi sederhana.

CodeCavalier
sumber
0

Saya melihat ini sudah cukup lama sebagai pertanyaan pergi tapi di sini ada sesuatu yang saya pikir harus disebutkan:

Metode kelas khusus yang disebut "__call ()" dapat digunakan untuk membuat item baru di dalam kelas. Anda menggunakannya seperti ini:

<?php
class test
{

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

}

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

Output harus:

I am here - new

Dengan demikian, Anda dapat membodohi PHP untuk membuat perintah "baru" di dalam kelas tingkat atas Anda (atau kelas mana pun juga) dan memasukkan perintah sertakan Anda ke fungsi __call () untuk memasukkan kelas yang telah Anda minta. Tentu saja, Anda mungkin ingin menguji $ func untuk memastikan itu adalah perintah "baru" yang dikirim ke perintah __call () dan (tentu saja) Anda dapat memiliki perintah lain juga karena cara __call () bekerja.

Mark Manning
sumber
0

Cukup kita bisa melakukan ini

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