Membuat pola desain Singleton di PHP5

204

Bagaimana cara membuat kelas Singleton menggunakan kelas PHP5?

Andrew Moore
sumber
1
@Andrew Dont instantiate instance kedua yang menghubungkan ke database kemudian. Berikan contoh itu ke tempat yang dibutuhkan. Kebutuhan akan Singleton adalah Bau Kode. Lebih lanjut di gooh.posterous.com/singletons-in-php
Gordon
3
@Andrew Mmmmkay. Jangan tersinggung, tapi saya sarankan Anda mendapatkan buku tentang kualitas perangkat lunak sebelum kami melanjutkan diskusi ini. Lajang tidak menyederhanakan tetapi mempersulit pemeliharaan dan pengembangan normal. Faktanya, ini sebaliknya: unit-test yang menyederhanakan dan memungkinkan pengembangan sejak awal.
Gordon
3
@Andrew: Anda menganggap sekarang bahwa Anda hanya perlu satu koneksi basis data. Apa yang terjadi ketika persyaratan Anda berubah dan Anda benar-benar perlu berbicara dengan 2 server basis data? Belum lagi jika Anda tidak dapat mempercayai tim Anda untuk melakukan hal-hal yang benar , menciptakan singleton tidak akan membantu Anda sedikit pun. Lakukan hal yang benar dari awal dan dapatkan tim yang bisa Anda percayai dan Anda akan baik-baik saja.
ircmaxell
4
Hanya karena Singleton telah digunakan secara berlebihan tidak menjadikannya pola buruk yang harus dihindari. Jangan membenci Singleton. Terkadang ini adalah solusi yang sangat baik untuk masalah tertentu. Lebih baik mulai berdebat mengapa kita tidak boleh menggunakannya daripada hanya secara emosional mencoba menurunkannya.
Gilles Lesire

Jawaban:

