เราจะสร้างคลาส Singleton โดยใช้คลาส PHP5 ได้อย่างไร
เราจะสร้างคลาส Singleton โดยใช้คลาส PHP5 ได้อย่างไร
คำตอบ:
/**
* Singleton class
*
*/
final class UserFactory
{
/**
* Call this method to get singleton
*
* @return UserFactory
*/
public static function Instance()
{
static $inst = null;
if ($inst === null) {
$inst = new UserFactory();
}
return $inst;
}
/**
* Private ctor so nobody else can instantiate it
*
*/
private function __construct()
{
}
}
ใช้:
$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();
$fact == $fact2;
แต่:
$fact = new UserFactory()
โยนข้อผิดพลาด
ดูhttp://php.net/manual/en/language.variables.scope.php#language.variables.scope.staticเพื่อทำความเข้าใจขอบเขตตัวแปรสแตติกและทำไมการตั้งค่าใช้static $inst = null;
งาน
PHP 5.3 อนุญาตให้สร้างคลาส Singleton ที่สืบทอดได้ผ่านการโยงแบบคงที่ในช่วงปลาย
class Singleton
{
protected static $instance = null;
protected function __construct()
{
//Thou shalt not construct that which is unconstructable!
}
protected function __clone()
{
//Me not like clones! Me smash clones!
}
public static function getInstance()
{
if (!isset(static::$instance)) {
static::$instance = new static;
}
return static::$instance;
}
}
วิธีนี้จะช่วยแก้ปัญหาก่อนที่ PHP 5.3 คลาสใด ๆ ที่ขยาย Singleton จะสร้างอินสแตนซ์ของคลาสพาเรนต์แทนที่จะเป็นของตัวเอง
ตอนนี้คุณสามารถทำได้:
class Foobar extends Singleton {};
$foo = Foobar::getInstance();
และ $ foo จะเป็นตัวอย่างของ Foobar แทนที่จะเป็นตัวอย่างของ Singleton
"subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());"
@ggsonic:
$instance
อยู่ใน Singleton ไม่ใช่คลาสย่อย หลังจากคลาสย่อยบางอินสแตนซ์ getInstance () จะส่งคืนอินสแตนซ์นั้นสำหรับคลาสย่อยทั้งหมด
น่าเสียดายที่คำตอบของ Inwdrหยุดลงเมื่อมีคลาสย่อยหลายคลาส
นี่คือคลาสพื้นฐานที่ถูกต้องซึ่งสืบทอดได้ของ Singleton
class Singleton
{
private static $instances = array();
protected function __construct() {}
protected function __clone() {}
public function __wakeup()
{
throw new Exception("Cannot unserialize singleton");
}
public static function getInstance()
{
$cls = get_called_class(); // late-static-bound class name
if (!isset(self::$instances[$cls])) {
self::$instances[$cls] = new static;
}
return self::$instances[$cls];
}
}
รหัสทดสอบ:
class Foo extends Singleton {}
class Bar extends Singleton {}
echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";
วิธีที่แท้จริงและทันสมัยในการสร้างรูปแบบซิงเกิลคือ:
<?php
/**
* Singleton Pattern.
*
* Modern implementation.
*/
class Singleton
{
/**
* Call this method to get singleton
*/
public static function instance()
{
static $instance = false;
if( $instance === false )
{
// Late static binding (PHP 5.3+)
$instance = new static();
}
return $instance;
}
/**
* Make constructor private, so nobody can call "new Class".
*/
private function __construct() {}
/**
* Make clone magic method private, so nobody can clone instance.
*/
private function __clone() {}
/**
* Make sleep magic method private, so nobody can serialize instance.
*/
private function __sleep() {}
/**
* Make wakeup magic method private, so nobody can unserialize instance.
*/
private function __wakeup() {}
}
ดังนั้นตอนนี้คุณสามารถใช้มันเหมือน
<?php
/**
* Database.
*
* Inherited from Singleton, so it's now got singleton behavior.
*/
class Database extends Singleton {
protected $label;
/**
* Example of that singleton is working correctly.
*/
public function setLabel($label)
{
$this->label = $label;
}
public function getLabel()
{
return $this->label;
}
}
// create first instance
$database = Database::instance();
$database->setLabel('Abraham');
echo $database->getLabel() . PHP_EOL;
// now try to create other instance as well
$other_db = Database::instance();
echo $other_db->getLabel() . PHP_EOL; // Abraham
$other_db->setLabel('Priler');
echo $database->getLabel() . PHP_EOL; // Priler
echo $other_db->getLabel() . PHP_EOL; // Priler
เมื่อคุณเห็นการรับรู้นี้มีความยืดหยุ่นมากขึ้น
instance
ฟังก์ชั่น$instance
ที่ควรจะเป็นnull
ไม่ได้false
คุณควรเพิ่มเมธอด __clone () ส่วนตัวเพื่อไม่อนุญาตการโคลนอินสแตนซ์
private function __clone() {}
หากคุณไม่ได้รวมวิธีนี้สิ่งต่อไปนี้จะเป็นไปได้
$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;
ตอนนี้$inst1
! == $inst2
- พวกเขาไม่ใช่อินสแตนซ์เดียวกันอีกต่อไป
<?php
/**
* Singleton patter in php
**/
trait SingletonTrait {
protected static $inst = null;
/**
* call this method to get instance
**/
public static function getInstance(){
if (static::$inst === null){
static::$inst = new static();
}
return static::$inst;
}
/**
* protected to prevent clonning
**/
protected function __clone(){
}
/**
* protected so no one else can instance it
**/
protected function __construct(){
}
}
ใช้:
/**
* example of class definitions using SingletonTrait
*/
class DBFactory {
/**
* we are adding the trait here
**/
use SingletonTrait;
/**
* This class will have a single db connection as an example
**/
protected $db;
/**
* as an example we will create a PDO connection
**/
protected function __construct(){
$this->db =
new PDO('mysql:dbname=foodb;port=3305;host=127.0.0.1','foouser','foopass');
}
}
class DBFactoryChild extends DBFactory {
/**
* we repeating the inst so that it will differentiate it
* from UserFactory singleton
**/
protected static $inst = null;
}
/**
* example of instanciating the classes
*/
$uf0 = DBFactoryChild::getInstance();
var_dump($uf0);
$uf1 = DBFactory::getInstance();
var_dump($uf1);
echo $uf0 === $uf1;
respose:
object(DBFactoryChild)#1 (0) {
}
object(DBFactory)#2 (0) {
}
หากคุณกำลังใช้ PHP 5.4: ลักษณะตัวเลือกของคุณจึงไม่ต้องเสียลำดับชั้นมรดกเพื่อให้มีรูปแบบเดี่ยว
และยังสังเกตเห็นว่าไม่ว่าคุณจะใช้คุณสมบัติหรือขยายชั้นเดียวที่มีปลายด้านเดียวที่หลวมก็คือการสร้างชั้นเรียนสำหรับเด็กถ้าคุณไม่เพิ่มบรรทัดของรหัสต่อไปนี้:
protected static $inst = null;
ในชั้นเรียนของเด็ก
ผลลัพธ์ที่ไม่คาดคิดจะเป็น:
object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}
protected static $_instance;
public static function getInstance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
รหัสนี้สามารถใช้กับคลาสใดก็ได้โดยไม่ต้องสนใจชื่อคลาส
วิธีนี้จะบังคับใช้ซิงเกิลตันในคลาสใด ๆ ที่คุณต้องการและคุณต้องทำคือเพิ่ม 1 วิธีในคลาสที่คุณต้องการสร้างซิงเกิลตันและจะทำเพื่อคุณ
สิ่งนี้ยังเก็บวัตถุในคลาส "SingleTonBase" เพื่อให้คุณสามารถดีบักวัตถุทั้งหมดของคุณที่คุณใช้ในระบบของคุณด้วยการเรียกSingleTonBase
วัตถุอีกครั้ง
สร้างไฟล์ชื่อ SingletonBase.php และรวมไว้ในรูทของสคริปต์ของคุณ!
รหัสคือ
abstract class SingletonBase
{
private static $storage = array();
public static function Singleton($class)
{
if(in_array($class,self::$storage))
{
return self::$storage[$class];
}
return self::$storage[$class] = new $class();
}
public static function storage()
{
return self::$storage;
}
}
จากนั้นสำหรับคลาสใด ๆ ที่คุณต้องการสร้างซิงเกิลตันให้เพิ่มเมธอดเดี่ยวขนาดเล็กนี้
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
นี่คือตัวอย่างเล็ก ๆ :
include 'libraries/SingletonBase.resource.php';
class Database
{
//Add that singleton function.
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
public function run()
{
echo 'running...';
}
}
$Database = Database::Singleton();
$Database->run();
และคุณสามารถเพิ่มฟังก์ชัน singleton นี้ในคลาสใดก็ได้ที่คุณมีและจะสร้าง 1 อินสแตนซ์ต่อคลาสเท่านั้น
หมายเหตุ: คุณควรสร้าง __ โครงสร้างส่วนตัวเพื่อกำจัดการใช้คลาสใหม่ (); instantiations
class Database{
//variable to hold db connection
private $db;
//note we used static variable,beacuse an instance cannot be used to refer this
public static $instance;
//note constructor is private so that classcannot be instantiated
private function __construct(){
//code connect to database
}
//to prevent loop hole in PHP so that the class cannot be cloned
private function __clone() {}
//used static function so that, this can be called from other classes
public static function getInstance(){
if( !(self::$instance instanceof self) ){
self::$instance = new self();
}
return self::$instance;
}
public function query($sql){
//code to run the query
}
}
Access the method getInstance using
$db = Singleton::getInstance();
$db->query();
คุณไม่จำเป็นต้องใช้รูปแบบซิงเกิลจริงๆเพราะถือว่าเป็น Antipattern โดยทั่วไปมีเหตุผลมากมายที่จะไม่ใช้รูปแบบนี้เลย อ่านนี้เพื่อเริ่มต้นกับการปฏิบัติที่ดีที่สุดในชั้นเรียน PHP เดี่ยว
หากคุณยังคิดว่าคุณต้องใช้รูปแบบซิงเกิลแล้วเราสามารถเขียนคลาสที่จะช่วยให้เราได้รับฟังก์ชั่น Singleton โดยขยายคลาสนามธรรมของ SingletonClassVendor
นี่คือสิ่งที่ฉันมาพร้อมกับการแก้ปัญหานี้
<?php
namespace wl;
/**
* @author DevWL
* @dosc allows only one instance for each extending class.
* it acts a litle bit as registry from the SingletonClassVendor abstract class point of view
* but it provides a valid singleton behaviour for its children classes
* Be aware, the singleton pattern is consider to be an anti-pattern
* mostly because it can be hard to debug and it comes with some limitations.
* In most cases you do not need to use singleton pattern
* so take a longer moment to think about it before you use it.
*/
abstract class SingletonClassVendor
{
/**
* holds an single instance of the child class
*
* @var array of objects
*/
protected static $instance = [];
/**
* @desc provides a single slot to hold an instance interchanble between all child classes.
* @return object
*/
public static final function getInstance(){
$class = get_called_class(); // or get_class(new static());
if(!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class){
self::$instance[$class] = new static(); // create and instance of child class which extends Singleton super class
echo "new ". $class . PHP_EOL; // remove this line after testing
return self::$instance[$class]; // remove this line after testing
}
echo "old ". $class . PHP_EOL; // remove this line after testing
return static::$instance[$class];
}
/**
* Make constructor abstract to force protected implementation of the __constructor() method, so that nobody can call directly "new Class()".
*/
abstract protected function __construct();
/**
* Make clone magic method private, so nobody can clone instance.
*/
private function __clone() {}
/**
* Make sleep magic method private, so nobody can serialize instance.
*/
private function __sleep() {}
/**
* Make wakeup magic method private, so nobody can unserialize instance.
*/
private function __wakeup() {}
}
ใช้ตัวอย่าง:
/**
* EXAMPLE
*/
/**
* @example 1 - Database class by extending SingletonClassVendor abstract class becomes fully functional singleton
* __constructor must be set to protected becaouse:
* 1 to allow instansiation from parent class
* 2 to prevent direct instanciation of object with "new" keword.
* 3 to meet requierments of SingletonClassVendor abstract class
*/
class Database extends SingletonClassVendor
{
public $type = "SomeClass";
protected function __construct(){
echo "DDDDDDDDD". PHP_EOL; // remove this line after testing
}
}
/**
* @example 2 - Config ...
*/
class Config extends SingletonClassVendor
{
public $name = "Config";
protected function __construct(){
echo "CCCCCCCCCC" . PHP_EOL; // remove this line after testing
}
}
เพียงเพื่อพิสูจน์ว่าทำงานได้ตามที่คาดไว้:
/**
* TESTING
*/
$bd1 = Database::getInstance(); // new
$bd2 = Database::getInstance(); // old
$bd3 = Config::getInstance(); // new
$bd4 = Config::getInstance(); // old
$bd5 = Config::getInstance(); // old
$bd6 = Database::getInstance(); // old
$bd7 = Database::getInstance(); // old
$bd8 = Config::getInstance(); // old
echo PHP_EOL."COMPARE ALL DATABASE INSTANCES".PHP_EOL;
var_dump($bd1);
echo '$bd1 === $bd2' . ($bd1 === $bd2)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd2 === $bd6' . ($bd2 === $bd6)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd6 === $bd7' . ($bd6 === $bd7)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo PHP_EOL;
echo PHP_EOL."COMPARE ALL CONFIG INSTANCES". PHP_EOL;
var_dump($bd3);
echo '$bd3 === $bd4' . ($bd3 === $bd4)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd4 === $bd5' . ($bd4 === $bd5)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd5 === $bd8' . ($bd5 === $bd8)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
ความซับซ้อนทั้งหมดนี้ ("การผูกปลายคงที่" ... ยากลำบาก) สำหรับฉันแล้วมันเป็นเพียงสัญลักษณ์ของโมเดลวัตถุ / คลาสที่เสียหายของ PHP ถ้าวัตถุคลาสเป็นวัตถุชั้นหนึ่ง (ดู Python) ดังนั้น "$ _instance" จะเป็นตัวแปรอินสแตนซ์ของคลาส- สมาชิกของวัตถุคลาสซึ่งตรงข้ามกับสมาชิก / คุณสมบัติของอินสแตนซ์และเมื่อเทียบกับที่ใช้ร่วมกัน โดยลูกหลานของมัน ในโลก Smalltalk นี่คือความแตกต่างระหว่าง "ตัวแปรคลาส" และ "ตัวแปรอินสแตนซ์ของคลาส"
ใน PHP ดูเหมือนว่าเราต้องคำนึงถึงคำแนะนำว่ารูปแบบเป็นแนวทางในการเขียนโค้ด - บางทีเราอาจคิดถึงเทมเพลต Singleton แต่พยายามเขียนโค้ดที่สืบทอดมาจากคลาส "Singleton" ที่แท้จริง ดูผิดสำหรับ PHP (แต่ฉันคิดว่าวิญญาณผู้กล้าได้กล้าเสียสามารถสร้างคำหลัก SVN ที่เหมาะสม)
ฉันจะยังคงรหัสแต่ละเดี่ยวแยกกันโดยใช้แม่แบบที่ใช้ร่วมกัน
สังเกตุว่าฉันไม่ได้อยู่ในการสนทนาเดี่ยวตันอย่างชั่วร้ายชีวิตสั้นเกินไป
ฉันรู้ว่านี่อาจจะทำให้เกิดสงครามไฟที่ไม่จำเป็น แต่ฉันสามารถดูว่าคุณอาจต้องการการเชื่อมต่อฐานข้อมูลมากกว่าหนึ่งดังนั้นฉันจะยอมรับจุดที่ซิงเกิลอาจไม่ใช่วิธีที่ดีที่สุดสำหรับ ... อย่างไรก็ตามมี การใช้รูปแบบซิงเกิลอื่นที่ฉันพบว่ามีประโยชน์มาก
นี่คือตัวอย่าง: ฉันตัดสินใจที่จะม้วน MVC ของตัวเองและเครื่องมือสร้างแรงบิดเพราะฉันต้องการบางสิ่งที่มีน้ำหนักเบาจริงๆ อย่างไรก็ตามข้อมูลที่ฉันต้องการแสดงมีอักขระพิเศษทางคณิตศาสตร์จำนวนมากเช่น≥และμและสิ่งที่คุณมี ... ข้อมูลถูกเก็บเป็นอักขระ UTF-8 จริงในฐานข้อมูลของฉันแทนที่จะเข้ารหัส HTML ล่วงหน้าเนื่องจาก แอพของฉันสามารถส่งรูปแบบอื่น ๆ เช่น PDF และ CSV นอกเหนือจาก HTML ตำแหน่งที่เหมาะสมสำหรับการจัดรูปแบบ HTML อยู่ในเทมเพลต ("ดู" หากคุณต้องการ) ที่รับผิดชอบการแสดงผลส่วนของหน้านั้น (ตัวอย่าง) ฉันต้องการแปลงให้เป็นเอนทิตี HTML ที่เหมาะสม แต่ฟังก์ชัน get_html_translation_table () ของ PHP นั้นไม่เร็วมาก ทำให้รู้สึกดีขึ้นในการดึงข้อมูลหนึ่งครั้งและเก็บเป็นอาร์เรย์ทำให้ทุกคนสามารถใช้งานได้ นี่' ตัวอย่างฉันเคาะด้วยกันเพื่อทดสอบความเร็ว สมมุติว่าวิธีนี้ใช้ได้ผลโดยไม่คำนึงว่าวิธีอื่นที่คุณใช้ (หลังจากได้รับอินสแตนซ์) นั้นคงที่หรือไม่
class EncodeHTMLEntities {
private static $instance = null;//stores the instance of self
private $r = null;//array of chars elligalbe for replacement
private function __clone(){
}//disable cloning, no reason to clone
private function __construct()
{
$allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
$specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
$this->r = array_diff($allEntities, $specialEntities);
}
public static function replace($string)
{
if(!(self::$instance instanceof self) ){
self::$instance = new self();
}
return strtr($string, self::$instance->r);
}
}
//test one million encodings of a string
$start = microtime(true);
for($x=0; $x<1000000; $x++){
$dump = EncodeHTMLEntities::replace("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)");
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds using singleton\n";
//now repeat the same without using singleton
$start = microtime(true);
for($x=0; $x<1000000; $x++){
$allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
$specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
$r = array_diff($allEntities, $specialEntities);
$dump = strtr("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)", $r);
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds without using singleton";
โดยทั่วไปฉันเห็นผลลัพธ์ทั่วไปดังนี้:
php test.php เวลาทำงาน: 27.842966794968 วินาทีโดยใช้ซิงเกิล เวลาทำงาน: 237.78191494942 วินาทีโดยไม่ต้องใช้ซิงเกิล
ดังนั้นในขณะที่ฉันไม่มีผู้เชี่ยวชาญแน่นอนฉันไม่เห็นวิธีที่สะดวกและเชื่อถือได้มากขึ้นในการลดค่าใช้จ่ายในการโทรช้าสำหรับข้อมูลบางประเภทในขณะที่ทำให้มันง่ายมาก (รหัสบรรทัดเดียวเพื่อทำสิ่งที่คุณต้องการ) ให้ตัวอย่างของฉันมีวิธีที่มีประโยชน์เพียงวิธีเดียวเท่านั้นดังนั้นจึงไม่ดีไปกว่าฟังก์ชั่นที่กำหนดไว้ทั่วโลก แต่ทันทีที่คุณมีสองวิธีคุณจะต้องจัดกลุ่มพวกมันด้วยกันใช่ไหม? ฉันจะออกจากฐาน?
นอกจากนี้ฉันชอบตัวอย่างที่ทำอะไรบางอย่างจริง ๆ เพราะบางครั้งมันยากที่จะมองเห็นเมื่อตัวอย่างมีข้อความเช่น "// ทำบางสิ่งที่มีประโยชน์ที่นี่" ซึ่งฉันเห็นตลอดเวลาเมื่อค้นหาบทช่วยสอน
อย่างไรก็ตามฉันชอบความคิดเห็นหรือความคิดเห็นใด ๆ ว่าทำไมการใช้ซิงเกิลตันสำหรับสิ่งประเภทนี้จึงเป็นอันตราย (หรือซับซ้อนเกินไป)
บทความนี้ครอบคลุมหัวข้อค่อนข้างครอบคลุม: http://www.phptherightway.com/pages/Design-Patterns.html#singleton
หมายเหตุดังต่อไปนี้:
- Constructor
__construct()
ถูกประกาศprotected
เพื่อป้องกันการสร้างอินสแตนซ์ใหม่นอกคลาสผ่านnew
โอเปอเรเตอร์- วิธีเวทย์มนตร์
__clone()
ถูกประกาศprivate
เพื่อป้องกันการโคลนอินสแตนซ์ของคลาสผ่านclone
โอเปอเรเตอร์- วิธีมายากล
__wakeup()
ถูกประกาศเป็นprivate
เพื่อป้องกันไม่ให้ unserializingunserialize()
ของตัวอย่างของการเรียนที่ผ่านฟังก์ชั่นระดับโลก- ตัวอย่างใหม่จะถูกสร้างขึ้นผ่านปลายคงมีผลผูกพันในวิธีการสร้างคงด้วยคำหลัก
getInstance()
static
สิ่งนี้อนุญาตให้ subclassing ของclass Singleton
ในตัวอย่าง
ฉันได้เขียนความคิดที่ยาวนานมาแบ่งปันที่นี่
class SingletonDesignPattern {
//just for demo there will be only one instance
private static $instanceCount =0;
//create the private instance variable
private static $myInstance=null;
//make constructor private so no one create object using new Keyword
private function __construct(){}
//no one clone the object
private function __clone(){}
//avoid serialazation
public function __wakeup(){}
//ony one way to create object
public static function getInstance(){
if(self::$myInstance==null){
self::$myInstance=new SingletonDesignPattern();
self::$instanceCount++;
}
return self::$myInstance;
}
public static function getInstanceCount(){
return self::$instanceCount;
}
}
//now lets play with singleton design pattern
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
echo "number of instances: ".SingletonDesignPattern::getInstanceCount();
ฉันเห็นด้วยกับคำตอบแรก แต่ฉันก็จะประกาศให้ชั้นเป็นขั้นสุดท้ายเพื่อที่จะไม่สามารถขยายได้เมื่อขยายซิงเกิลที่ละเมิดรูปแบบซิงเกิล นอกจากนี้ตัวแปรอินสแตนซ์ควรเป็นแบบส่วนตัวเพื่อให้ไม่สามารถเข้าถึงได้โดยตรง ทำให้เมธอด __clone เป็นไพรเวตเพื่อให้คุณไม่สามารถโคลนวัตถุซิงเกิล
ด้านล่างนี้คือตัวอย่างโค้ด
/**
* Singleton class
*
*/
final class UserFactory
{
private static $_instance = null;
/**
* Private constructor
*
*/
private function __construct() {}
/**
* Private clone method
*
*/
private function __clone() {}
/**
* Call this method to get singleton
*
* @return UserFactory
*/
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new UserFactory();
}
return self::$_instance;
}
}
ตัวอย่างการใช้งาน
$user_factory = UserFactory::getInstance();
สิ่งนี้จะหยุดคุณจากการทำ (ซึ่งจะละเมิดรูปแบบซิงเกิล ..
คุณไม่สามารถทำเช่นนี้ได้!
$user_factory = UserFactory::$_instance;
class SecondUserFactory extends UserFactory { }
นี่ควรเป็นวิธีที่ถูกต้องของซิงเกิล
class Singleton {
private static $instance;
private $count = 0;
protected function __construct(){
}
public static function singleton(){
if (!isset(self::$instance)) {
self::$instance = new Singleton;
}
return self::$instance;
}
public function increment()
{
return $this->count++;
}
protected function __clone(){
}
protected function __wakeup(){
}
}
ฉันชอบวิธีการ @ jose-segura ของการใช้ลักษณะ แต่ไม่ชอบความจำเป็นในการกำหนดตัวแปรคงที่ในคลาสย่อย ด้านล่างนี้เป็นวิธีการแก้ปัญหาที่หลีกเลี่ยงได้โดยการแคชอินสแตนซ์ในตัวแปรสแตติกท้องถิ่นไปยังวิธีการจัดทำดัชนีจากโรงงานโดยชื่อคลาส:
<?php
trait Singleton {
# Single point of entry for creating a new instance. For a given
# class always returns the same instance.
public static function instance(){
static $instances = array();
$class = get_called_class();
if( !isset($instances[$class]) ) $instances[$class] = new $class();
return $instances[$class];
}
# Kill traditional methods of creating new instances
protected function __clone() {}
protected function __construct() {}
}
การใช้งานเหมือนกับ @ jose-segura ไม่จำเป็นต้องมีตัวแปรสแตติกในคลาสย่อยเท่านั้น
คลาสฐานข้อมูลที่ตรวจสอบว่ามีอินสแตนซ์ฐานข้อมูลใด ๆ ที่มีอยู่จะส่งคืนอินสแตนซ์ก่อนหน้า
class Database {
public static $instance;
public static function getInstance(){
if(!isset(Database::$instance) ) {
Database::$instance = new Database();
}
return Database::$instance;
}
private function __cunstruct() {
/* private and cant create multiple objects */
}
public function getQuery(){
return "Test Query Data";
}
}
$dbObj = Database::getInstance();
$dbObj2 = Database::getInstance();
var_dump($dbObj);
var_dump($dbObj2);
/*
After execution you will get following output:
object(Database)[1]
object(Database)[1]
*/
อ้างอิงhttp://www.phptechi.com/php-singleton-design-patterns-example.html
นี่คือตัวอย่างของการสร้างซิงเกิลตันในคลาสฐานข้อมูล
รูปแบบการออกแบบ 1) ซิงเกิล
class Database{
public static $instance;
public static function getInstance(){
if(!isset(Database::$instance)){
Database::$instance=new Database();
return Database::$instance;
}
}
$db=Database::getInstance();
$db2=Database::getInstance();
$db3=Database::getInstance();
var_dump($db);
var_dump($db2);
var_dump($db3);
จากนั้นออกวางคือ -
object(Database)[1]
object(Database)[1]
object(Database)[1]
ใช้อินสแตนซ์เดียวเท่านั้นที่ไม่ได้สร้าง 3 อินสแตนซ์
ตัวอย่างด่วน:
final class Singleton
{
private static $instance = null;
private function __construct(){}
private function __clone(){}
private function __wakeup(){}
public static function get_instance()
{
if ( static::$instance === null ) {
static::$instance = new static();
}
return static::$instance;
}
}
หวังว่าจะช่วย
นี่คือตัวอย่างของฉันที่ให้ความสามารถในการเรียกใช้เป็น $ var = new Singleton () และสร้างตัวแปร 3 ตัวเพื่อทดสอบว่ามันสร้างวัตถุใหม่หรือไม่:
class Singleton{
private static $data;
function __construct(){
if ($this::$data == null){
$this->makeSingleton();
}
echo "<br/>".$this::$data;
}
private function makeSingleton(){
$this::$data = rand(0, 100);
}
public function change($new_val){
$this::$data = $new_val;
}
public function printme(){
echo "<br/>".$this::$data;
}
}
$a = new Singleton();
$b = new Singleton();
$c = new Singleton();
$a->change(-2);
$a->printme();
$b->printme();
$d = new Singleton();
$d->printme();