ใน PHP คุณสามารถสร้างอินสแตนซ์อ็อบเจ็กต์และเรียกเมธอดในบรรทัดเดียวกันได้หรือไม่?


126

สิ่งที่ฉันต้องการจะทำมีดังนี้:

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

แทนที่จะต้องทำ:

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

ผลลัพธ์ที่ได้ไม่สำคัญสำหรับฉันในกรณีเฉพาะของฉัน แต่มีวิธีทำหรือไม่?


4
btw ถ้าคุณไม่ได้ใช้ 5.4 (ซึ่งคุณอาจจะไม่ใช่) คุณสามารถกำหนดฟังก์ชันตัวช่วยซึ่งจะส่งคืนอ็อบเจกต์ไปยัง chain stuff ... function ด้วย ($ obj) {return $ obj; } (เลือกเคล็ดลับจาก laravel: P) .. จากนั้นคุณสามารถทำได้ด้วย (Obj ใหม่) -> method ()
kapv89

BTW หากคุณพบว่าตัวเองทำสิ่งนี้บ่อยๆควรพิจารณาว่าmy_methodควรจะประกาศแทนstaticหรือไม่
ToolmakerSteve

คำตอบ:


167

คุณลักษณะที่คุณขอมีให้จาก PHP 5.4 นี่คือรายการคุณสมบัติใหม่ใน PHP 5.4:

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

และส่วนที่เกี่ยวข้องจากรายการคุณสมบัติใหม่:

มีการเพิ่มการเข้าถึงของสมาชิกชั้นเรียนในการสร้างอินสแตนซ์เช่น (Foo ใหม่) -> bar ()


9
โปรดทราบว่านี่หมายความว่าคุณสามารถทำได้(new Foo)->propertyหากต้องการ
dave1010

1
โปรดทราบว่าคุณยังไม่สามารถกำหนดคุณสมบัติด้วยวิธีนี้ได้ (Foo ใหม่) -> property = 'property';
CMCDragonkai

7
@CMCDragonkai มีเหตุผลที่สมเหตุสมผล วัตถุมีอยู่ในช่วงเวลาของคำสั่งเท่านั้น(new Foo)->property- ค่าที่คุณจัดเก็บไม่มีที่ไปเพราะวัตถุจะไม่มีอยู่อีกต่อไปหลังจากนั้นเนื่องจากไม่ได้เก็บไว้ที่ใด
thomasrutter

1
@CMCDragonkai คุณสามารถกำหนดคุณสมบัติวิธีนี้โดยการเรียกที่สอดคล้องกันsettersทั้งหมดที่คุณต้องทำคือการเพิ่มreturn $thisการ setters ของคุณ นอกจากนี้ยังช่วยให้คุณสามารถตั้งโซ่
iloo

ฉันมีคำถาม. มีประโยชน์หรือไม่ในการประกาศวัตถุในบรรทัดแยกต่างหากและบันทึกลงในตัวแปรนอกเหนือจากความสามารถในการนำวัตถุกลับมาใช้ใหม่
Tyler Swartzenburg

37

คุณไม่สามารถทำสิ่งที่คุณขอได้ แต่คุณสามารถ "โกง" ได้โดยใช้ข้อเท็จจริงที่ว่าใน PHP คุณสามารถมีฟังก์ชันที่มีชื่อเดียวกับคลาสได้ ชื่อเหล่านั้นจะไม่ขัดแย้งกัน

ดังนั้นหากคุณประกาศคลาสเช่นนี้:

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

จากนั้นคุณสามารถประกาศฟังก์ชันที่ส่งคืนอินสแตนซ์ของคลาสนั้น - และมีชื่อเดียวกับคลาส:

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

และตอนนี้มันเป็นไปได้ที่จะใช้ซับเดียวอย่างที่คุณถามสิ่งเดียวคือคุณเรียกใช้ฟังก์ชันดังนั้นจึงไม่ใช้ใหม่:

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

และได้ผล: ที่นี่ฉันได้รับ:

int 20

เป็นเอาต์พุต


และที่ดีกว่านั้นคุณสามารถใส่ phpdoc ในฟังก์ชันของคุณได้:

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

ด้วยวิธีนี้คุณจะมีคำใบ้ใน IDE ของคุณอย่างน้อยก็ด้วย Eclipse PDT 2.x; ดู screeshot:



