2009-09-09 37 views
89

Những gì tôi muốn làm là một cái gì đó như thế này: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?

$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 đối 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?

+3

btw, nếu bạn không sử dụng 5.4 (bạn có thể không), bạn có thể xác định hàm trợ giúp chỉ trả về đối tượng cho chuỗi ... chức năng với ($ obj) {return $ obj; } (chọn các trick lên từ laravel: P) .. sau đó bạn có thể làm với (new Obj) -> method() – kapv89

+0

Đơn giản như '(new Object()) -> doSomething()'. –

Trả lời

117

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://docs.php.net/manual/en/migration54.new-features.php

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

truy cập thành viên lớp trên instantiation đã được thêm vào, ví dụ (new Foo) -> bar().

+7

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

+0

Đây là một tính năng thực sự tốt đẹp của PHP 5.4, đáng tiếc là nó không có sẵn trên 5.3.27 (mà tôi đang trên). – crmpicco

+1

Lưu ý rằng bạn không thể gán thuộc tính theo cách này. (new Foo) -> property = 'property'; – CMCDragonkai

14

Không, điều này là không thể.
Bạn cần gán phiên bản cho 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ự wan't để 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(); 
+3

Câu trả lời của Pim là chính xác. Hoặc 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 – Mark

+1

objFacotry là gì?;) – Ropstah

6

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

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

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

18

Làm thế nào về :

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

: P

+11

Câu trả lời hay: P Làm tôi cười. –

36

Bạn không thể làm những gì bạn đang yêu cầu; nhưng bạn có thể "lừa gạt", 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 học 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ó chính xác cùng tên với lớp:

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

Và bây giờ, nó trở nên có thể sử dụng một lớp lót, giống như bạn hỏi - chỉ điều là bạn đang gọi chức năng, 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 

như đầu ra.


Và, tốt hơn, bạn có thể đặt một số PHPDoc trên chức năng của bạn:

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

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

http://extern.pascal-martin.fr/so/class-and-function.png



Sửa 2010-11-30: Chỉ cần cung cấp thông tin, một RFC mới đã được gửi đi, một vài ngày trước, rằng đề xuất thêm tính năng này cho một trong các phiên bản tương lai của PHP.

Xem: Request for Comments: Instance and method call/property access

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

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

đẹp! không biết rằng – knittl

+0

Tôi cũng vậy, cảm ơn. – Ropstah

+0

Wow, rất tuyệt! Tôi không biết điều đó. –

18

Bạn có thể làm điều đó phổ biến hơn bằng cách định nghĩa một hàm sắc:

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

identity(new Obj)->method(); 

Bằng cách đó bạn không cần xác định hàm cho từng lớp.

+10

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

3

Tôi cũng đ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ã vì nó là một phép toán logic duy nhất. Vì vậy, đây là một chút khó hiểu, nhưng nó cho phép bạn nhanh chóng 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 để một dòng chuyển đổi chuỗi ngày từ một định dạng khác là sử dụng một chức năng helper để 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à mát mẻ và cần thiết, nhưng đôi khi nó có thể được 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 là khá cũ như câu hỏi đi nhưng đây là điều mà tôi nghĩ nên được đề cập:

Phương pháp lớp học đặc biệt gọi là "__call()" có thể được sử dụng để tạo mặt hàng 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"); 
?> 

Output nên là:

I am here - new 

Vì vậy, bạn có thể đánh lừa PHP vào thực hiện một "mới" lệnh bên trong lớp cấp cao nhất của bạn (hoặc bất kỳ lớp thực sự) và đặt lệnh include 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 thử nghiệm $ func để đảm bảo rằng nó là một lệnh "mới" được gửi đến lệnh __call() và (dĩ nhiên) bạn cũng có thể có các lệnh khác cũng vì cách thức hoạt động của __call().

Các vấn đề liên quan