Trong PHP, bạn có thể khởi tạo một đối tượng và gọi một phương thức trên cùng một dòng không?


126

Những gì tôi muốn làm là một cái gì đó như thế này:

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

Thay vì phải làm:

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

Kết quả không thực sự quan trọng với tôi trong trường hợp cụ thể của tôi. Nhưng, có cách nào để làm điều này?


4
btw, nếu bạn không sử dụng 5.4 (mà bạn có thể không biết), bạn có thể xác định hàm trợ giúp chỉ trả về một đối tượng cho chuỗi công cụ ... hàm với ($ obj) {return $ obj; } (chọn mẹo từ laravel: P) .. sau đó bạn có thể thực hiện với (Obj mới) -> phương thức ()
kapv89

BTW, nếu bạn thấy mình làm điều này thường xuyên, đáng để xem xét liệu có my_methodnên khai báo hay không static.
ToolmakerSteve

Câu trả lời:


166

Tính năng bạn đã yêu cầu có sẵn từ PHP 5.4. Dưới đây là danh sách các tính năng mới trong PHP 5.4:

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

Và phần có liên quan từ danh sách tính năng mới:

Truy cập thành viên lớp trên khởi tạo đã được thêm vào, ví dụ (Foo mới) -> bar ().


9
Lưu ý rằng điều này cũng có nghĩa là bạn có thể làm (new Foo)->propertynếu bạn muốn.
dave1010

1
Lưu ý rằng bạn không thể gán thuộc tính theo cách này được nêu ra. (Foo mới) -> property = 'property';
CMCDragonkai

7
@CMCDragonkai hợp lý mà có ý nghĩa; đối tượng chỉ tồn tại trong suốt thời gian của câu lệnh (new Foo)->property- giá trị bạn đang lưu trữ không còn nữa vì đối tượng sẽ không còn tồn tại sau đó vì nó không được lưu trữ ở bất kỳ đâu.
thomasrutter

1
@CMCDragonkai Bạn có thể gán các thuộc tính theo cách này bằng cách gọi các setters tương ứng , tất cả những gì bạn cần làm là thêm return $thisvào setters của bạn. Điều này cũng sẽ cho phép bạn xâu chuỗi setters.
iloo

Tôi có một câu hỏi. Có bất kỳ lợi ích nào khi khai báo đối tượng trên một dòng riêng biệt và lưu nó vào một biến, ngoài việc có thể sử dụng lại đối tượng không?
Tyler Swartzenburg

37

Bạn không thể làm những gì bạn đang yêu cầu; nhưng bạn có thể "gian lận", bằng cách sử dụng thực tế rằng, trong PHP, bạn có thể có một hàm có cùng tên với một lớp; những cái tên đó sẽ không xung đột.

Vì vậy, nếu bạn đã khai báo một lớp như thế này:

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

Sau đó, bạn có thể khai báo một hàm trả về một thể hiện của lớp đó - và có cùng tên với lớp:

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

Và bây giờ, có thể sử dụng một lớp lót, như bạn đã hỏi - điều duy nhất là bạn đang gọi hàm, do đó không sử dụng mới:

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

Và nó hoạt động: ở đây, tôi nhận được:

int 20

làm đầu ra.


Và, tốt hơn, bạn có thể đặt một số phpdoc vào chức năng của mình:

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

Theo cách này, bạn thậm chí sẽ có gợi ý trong IDE của mình - ít nhất là với PDT 2.x của Eclipse; xem screeshot:



Chỉnh sửa 2010-11-30: Chỉ để biết thông tin, một RFC mới đã được gửi, vài ngày trước, đề xuất thêm tính năng này vào một trong những phiên bản tương lai của PHP.

Xem: Yêu cầu Nhận xét: Truy cập cá nhân và phương thức truy cập / thuộc tính

Vì vậy, có thể làm những việc như thế này sẽ có thể có trong PHP 5.4 hoặc phiên bản tương lai khác:

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

19

Bạn có thể làm điều đó phổ biến hơn bằng cách xác định chức năng nhận dạng:

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

identity(new Obj)->method();

Theo cách đó, bạn không cần xác định hàm cho mỗi lớp.


10
Giải pháp tuyệt vời vì nó nhấn mạnh sự ngu ngốc của giới hạn này :)
Ole

19

Làm thế nào về:

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

: P


16

Không, điều này là không thể.
Bạn cần gán thể hiện cho một biến trước khi bạn có thể gọi bất kỳ phương thức nào của nó.

Nếu bạn thực sự không muốn làm điều này, bạn có thể sử dụng một nhà máy như ropstah gợi ý:

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

4
Câu trả lời của Pim là chính xác. Ngoài ra, bạn có thể sử dụng các hàm tĩnh nếu bạn không muốn tạo một thể hiện của đối tượng
Đánh dấu

sử dụng điều này, chúng tôi buộc phải sử dụng public static functionthay vì public function. Được khuyến khích sử dụng tĩnh?
ichimaru

6

Bạn có thể sử dụng một phương thức tĩnh nhà máy để tạo đối tượng:

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

3
Không cần một nhà máy riêng biệt; một phương thức tĩnh trong cùng một lớp sẽ thực hiện cùng một điều.
Brilliand

3

Tôi cũng vậy, tôi đang tìm kiếm một lớp lót để thực hiện điều này như là một phần của một biểu thức duy nhất để chuyển đổi ngày từ định dạng này sang định dạng khác. Tôi thích làm điều này trong một dòng mã bởi vì nó là một hoạt động logic duy nhất. Vì vậy, đây là một chút khó hiểu, nhưng nó cho phép bạn khởi tạo và sử dụng một đối tượng ngày trong một dòng duy nhất:

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

Một cách khác để chuyển đổi một chuỗi chuỗi ngày từ định dạng này sang định dạng khác là sử dụng hàm trợ giúp để quản lý các phần OO của mã:

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

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

Tôi nghĩ rằng cách tiếp cận hướng đối tượng là tuyệt vời và cần thiết, nhưng đôi khi nó có thể tẻ nhạt, đòi hỏi quá nhiều bước để thực hiện các hoạt động đơn giản.


0

Tôi thấy điều này khá cũ khi các câu hỏi đi nhưng đây là điều tôi nghĩ nên được đề cập:

Phương thức lớp đặc biệt có tên "__call ()" có thể được sử dụng để tạo các mục mới bên trong một lớp. Bạn sử dụng nó như thế này:

<?php
class test
{

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

}

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

Đầu ra phải là:

I am here - new

Do đó, bạn có thể đánh lừa PHP để tạo một lệnh "mới" bên trong lớp cấp cao nhất của bạn (hoặc bất kỳ lớp nào thực sự) và đưa lệnh bao gồm của bạn vào hàm __call () để bao gồm lớp mà bạn đã yêu cầu. Tất nhiên, bạn có thể muốn kiểm tra $ func để đảm bảo rằng đó là lệnh "mới" được gửi đến lệnh __call () và (tất nhiên) bạn cũng có thể có các lệnh khác vì cách hoạt động của __call ().


0

Đơn giản là chúng ta có thể làm điều này

$method_result = (new Obj())->method();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.