แก้ไข 2010-11-30:เพียงเพื่อเป็นข้อมูลมีการส่ง RFC ใหม่เมื่อไม่กี่วันที่ผ่านมาซึ่งเสนอให้เพิ่มคุณสมบัตินี้ใน PHP เวอร์ชันอนาคต

ดู: ขอความคิดเห็น: อินสแตนซ์และวิธีการเรียก / การเข้าถึงคุณสมบัติ

ดังนั้นการทำสิ่งเหล่านี้อาจทำได้ใน PHP 5.4 หรือเวอร์ชันอื่นในอนาคต:

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

19

คุณสามารถทำได้ในระดับสากลมากขึ้นโดยกำหนดฟังก์ชันระบุตัวตน:

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

identity(new Obj)->method();

ด้วยวิธีนี้คุณไม่จำเป็นต้องกำหนดฟังก์ชันสำหรับแต่ละคลาส


10
ทางออกที่ดีเนื่องจากเน้นย้ำถึงความโง่เขลาของข้อ จำกัด นี้ :)
Ole


16

ไม่นี่เป็นไปไม่ได้
คุณต้องกำหนดอินสแตนซ์ให้กับตัวแปรก่อนจึงจะเรียกใช้วิธีการใด ๆ ได้

หากคุณไม่ต้องการทำสิ่งนี้จริงๆคุณสามารถใช้โรงงานได้ตามที่ ropstah แนะนำ:

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

4
คำตอบของพิมถูกต้อง หรือคุณสามารถใช้ฟังก์ชันแบบคงที่ได้หากคุณไม่ต้องการสร้างอินสแตนซ์ของวัตถุ
ทำเครื่องหมาย

ใช้นี้เรามีแรงที่จะใช้แทนpublic static function public functionแนะนำให้ใช้แบบคงที่หรือไม่?
ichimaru

6

คุณสามารถใช้วิธีการโรงงานแบบคงที่เพื่อผลิตวัตถุ:

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

3
ไม่จำเป็นต้องมีโรงงานแยกต่างหาก วิธีการคงที่ในคลาสเดียวกันจะทำสิ่งเดียวกันให้สำเร็จ
Brilliand

3

ฉันเองก็กำลังมองหาหนึ่งซับเพื่อทำสิ่งนี้ให้สำเร็จโดยเป็นส่วนหนึ่งของนิพจน์เดียวสำหรับการแปลงวันที่จากรูปแบบหนึ่งไปเป็นอีกรูปแบบหนึ่ง ฉันชอบทำสิ่งนี้ในโค้ดบรรทัดเดียวเพราะมันเป็นการดำเนินการเชิงตรรกะเดียว ดังนั้นนี่จึงเป็นความลับเล็กน้อย แต่ให้คุณสร้างอินสแตนซ์และใช้วัตถุวันที่ภายในบรรทัดเดียว:

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

อีกวิธีหนึ่งในการแปลงสตริงวันที่จากรูปแบบหนึ่งไปยังอีกรูปแบบหนึ่งคือการใช้ฟังก์ชันตัวช่วยในการจัดการส่วน OO ของโค้ด:

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

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

ฉันคิดว่าแนวทางเชิงวัตถุนั้นยอดเยี่ยมและจำเป็น แต่บางครั้งก็อาจน่าเบื่อโดยต้องใช้ขั้นตอนมากเกินไปในการดำเนินการง่ายๆให้สำเร็จ


0

ฉันเห็นว่ามันค่อนข้างเก่าเมื่อมีคำถาม แต่นี่คือสิ่งที่ฉันคิดว่าควรกล่าวถึง:

เมธอดคลาสพิเศษที่เรียกว่า "__call ()" สามารถใช้เพื่อสร้างไอเท็มใหม่ภายในคลาส คุณใช้สิ่งนี้:

<?php
class test
{

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

}

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

ผลลัพธ์ควรเป็น:

I am here - new

ดังนั้นคุณสามารถหลอก PHP ให้สร้างคำสั่ง "ใหม่" ภายในคลาสระดับบนสุดของคุณ (หรือคลาสใด ๆ ก็ได้) และใส่คำสั่ง include ของคุณในฟังก์ชัน __call () เพื่อรวมคลาสที่คุณขอ แน่นอนคุณอาจต้องการทดสอบ $ func เพื่อให้แน่ใจว่าเป็นคำสั่ง "ใหม่" ที่ส่งไปยังคำสั่ง __call () และ (แน่นอน) คุณอาจมีคำสั่งอื่น ๆ ด้วยเนื่องจากการทำงานของ __call ()


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.