ตัวเองใหม่ (); ค่าเฉลี่ยใน PHP?


110

ฉันไม่เคยเห็นรหัสแบบนี้:

public static function getInstance()
{
    if ( ! isset(self::$_instance)) {
        self::$_instance = new self();
    }
    return self::$_instance;
}

มันเหมือนกับnew className()?

แก้ไข

ถ้าคลาสเป็นผู้สืบทอดคลาสใดที่ชี้ไปที่?



@ stereofrog คุณหมายความว่าควรละทิ้งรูปแบบซิงเกิลตันหรือไม่ แต่ทุกสิ่งมีอยู่ด้วยเหตุผลใช่ไหม?
user198729

โอ้ฉันมักจะเห็นด้วยกับประเด็นนี้: singleton ควรถูกแทนที่ด้วยโรงงาน
198729

@stereofrog Singleton เป็นพิษต่อการทดสอบหน่วยเป็นเรื่องยากมากที่จะทำการทดสอบที่ไม่เปลี่ยนรูปในบางสิ่งที่เปลี่ยนสถานะจากการเรียกหนึ่งไปสู่อีกครั้ง
เดวิด

น่าเสียดายที่วิธีนี้จะไม่ขยาย มันจะให้วัตถุใหม่จากคลาสที่กำหนดฟังก์ชันนี้ให้คุณเสมอ
Ares

คำตอบ:


211

self ชี้ไปที่คลาสที่เขียน

ดังนั้นหากเมธอด getInstance ของคุณอยู่ในชื่อคลาสMyClassบรรทัดต่อไปนี้:

self::$_instance = new self();

จะทำเช่นเดียวกับ:

self::$_instance = new MyClass();



แก้ไข: ข้อมูลเพิ่มเติมอีกสองสามข้อหลังจากความคิดเห็น

หากคุณมีสองคลาสที่ขยายซึ่งกันและกันคุณมีสองสถานการณ์:

  • getInstance ถูกกำหนดไว้ในคลาสย่อย
  • getInstance ถูกกำหนดไว้ในคลาสพาเรนต์

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

class MyParentClass {

}
class MyChildClass extends MyParentClass {
    public static function getInstance() {
        return new self();
    }
}

$a = MyChildClass::getInstance();
var_dump($a);

ที่นี่คุณจะได้รับ:

object(MyChildClass)#1 (0) { } 

ซึ่งมีความหมายselfว่าMyChildClass- คือคลาสที่เขียน


สำหรับสถานการณ์ที่สองรหัสจะมีลักษณะดังนี้:

class MyParentClass {
    public static function getInstance() {
        return new self();
    }
}
class MyChildClass extends MyParentClass {

}

$a = MyChildClass::getInstance();
var_dump($a);

และคุณจะได้ผลลัพธ์ประเภทนี้:

object(MyParentClass)#1 (0) { }

ซึ่งหมายถึงselfวิธีการMyParentClass- คือที่นี่เกินไปชั้นในที่จะเขียน




ด้วย PHP <5.3 "คลาสที่จะเขียน" มีความสำคัญและบางครั้งอาจทำให้เกิดปัญหาได้

นั่นเป็นเหตุผลที่ PHP 5.3 แนะนำการใช้งานใหม่สำหรับstaticคำหลัก: ตอนนี้สามารถใช้ได้ตรงกับที่เราใช้selfในตัวอย่างเหล่านี้:

class MyParentClass {
    public static function getInstance() {
        return new static();
    }
}
class MyChildClass extends MyParentClass {

}

$a = MyChildClass::getInstance();
var_dump($a);

แต่มีstaticแทนselfตอนนี้คุณจะได้รับ:

object(MyChildClass)#1 (0) { } 

ซึ่งหมายความว่าการstaticจัดเรียงคะแนนไปยังชั้นเรียนที่ใช้ (เราใช้MyChildClass::getInstance()) ไม่ใช่จุดที่ถูกเขียน

แน่นอนพฤติกรรมของselfไม่ได้รับการเปลี่ยนแปลงเพื่อไม่ทำลายแอปพลิเคชันที่มีอยู่ - PHP 5.3 เพิ่งเพิ่มพฤติกรรมใหม่รีไซเคิลไฟล์staticคำหลัก


และเมื่อพูดถึง PHP 5.3 คุณอาจต้องการดูที่หน้าLate Static Bindingsของคู่มือ PHP


@ พอล: heu ... หมายถึง "ตัวเองทำหน้าที่เป็นนามแฝงของ" หรือ "จัดเรียงจุดด้วยตนเอง" - คำกริยา "ผู้ออกแบบ" ในภาษาฝรั่งเศสสามารถใช้สำหรับสิ่งนั้นได้ - ฉันคิดว่านั่นเป็นหนึ่งในสถานการณ์ ซึ่งการใช้คำเดียวกันในภาษาอังกฤษไม่ใช่ความคิดที่ดี ;-( ฉันจะแก้ไขคำตอบของฉันเพื่อแก้ไขปัญหานี้ ;; ขอบคุณ :-)
Pascal MARTIN

เกิดอะไรขึ้นถ้ามีbaseclass, classที่หนึ่งไม่ได้ชี้ไป?
user198729