268
/**
 * 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()
    {

    }
}

Menggunakan:

$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();

$fact == $fact2;

Tapi:

$fact = new UserFactory()

Melempar kesalahan

Lihat http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static untuk memahami cakupan variabel statis dan mengapa pengaturan static $inst = null;berfungsi.

Arount
sumber
59
untuk membandingkan dua contoh, Anda harus menggunakan === daripada ==. == akan mengembalikan true jika $ fact1 dan $ fact2 keduanya dari kelas yang sama, tetapi === hanya mengembalikan true jika keduanya merupakan instance yang sama dari objek yang sama.
Keith Twombley
10
Metode klon juga harus bersifat pribadi
Alex Petrov
22
Apakah metode ini tidak akan menyetel ulang instance UserFactory ke null setiap kali Anda memanggil Instance ()? Dalam java, variabel $ inst akan menjadi atribut statis privat yang tidak boleh di-reset berulang-ulang, jika tidak, Anda mungkin juga tidak menjadikannya singleton.
Rudy Garcia
8
Berikut ini adalah penulisan yang bagus tentang mengapa dan bagaimana mendeklarasikan variabel sebagai statis dalam fungsinya berfungsi sesuai dengan maksud penulis: php.net/manual/en/…
hereswhatidid
10
Anda harus menggunakan $ inst = new self (); bukan $ inst = UserFactory baru (); bagi siapa saja yang menemukan ini nanti. +1 untuk menggunakan metodologi PHP bawaan.
Ligemer
119

PHP 5.3 memungkinkan pembuatan kelas Singleton yang dapat diwariskan melalui pengikatan statis akhir:

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;
    }
}

Ini memecahkan masalah, bahwa sebelum PHP 5.3 setiap kelas yang memperpanjang Singleton akan menghasilkan turunan dari kelas induknya bukan miliknya sendiri.

Sekarang Anda bisa melakukannya:

class Foobar extends Singleton {};
$foo = Foobar::getInstance();

Dan $ foo akan menjadi turunan dari Foobar bukan turunan dari Singleton.

selfawaresoup
sumber
1
Mengikat statis terlambat memang hal yang sangat baik di php 5.3. Sayang sekali saya masih tidak bisa menggunakannya.
AntonioCS
4
Dari @ggsonic: "subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());".
Brock Adams
4
Ini tidak bekerja sama sekali, kebetulan Foobar adalah kelas pertama yang Anda buat?
Chris KL
1
masih ada kemungkinan untuk mengkloning ..... "$ a = Singleton :: getInstance (); $ b = unserialize (serialize ($ a)); $ a! == $ b;"
bortunac
15
Ini tidak berfungsi ketika ada lebih dari satu subkelas! $instanceberada di Singleton, bukan subclass. Setelah beberapa subclass di-instantiated, getInstance () akan mengembalikan instance itu untuk semua subclass.
mpartel
116

Sayangnya jawaban Inwdr terputus ketika ada beberapa subclass.

Ini adalah kelas dasar Singleton bawaan yang benar.

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];
    }
}

Kode uji:

class Foo extends Singleton {}
class Bar extends Singleton {}

echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";
bagian
sumber
1
Sejauh ini yang paling dekat dengan memperbaiki implementasi Singleton. Anda juga harus mempertimbangkan untuk melempar metode __wakeup () untuk mencegah unserialisation.
Robert Rossmann
Sebenarnya Anda harus melempar Pengecualian atau meningkatkan kesalahan secara manual - mendeklarasikan fungsi sebagai terproteksi / pribadi hanya akan memunculkan E_WARNING yang mengatakan bahwa ia tidak dapat mengakses metode, tetapi sebaliknya akan dilanjutkan.
Robert Rossmann
Terima kasih. Saya biasanya memiliki semua peringatan dll berubah menjadi pengecualian, jadi saya lupa tentang perbedaan ketika saya diuji: P
mpartel
Ini adalah satu-satunya solusi yang saya temukan yang benar menangani beberapa sub-kelas. Terima kasih!
Bob Dankert
36

Cara Nyata dan Modern untuk membuat Pola Singleton adalah:

<?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() {}

}

Jadi sekarang Anda bisa menggunakannya seperti.

<?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

Seperti yang Anda lihat, realisasi ini jauh lebih fleksibel.

Abraham Tugalov
sumber
4
Ini adalah jawaban yang paling jelas tentang pola Singleton dalam utas ini. Terima kasih.
Gus
Saya telah menerapkan pendekatan ini dan berfungsi sebagai spected: instance kedua menjadi null. Namun saya tidak perlu memperluas kelas konkret juga. Saya baru saja mengimplementasikan Singleton :: instance () dalam konstruktor kelas konkret itu.
snaphuman
dalam instancefungsi $instanceseharusnya nulltidakfalse
Mifas
Yap, tapi itu bukan fungsi, tapi metode.
Abraham Tugalov
26

Anda mungkin harus menambahkan metode __clone () pribadi untuk melarang kloning instance.

private function __clone() {}

Jika Anda tidak memasukkan metode ini, berikut ini menjadi mungkin

$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;

sekarang $inst1! == $inst2- mereka bukan contoh yang sama lagi.

Stefan Gehrig
sumber
11
<?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(){
  }
}

menggunakan:

/**
 *  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) {
}

Jika Anda menggunakan PHP 5.4: trait nya pilihan, sehingga Anda tidak perlu membuang hirarki warisan untuk memiliki pola Singleton

dan perhatikan juga apakah Anda menggunakan ciri atau memperluas kelas Singleton pada akhirnya adalah membuat singleton dari kelas anak jika Anda tidak menambahkan baris kode berikut:

   protected static $inst = null;

di kelas anak

hasil yang tak terduga adalah:

object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}
jose segura
sumber
10
protected  static $_instance;

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

Kode ini dapat diterapkan untuk kelas apa pun tanpa peduli dengan nama kelasnya.

hungneox
sumber
8

Mendukung Banyak Objek dengan 1 baris per kelas:

Metode ini akan memberlakukan lajang pada setiap kelas yang Anda inginkan, yang harus Anda lakukan adalah menambahkan 1 metode ke kelas yang ingin Anda buat lajang dan ini akan melakukannya untuk Anda.

Ini juga menyimpan objek dalam kelas "SingleTonBase" sehingga Anda dapat men-debug semua objek yang telah Anda gunakan dalam sistem Anda dengan mengulangi SingleTonBaseobjek.


Buat file bernama SingletonBase.php dan sertakan di root skrip Anda!

Kodenya adalah

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;
    }
}

Kemudian untuk kelas mana pun yang Anda ingin membuat singleton cukup tambahkan metode tunggal kecil ini.

public static function Singleton()
{
    return SingletonBase::Singleton(get_class());
}

Ini adalah contoh kecil:

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();

Dan Anda bisa menambahkan fungsi singleton ini di kelas yang Anda miliki dan itu hanya akan membuat 1 instance per kelas.

CATATAN: Anda harus selalu menjadikan __construct pribadi untuk menghilangkan penggunaan Kelas baru (); Instansiasi.

RobertPitt
sumber
5
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();
Rizon
sumber
5

Anda tidak benar-benar perlu menggunakan pola Singleton karena dianggap sebagai antipattern. Pada dasarnya ada banyak alasan untuk tidak menerapkan pola ini sama sekali. Baca ini untuk mulai dengan: Praktik terbaik di kelas PHP tunggal .

Jika bagaimanapun Anda masih berpikir Anda perlu menggunakan pola Singleton maka kita bisa menulis kelas yang memungkinkan kita untuk mendapatkan fungsionalitas Singleton dengan memperluas kelas abstrak SingletonClassVendor kami.

Inilah yang saya datangi untuk menyelesaikan masalah ini.

<?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() {}

}

Gunakan contoh:

/**
 * 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
    }
}

Hanya untuk membuktikan bahwa itu berfungsi seperti yang diharapkan:

/**
 *  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
DevWL
sumber
Sambil membaca jawaban yang lebih tervotasikan, saya memikirkan hal ini. Untungnya sudah ada di sini :)
hatef
3

Semua kerumitan ini ("keterlambatan pengikatan statis" ... harumph), bagi saya, hanyalah tanda dari objek PHP rusak / model kelas. Jika objek kelas adalah objek kelas satu (lihat Python), maka "$ _instance" akan menjadi instance kelas variabel - anggota objek kelas, yang bertentangan dengan anggota / properti dari instansnya, dan juga sebagai lawan untuk dibagikan oleh keturunannya. Di dunia Smalltalk, ini adalah perbedaan antara "variabel kelas" dan "variabel instance kelas".

Dalam PHP, saya merasa seolah-olah kita perlu memperhatikan pedoman bahwa pola adalah panduan untuk menulis kode - kita mungkin berpikir tentang template Singleton, tetapi mencoba untuk menulis kode yang mewarisi dari kelas "Singleton" yang sebenarnya tampak sesat untuk PHP (meskipun saya kira beberapa jiwa giat dapat membuat kata kunci SVN yang cocok).

Saya akan terus hanya kode setiap singleton secara terpisah, menggunakan templat bersama.

Perhatikan bahwa saya benar-benar keluar dari diskusi lajang-jahat, hidup ini terlalu singkat.

Tom Stambaugh
sumber
Keterangan Anda benar saat melihat kompleksitas yang semakin meningkat dari bahasa PHP. Sepertinya terlalu banyak kata kunci baru yang ditambahkan untuk bekerja keluar dari terlalu banyak lubang desain yang berbeda dalam terlalu banyak paradigma pengkodean yang berbeda. Lebih buruk lagi, karena tingkat perubahan yang tinggi, dan versi miring di seluruh host dan platform pengembangan, "solusi du jour" hari ini (seperti ciri-ciri dalam jawaban @Eric Anderson [ stackoverflow.com/a/23998306/3696363], ) tidak berfungsi pada sistem produksi yang mungkin menjalankan versi "stabil" dan bukan "terbaru, terhebat."
Eliyahu Skoczylas
2

Saya tahu ini mungkin akan menyebabkan perang api yang tidak perlu, tetapi saya dapat melihat bagaimana Anda mungkin menginginkan lebih dari satu koneksi basis data, jadi saya akan mengakui bahwa singleton mungkin bukan solusi terbaik untuk itu ... namun, ada kegunaan lain dari pola singleton yang menurut saya sangat berguna.

Berikut ini contohnya: Saya memutuskan untuk menggulung MVC dan mesin templating saya sendiri karena saya menginginkan sesuatu yang sangat ringan. Namun, data yang ingin saya tampilkan berisi banyak karakter matematika khusus seperti ≥ dan μ dan apa pun yang Anda miliki ... Data disimpan sebagai karakter UTF-8 yang sebenarnya dalam basis data saya alih-alih pra-HTML-disandikan karena aplikasi saya dapat memberikan format lain seperti PDF dan CSV selain HTML. Tempat yang tepat untuk memformat HTML ada di dalam templat ("view" jika Anda mau) yang bertanggung jawab untuk merender bagian halaman itu (snippet). Saya ingin mengonversikannya ke entitas HTML yang sesuai, tetapi fungsi PHP get_html_translation_table () tidak super cepat. Masuk akal untuk mengambil data satu kali dan menyimpannya sebagai sebuah array, membuatnya tersedia untuk semua orang. Sini' sa sampel saya mengetuk bersama untuk menguji kecepatan. Agaknya, ini akan berhasil terlepas dari apakah metode lain yang Anda gunakan (setelah mendapatkan contoh) statis atau tidak.

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";

Pada dasarnya, saya melihat hasil khas seperti ini:

php test.php
Durasi: 27.842966794968 detik menggunakan singleton
Durasi: 237.78191494942 detik tanpa menggunakan singleton

Jadi, walaupun saya jelas bukan pakar, saya tidak melihat cara yang lebih nyaman dan dapat diandalkan untuk mengurangi overhead panggilan lambat untuk beberapa jenis data, sambil membuatnya super sederhana (satu baris kode untuk melakukan apa yang Anda butuhkan). Diberikan contoh saya hanya memiliki satu metode yang bermanfaat, dan karena itu tidak lebih baik dari fungsi yang didefinisikan secara global, tetapi begitu Anda memiliki dua metode, Anda akan ingin mengelompokkannya bersama, bukan? Apakah saya jauh dari markas?

Juga, saya lebih suka contoh yang benar-benar MELAKUKAN sesuatu, karena kadang-kadang sulit untuk memvisualisasikan ketika contoh menyertakan pernyataan seperti "// lakukan sesuatu yang berguna di sini" yang saya lihat sepanjang waktu ketika mencari tutorial.

Ngomong-ngomong, saya suka umpan balik atau komentar tentang mengapa menggunakan singleton untuk hal semacam ini merugikan (atau terlalu rumit).

pengguna2009125
sumber
1

Artikel ini membahas topik cukup luas: http://www.phptherightway.com/pages/Design-Patterns.html#singleton

Perhatikan yang berikut ini:

  • Konstruktor __construct()dinyatakan protecteduntuk mencegah pembuatan instance baru di luar kelas melalui newoperator.
  • Metode ajaib __clone()dinyatakan privateuntuk mencegah kloning instance kelas melalui cloneoperator.
  • Metode ajaib __wakeup()dinyatakan privateuntuk mencegah penghapusan kelas instance melalui fungsi global unserialize().
  • Mesin virtual baru dibuat melalui pengikatan statis lanjut dalam metode pembuatan statis getInstance()dengan kata kunci static. Ini memungkinkan subklasifikasi class Singletondalam contoh.
Krzysztof Przygoda
sumber
1

Saya telah menulis pemikiran lama untuk dibagikan di sini

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();
Gyaneshwar Pardhi
sumber
0

Saya setuju dengan jawaban pertama tetapi saya juga akan menyatakan kelas sebagai final sehingga tidak dapat diperpanjang karena memperluas singleton melanggar pola singleton. Juga variabel instan harus pribadi sehingga tidak dapat diakses secara langsung. Jadikan juga metode __clone pribadi sehingga Anda tidak dapat mengkloning objek singleton.

Di bawah ini adalah beberapa contoh kode.

/**
 * 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;
    }
}

Contoh Penggunaan

$user_factory = UserFactory::getInstance();

Apa ini menghentikan Anda dari melakukan (yang akan melanggar pola singleton ..

ANDA TIDAK BISA MELAKUKANNYA!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }
Joseph Crawford
sumber
0

Ini harus menjadi cara yang benar dari Singleton.

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(){

    }

} 
Mário Kapusta
sumber
0

Saya suka metode @ jose-segura menggunakan ciri-ciri tetapi tidak suka kebutuhan untuk mendefinisikan variabel statis pada sub-kelas. Di bawah ini adalah solusi yang menghindarinya dengan melakukan caching instance dalam variabel lokal statis ke metode pabrik yang diindeks oleh nama kelas:

<?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() {}
}

Penggunaannya sama dengan @ jose-segura hanya tidak perlu untuk variabel statis di sub-kelas.

Eric Anderson
sumber
0

Kelas database yang memeriksa jika ada instance database yang ada, ia akan mengembalikan instance sebelumnya.

   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] 

*/  

