ใหม่ด้วยตนเองกับใหม่คงที่


513

ฉันกำลังแปลงไลบรารี PHP 5.3 ให้ทำงานบน PHP 5.2 สิ่งสำคัญที่ยืนอยู่ในทางของฉันคือการใช้การเชื่อมโยงแบบคงที่ล่าช้าเช่นreturn new static($options);ถ้าฉันแปลงสิ่งนี้เป็นreturn new self($options)ฉันจะได้ผลลัพธ์เดียวกันหรือไม่

ความแตกต่างระหว่างnew selfและnew staticคืออะไร?

คำตอบ:


890

ฉันจะได้ผลลัพธ์เดียวกัน

ไม่ได้จริงๆ อย่างไรก็ตามฉันไม่ทราบวิธีแก้ปัญหาสำหรับ PHP 5.2

ความแตกต่างระหว่างnew selfและnew staticคืออะไร?

selfอ้างถึงคลาสเดียวกันที่newเขียนคำสำคัญจริง

staticในการเชื่อมโยงคงที่ของ PHP 5.3 หมายถึงคลาสใด ๆ ในลำดับชั้นที่คุณเรียกว่าเมธอด

ในตัวอย่างต่อไปนี้สืบทอดวิธีการทั้งจากB Aการselfร้องขอนั้นถูกผูกไว้Aเพราะมันถูกกำหนดไว้ในAการใช้งานของวิธีแรกในขณะที่staticถูกผูกไว้กับคลาสที่เรียกว่า (ดูด้วยget_called_class())

class A {
    public static function get_self() {
        return new self();
    }