@ ผู้ใช้: ฉันได้แก้ไขคำตอบของฉันเพื่อให้ข้อมูลเพิ่มเติมเกี่ยวกับselfและการสืบทอด และฉันยังได้รวมข้อมูลบางอย่างเกี่ยวกับstaticPHP 5.3 ;; หวังว่านี่จะช่วยได้ :-)
Pascal MARTIN

10

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

ถ้ามันไม่ได้ก็เริ่มต้นอินสแตนซ์ของตัวเอง (เป็นnew self()) $_instanceและเก็บไว้ใน

หากคุณโทรclassName::getInstance()คุณจะได้รับอินสแตนซ์คลาสเดียวกันทุกครั้งซึ่งเป็นจุดเริ่มต้นของรูปแบบซิงเกิลตัน

ฉันไม่เคยเห็นมันทำแบบนี้มาก่อนและไม่รู้จริง ๆ ว่ามันเป็นไปได้ อะไรคือ$_instanceการประกาศให้เป็นในชั้นเรียน?


1
$_instanceประกาศเป็นpublic static $_instance;
Atif

7

สิ่งนี้มักใช้ในรูปแบบการออกแบบซิงเกิลตันโดยที่คอนสตรัคเตอร์ถูกกำหนดให้เป็นไพรเวตเพื่อหลีกเลี่ยงการสร้างอินสแตนซ์ตัว(::)ดำเนินการโคลอนคู่สามารถเข้าถึงสมาชิกที่ประกาศแบบคงที่ภายในคลาสได้ดังนั้นหากมีสมาชิกแบบคงที่ตัวแปรหลอก $ ไม่สามารถใช้สิ่งนี้ได้ด้วยเหตุนี้จึงใช้รหัสแทนตัวเอง Singletons จึงเป็นแนวทางปฏิบัติในการเขียนโปรแกรมที่ดีซึ่งจะอนุญาตให้ใช้เพียง 1 อินสแตนซ์ของวัตถุเช่นตัวจัดการตัวเชื่อมต่อฐานข้อมูล จากรหัสไคลเอนต์การเข้าถึงอินสแตนซ์นั้นจะทำได้โดยการสร้างจุดเชื่อมต่อเดียวในกรณีนี้เขาตั้งชื่อมันว่าgetInstance()getInstance ในตัวเองเป็นฟังก์ชันที่สร้างวัตถุโดยพื้นฐานโดยใช้คำหลักใหม่เพื่อสร้างวัตถุซึ่งหมายความว่าวิธีการสร้างคือ เรียกอีกอย่างว่า

บรรทัดif(!isset(self::instance))จะตรวจสอบว่ามีการสร้างออบเจ็กต์หรือไม่คุณไม่เข้าใจสิ่งนี้เนื่องจากโค้ดเป็นเพียงส่วนที่อยู่ด้านบนควรมีสมาชิกคงที่เหมือน

private static $_instance = NULL; 

ในชั้นเรียนปกติเราจะเข้าถึงสมาชิกคนนี้ได้ง่ายๆ

$this->_instance = 'something';

แต่ประกาศว่าคงที่ดังนั้นเราจึงไม่สามารถใช้ $ รหัสนี้ที่เราใช้แทนได้

self::$_instance

โดยการตรวจสอบว่ามีออบเจ็กต์ที่เก็บอยู่ในตัวแปรคลาสคงที่นี้หรือไม่จากนั้นคลาสจะสามารถตัดสินใจสร้างหรือไม่สร้างอินสแตนซ์เดียวได้ดังนั้นหากไม่ได้ตั้งค่า! isset หมายความว่าไม่มีวัตถุอยู่ในสมาชิกแบบคงที่ $ _instance ดังนั้น สร้างวัตถุใหม่เก็บไว้ในสมาชิกแบบคงที่$_instanceโดยคำสั่ง

self::$_instance = new self();

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

$thisObject = className::getInstance();

เหตุผลฟังก์ชั่นในตัวเองถูกประกาศแบบคงที่


2

ใช่มันเหมือนกับnew className()(หมายถึงคลาสที่มีเมธอดนั้น) อาจใช้ในรูปแบบ Singleton ที่ตัวสร้างเป็นแบบส่วนตัว


ทำไมบางคนถึงใช้รูปแบบ Singleton ใน PHP? เว้นแต่จะใช้ในโปรแกรมที่มีลักษณะเหมือน daemon ซิงเกิลตันจะใช้งานได้ในขณะที่สคริปต์ทำงานจากนั้นจะหายไปพร้อมกับโปรแกรม
ILikeTacos

4
เพื่อหลีกเลี่ยงการประกาศทั่วโลกอย่างไม่เหมาะสมเพื่อเข้าถึงตัวแปรระดับโลก
Sam Adamsh

0

หากคลาสได้รับการสืบทอดการเรียก getInstance () จาก child จะไม่ทำให้คุณมีตัวอย่างของ child มันจะส่งคืนอินสแตนซ์ของอินสแตนซ์หลักเท่านั้น นี่เป็นเพราะเราเรียกตัวเองใหม่ว่า ()

หากคุณต้องการให้คลาสลูกส่งคืนอินสแตนซ์ของคลาสลูกให้ใช้ new static () ใน getInstance () จากนั้นจะส่งคืนอินสแตนซ์คลาสลูก แบบนี้เรียกว่าผูกพันสาย !!

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