Ref http://www.phptechi.com/php-singleton-design-patterns-example.html

sunil rajput
sumber
0

Ini adalah contoh dari membuat singleton pada kelas Database

pola desain 1) singleton

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);

maka put put adalah -

  object(Database)[1]
  object(Database)[1]
  object(Database)[1]

gunakan hanya satu instance tidak membuat 3 instance

Surendra Kumar Ahir
sumber
0

Contoh cepat:

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;
    }
}

Semoga bantuan.

Dmitry
sumber
-4

Inilah contoh saya yang memberikan kemampuan untuk memanggil $ var = new Singleton () dan juga membuat 3 variabel untuk menguji apakah ia menciptakan objek baru:

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();
bboydev
sumber
5
Kecuali bahwa itu bukan singleton. Anda dapat membuat banyak instance dari kelas Singleton.
Andrew Moore
Saya pikir bagaimanapun juga, karena tidak masalah instance mana yang mempengaruhi kelas Singleton, perubahan adalah untuk semua instance Singleton. Saya telah menambahkan dua fungsi lainnya di atas. Sekarang, mari kita coba modifikasi data dalam satu contoh dan lihat yang lainnya. Jadi, bukan Singleton dan jika tidak - apa yang salah?
bboydev
5
Singleton adalah kelas yang hanya mengizinkan satu instance dari dirinya sendiri. Dengan membuat banyak contoh, Anda membatalkan prinsip itu.
Andrew Moore