    public static function get_static() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A

มีเหตุผล. ฉันคิดว่าทางออกที่ดีที่สุดคือการส่งชื่อคลาสไปยังฟังก์ชันที่ใช้การรวมคงที่ล่าช้าและจากนั้นส่งคืน $ className ($ options) ใหม่;
Mike

12
คุณไม่จำเป็นต้อง "ส่ง" ชื่อคลาสคุณสามารถทำได้เสมอget_called_class()ซึ่งมีประสิทธิภาพเหมือนกับ__CLASS__แต่ใช้งานได้กับ LSB
shadowhand

7
get_called_class ไม่มีอยู่ใน <PHP5.3 ดังนั้นหากคุณต้องการได้รับชื่อคลาสของวัตถุ instantiated ใน PHP5.2 ฟังก์ชั่นนี้ไม่ได้ช่วยเมื่อพยายามแปลงห้องสมุดจาก PHP 5.3 เป็น PHP 5.2
txwikinger

2
ฟังก์ชั่นที่เรียกว่าเป็นตัวเอง :: theFunction () ทำหน้าที่เหมือน "ฉันจะดำเนินการในบริบทของชั้นเรียนที่ฉันเป็นของร่างกาย" และฟังก์ชั่นที่เรียกว่าเป็นแบบคงที่ :: theFunction () จะทำงานเหมือน "ฉันจะดำเนินการในบริบทของชั้นเรียนที่โลกภายนอกเรียกจริง" (สมมติว่าสถานการณ์การสืบทอด) ขอบคุณ
Shubhranshu

2
ในหัวของฉันฉันแค่ใช้ทุกอย่างที่เป็นธรรมชาติและทำให้มันตรงกันข้าม คุณจะคิดตามการตั้งชื่อselfจะคืนตัวเองและstaticจะคืนสิ่งที่ไม่สามารถแทนที่ ... แต่แท้จริงและเห็นว่ามันตรงกันข้าม ฉันไม่เคยหยุดที่จะประทับใจกับการตั้งชื่อการประชุมและสไตล์โดยรวมของ PHP -_-
ahnbizcad

23

หากวิธีการของรหัสนี้ไม่คงที่คุณจะได้รับการทำงานรอบใน 5.2 get_class($this)โดยใช้

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

ผลลัพธ์ที่ได้:

string(1) "B"
string(1) "B"

17
หากวิธีการนั้นไม่คงที่การผูกแบบคงที่ในช่วงปลายจะไม่เกี่ยวข้องทั้งหมด
BoltClock

1
ตัวอย่างเช่นคุณสามารถใช้มันในวิธีการ "คัดลอก" ที่วัตถุถูกคัดลอกโดยไม่ต้องใช้cloneแต่เพียงแค่การสร้างใหม่และการตั้งค่าคุณสมบัติ $copy = new static(); $copy->set($this->get()); return $copy;
Marius Balčytis

9
@BoltClock ไม่จริงเหรอ? หากคุณกำลังเรียกใช้เมธอดแบบสแตติกที่แทนที่จากภายในเมธอดอินสแตนซ์ของคลาสย่อยคุณจะต้องเลือกself::หรือstatic::จะส่งผลกระทบไม่ว่าจะใช้เวอร์ชันสแตติกคลาสหรือคลาสย่อยของเมธอดสแตติกนั้นหรือไม่ ในกรณีที่ไม่มีเหตุผลที่จะคิดว่าสถานการณ์ดังกล่าวเกิดขึ้นโดยเนื้อแท้แสดงถึงการปฏิบัติที่ไม่ดี (และฉันไม่เห็นเหตุผลใด ๆ ที่ทำให้เป็นเช่นนั้น) ตัวเลือกระหว่างself::และstatic::มีความเกี่ยวข้องภายในวิธีการที่ไม่คงที่เหมือนใน วิธีการคงที่ ฉันเข้าใจผิดความคิดเห็นของคุณหรือเป็นหนึ่งในนั้นเราผิด?
Mark Amery

4
@ Mark Amery: อืมฉันไม่ได้คิดอย่างนั้น คุณพูดถูก ฉันสันนิษฐานว่าไม่มีวิธีการคงที่ที่จะถูกเรียกในวิธีอินสแตนซ์ที่เป็นปัญหา แต่จากตัวอย่างของคุณฉันสามารถดูว่ามันจะเป็นสมมติฐานที่ไร้เดียงสามาก
BoltClock

การรวมเข้าด้วยกันตอนปลาย doc => php.net/manual/en/language.oop5.late-static-bindings.php
DevWL

7

นอกจากคำตอบของผู้อื่น:

static :: จะถูกคำนวณโดยใช้ข้อมูลรันไทม์

นั่นหมายความว่าคุณไม่สามารถใช้static::ในคุณสมบัติคลาสได้เนื่องจากค่าคุณสมบัติ:

จะต้องสามารถประเมินได้ในเวลารวบรวมและจะต้องไม่ขึ้นอยู่กับข้อมูลเวลาทำงาน

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

การใช้ self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

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


4
หมายเหตุข้อผิดพลาดเกิดขึ้นที่บรรทัดที่ 2 public $name = static::class;ไม่ใช่ที่บรรทัดที่ 7 ตามที่แนะนำโดยตัวอย่าง ข้อผิดพลาดบอกว่า: "คลาส :: :: คงไม่สามารถใช้สำหรับการจำแนกชื่อคลาสเวลาคอมไพล์" ซึ่งบ่งชี้ว่าปัญหาไม่ใช่ตำแหน่งที่คุณพยายามเข้าถึงฟิลด์ชื่อ $ แต่ก่อนหน้านี้เมื่อทำการรวบรวมคลาส PHP จะไม่ถึงบรรทัดที่ 7 (หรือ 6) ในตัวอย่างแรก
sbnc.eu

@Grapestain ความคิดเห็นที่ฉันทำในตัวอย่างคือการแสดงผลลัพธ์สุดท้ายและไม่ระบุว่าเกิดข้อผิดพลาดขึ้นจริง แต่อย่างไรก็ตามขอบคุณที่ชี้ให้เห็น
เรน

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