PHP5'te Singleton tasarım deseni oluşturma


204

PHP5 sınıflarını kullanarak bir Singleton sınıfı nasıl oluşturulur?



1
@Andrew Dont sonra veritabanına bağlanan ikinci bir örneği somutlaştırır. Bu örneği gereken yere iletin. Singleton'a duyulan ihtiyaç bir Kod Kokusudur. Gooh.posterous.com/singletons-in-php
Gordon

3
@Andrew Mmmmkay. Suç yok, ama bu tartışmaya devam etmeden önce yazılım kalitesi hakkında bir kitap almanızı öneririm. Singletons basitleştirmez, ancak normal bakım ve geliştirmeyi karmaşıklaştırır. Aslında, tam tersi: ilk etapta gelişimi basitleştiren ve mümkün kılan birim testleri.
Gordon

3
@Andrew: Artık yalnızca bir veritabanı bağlantısına ihtiyacınız olduğunu varsayıyorsunuz. Gereksinimleriniz değiştiğinde ve aslında 2 veritabanı sunucusuyla konuşmanız gerektiğinde ne olur? Ekibinizin bir şeyleri doğru yaptığına güvenemezseniz, tek birton oluşturmak size en azından yardımcı olmaz. İşleri en baştan yapın ve güvenebileceğiniz bir ekip edinin ve iyi olacaksınız.
ircmaxell

4
Singleton'un aşırı kullanılması kaçınılması gereken kötü bir model yapmaz. Singleton'dan nefret etme. Bazen belirli bir soruna mükemmel bir çözümdür. Sadece duygusal olarak aşağılamaya çalışmak yerine neden kullanmamamız gerektiğini tartışmaya başlasak iyi olur.
Gilles Lesire

Yanıtlar:


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

    }
}

Kullanmak:

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

$fact == $fact2;

Fakat:

$fact = new UserFactory()

Bir hata atar.

Statik değişken kapsamlarını ve ayarın neden işe yaradığını anlamak için http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static adresine bakın static $inst = null;.


59
iki örneği karşılaştırmak için == yerine === kullanmalısınız. == $ fact1 ve $ fact2 her ikisi de aynı sınıftaysa true değerini döndürür, ancak === yalnızca ikisi de aynı nesnenin aynı örneğiyse true değerini döndürür.
Keith Twombley

10
klon yöntemi de özel olmalı
Alex Petrov

22
Bu yöntem, Instance () öğesini her çağırışınızda UserFactory örneğini null değerine sıfırlamaz mı? Java'da $ inst değişkeni, tekrar tekrar sıfırlanmaması gereken özel bir statik öznitelik olacaktır, aksi takdirde bunu bir singleton yapamazsınız.
Rudy Garcia

8
Yazarın amaçladığı şekilde değişkenin işlevde statik olarak neden bildirildiğini ve nasıl çalıştığını gösteren iyi bir yazı: php.net/manual/en/…
hereswhatidid

10
$ İnst = new self (); $ inst = new UserFactory (); daha sonra karşılaşacak olanlar için. Yerleşik bir PHP metodolojisi kullanmak için +1.
Ligemer

119

PHP 5.3, geç statik bağlama yoluyla devralınabilen bir Singleton sınıfının oluşturulmasına izin verir:

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

Bu, PHP 5.3'ten önce bir Singleton'u genişleten herhangi bir sınıfın kendi yerine kendi sınıfının bir örneğini üretmesi sorununu çözmektedir.

Şimdi şunları yapabilirsiniz:

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

Ve $ foo, Singleton yerine Foobar örneği olacak.


1
Geç statik bağlanma gerçekten php 5.3 çok iyi bir şeydir. Çok kötü, hala kullanamıyorum.
AntonioCS

4
@Ggsonic Gönderen: "subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());".
Brock Adams

4
Bu hiç işe yaramıyor, öyle ki Foobar ilk inşa ettiğiniz sınıf oldu?
Chris KL

1
hala klonlama olasılığı ..... "$ a = Singleton :: getInstance (); $ b = unserialize (serialize ($ a)); $ a! == $ b;"
bortunac

15
Birden fazla alt sınıf olduğunda bu çalışmaz! $instancealt sınıfta değil, Singleton'da bulunur. Bazı alt sınıflar örneklendikten sonra getInstance () yöntemi tüm alt sınıflar için bu örneği döndürür.
mpartel

116

Ne yazık ki Inwdr'ın cevabı birden fazla alt sınıf olduğunda kesiliyor.

İşte doğru miras alınabilen Singleton temel sınıfı.

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

Test kodu:

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

echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";

1
Bu, Singleton uygulamasını düzeltmek için şimdiye kadar çok yakın. Serileştirmeyi önlemek için __wakeup () yöntemini de atmayı düşünmelisiniz .
Robert Rossmann

Aslında bir İstisna atmanız veya bir hatayı manuel olarak yükseltmeniz gerekir - işlevi korumalı / özel olarak bildirmek, yalnızca yönteme erişemediğini ancak aksi halde devam edeceğini söyleyen bir E_WARNING değerini yükseltir.
Robert Rossmann

Teşekkürler. Normalde tüm uyarıları vb. İstisnalara dönüştürdüm, bu yüzden test ettiğimde farkı unuttum: P
mpartel

Bu, birden fazla alt sınıfla düzgün bir şekilde ilgilenen bulduğum tek çözüm. Teşekkür ederim!
Bob Dankert

36

Singleton Deseni yapmanın Gerçek ve Modern yolu:

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

}

Yani şimdi onu kullanabilirsiniz.

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

Gördüğünüz gibi bu gerçekleşme çok daha esnektir.


4
Bu, bu iş parçacığındaki Singleton modeli hakkındaki en açık yanıttır. Teşekkürler.
Gus

Bu yaklaşımı uyguladım ve belirtildiği gibi çalışıyor: ikinci örnek null olur. Ancak somut sınıfı da genişletmem gerekmiyordu. Bu somut sınıfın yapıcısında Singleton :: instance () yöntemini yeni uyguladım.
snaphuman

içinde instancefonksiyonun $instanceolmalı nulldeğilfalse
Mifas

Evet, ama işlev değil, yöntem.
Abraham Tugalov

26

Muhtemelen bir örneğin klonlanmasına izin vermemek için özel bir __clone () yöntemi eklemeniz gerekir.

private function __clone() {}

Bu yöntemi eklemezseniz aşağıdakiler mümkün olur

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

Şimdi $inst1! == $inst2- artık aynı örnek değiller.


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

kullanmak:

/**
 *  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 kullanıyorsanız: trait bir seçenek, bu nedenle Singleton desenine sahip olmak için kalıtım hiyerarşisini boşa harcamanıza gerek yok

ve ayrıca aşağıdaki kod satırını eklemezseniz, özellikleri kullanmanız veya Singleton sınıfının bir gevşek ucunun genişletilmesinin , alt sınıfların singletonunu oluşturmak olduğuna dikkat edin:

   protected static $inst = null;

çocuk sınıfında

beklenmedik sonuç:

object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}

10
protected  static $_instance;

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

Bu kod, sınıf adını önemsemeden herhangi bir sınıfa uygulanabilir.


8

Sınıf başına 1 satır içeren birden çok nesneyi destekler:

Bu yöntem, herhangi bir sınıfta tekilleri uygulayacaktır, tek yapmanız gereken tekil yapmak istediğiniz sınıfa 1 yöntem eklemektir ve bu sizin için yapacaktır.

Bu ayrıca nesneleri "SingleTonBase" sınıfında depolar, böylece nesneleri tekrarlayarak sisteminizde kullandığınız tüm nesnelerin hatalarını ayıklayabilirsiniz SingleTonBase.


SingletonBase.php adlı bir dosya oluşturun ve bunu komut dosyanızın kök dizinine ekleyin!

Kod

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

Sonra herhangi bir sınıf için bir singleton yapmak sadece bu küçük tek yöntemi ekleyin.

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

İşte küçük bir örnek:

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

Ve bu singleton işlevini sahip olduğunuz herhangi bir sınıfa ekleyebilirsiniz ve sınıf başına yalnızca 1 örnek oluşturur.

Not: yeni Class () kullanımını ortadan kaldırmak için her zaman __construct özel yapmalısınız; örneklemi.


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

5

Gerçekten bir Singleton kalıbı kullanmanıza gerek yoktur, çünkü bu bir antipattern olarak kabul edilir. Temel olarak, bu kalıbı hiç uygulamamak için birçok neden var. Başlamak için bunu okuyun: PHP singleton sınıflarında en iyi uygulama .

Sonuçta hala Singleton desenini kullanmanız gerektiğini düşünüyorsanız, SingletonClassVendor soyut sınıfımızı genişleterek Singleton işlevselliğini elde etmemizi sağlayacak bir sınıf yazabiliriz.

Bu sorunu çözmek için birlikte geldim.

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

}

Örnek kullanın:

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

Sadece beklendiği gibi çalıştığını kanıtlamak için:

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

Daha fazla oylanan cevapları okurken aklımda böyle bir şey vardı. Neyse ki zaten buradaydı :)
hatef

3

Tüm bu karmaşıklık ("geç statik bağlama" ... harumph), bana göre, sadece PHP'nin kırık nesne / sınıf modelinin bir işaretidir. Sınıf nesneleri birinci sınıf nesnelerse (bkz. Python), "$ _instance" bir sınıf örneği olur değişkeni olacaktır - sınıf nesnesinin bir üyesi, örneklerinin bir üyesi / özelliğinin aksine ve aynı zamanda paylaşılanların aksine torunları tarafından. Smalltalk dünyasında bu, "sınıf değişkeni" ile "sınıf örneği değişkeni" arasındaki farktır.

PHP'de bana, kalıpların kod yazmaya yönelik bir rehber olduğu yönündeki rehberliğe ihtiyacımız var gibi görünüyor - belki de bir Singleton şablonu düşünebiliriz, ancak gerçek bir "Singleton" sınıfından miras alan kod yazmaya çalışabiliriz (Ben bazı girişimci ruhun uygun bir SVN anahtar kelime oluşturabilirsiniz varsayalım) PHP için yanlış görünüyor.

Paylaşılan bir şablon kullanarak her tek tek tek ayrı kodlamaya devam edeceğim.

Kesinlikle singleton-are-kötü tartışma dışında kalıyorum dikkat edin, hayat çok kısa.


PHP dilinin gittikçe artan karmaşıklığını görüntülerken açıklamalarınız doğru. Çok fazla farklı kodlama paradigmasında çok fazla farklı tasarım deliğinden çıkma yolunda çalışmak için çok fazla yeni anahtar kelime ekleniyor gibi görünüyor. Daha da kötüsü, yüksek değişim oranı ve ana bilgisayarlar ve geliştirme platformlarında sürüm eğriliği nedeniyle, bugünün "çözüm du jour" (@Eric Anderson'ın cevabındaki özellikler gibi [ stackoverflow.com/a/23998306/3696363), çalışmıyor "En yeni, en büyük" yerine "kararlı" bir sürümü çalıştırabilecek üretim sistemlerinde.
Eliyahu Skoczylas

2

Bu muhtemelen gereksiz bir alev savaşı neden olacağını biliyorum, ama birden fazla veritabanı bağlantısı nasıl isteyebilir görebilirsiniz, bu yüzden singleton bunun için en iyi çözüm olmayabilir noktası kabul ediyorum ... Ancak, vardır son derece kullanışlı bulduğum singleton deseninin diğer kullanımları.

İşte bir örnek: Kendi MVC ve şablon motorumu yuvarlamaya karar verdim çünkü gerçekten hafif bir şey istedim. Ancak, görüntülemek istediğim veriler ≥ ve μ gibi çok sayıda özel matematik karakteri içeriyor ve sizde neler var ... Veriler, HTML kodlamalı yerine veritabanımda gerçek UTF-8 karakteri olarak depolanıyor çünkü uygulamam HTML'ye ek olarak PDF ve CSV gibi başka formatlar da sunabilir. HTML için biçimlendirmek için uygun yer, söz konusu sayfa bölümünü (snippet) oluşturmaktan sorumlu olan şablonun içindedir (isterseniz "görünüm"). Onları uygun HTML varlıklarına dönüştürmek istiyorum, ancak PHP'lerin get_html_translation_table () işlevi süper hızlı değil. Verileri bir kez almak ve bir dizi olarak saklamak daha iyi olur, bu da herkesin kullanımına açıktır. Buraya' Bir örnek Hızı test etmek için birlikte vurdum. Muhtemelen, bu, kullandığınız diğer yöntemlerin (örneği aldıktan sonra) statik olup olmadığına bakılmaksızın işe yarayacaktır.

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

Temel olarak, böyle tipik sonuçlar gördüm:

php test.php
Çalışma süresi: singleton kullanarak 27.842966794968 saniye
Çalışma süresi: singleton kullanmadan 237.78191494942 saniye

Bu yüzden kesinlikle uzman olmamamla birlikte, bir tür veri için yavaş çağrıların yükünü azaltmak için daha kolay ve güvenilir bir yol görmüyorum, bu da süper basit hale getiriyor (ihtiyacınız olanı yapmak için tek bir kod satırı). Benim örneğimin sadece bir yararlı yöntemi var ve bu nedenle küresel olarak tanımlanmış bir işlevden daha iyi değil, ancak iki yönteminiz olur olmaz, bunları birlikte gruplamak isteyeceksiniz, değil mi? Ben üssün dışında mıyım?

Ayrıca, aslında bir şey yapmak örnekleri tercih ederim, çünkü bazen bir örnek "// burada yararlı bir şey yap" gibi ifadeler içerdiğinde görselleştirmek zor çünkü öğreticiler ararken her zaman görüyorum.

Her neyse, bu tür bir şey için neden bir singleton kullanmanın zararlı (veya aşırı derecede karmaşık) olduğuna dair herhangi bir geri bildirim veya yorum isterim.


1

Bu makale konuyu oldukça kapsamlı bir şekilde ele almaktadır: http://www.phptherightway.com/pages/Design-Patterns.html#singleton

Aşağıdakilere dikkat et:

  • Yapıcı __construct(), işleç protectedaracılığıyla sınıfın dışında yeni bir örnek oluşturulmasını önleyecek şekilde bildirilir new.
  • Magic yöntemi __clone(), privatesınıfın bir örneğinin cloneişleç aracılığıyla klonlanmasını önleyeceği bildirildi .
  • Magic yöntemi __wakeup(), privatesınıfın bir örneğinin küresel işlev aracılığıyla serileştirilmesini önleyeceği bildirildi unserialize().
  • getInstance()Anahtar kelime ile statik oluşturma yönteminde geç statik bağlama yoluyla yeni bir örnek oluşturulur static. Bu class Singleton, örnekteki alt sınıflamaya izin verir .

1

Burada paylaşmayı düşündüğüm uzun bir geçmiş yazdım

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

0

İlk yanıta katılıyorum, ancak sınıfı bir singletonun uzatılması singleton modelini ihlal ettiği için genişletilememesi için final olarak da beyan ederim. Ayrıca örnek değişkeni, doğrudan erişilememesi için özel olmalıdır. Ayrıca __clone yöntemini özel yapın, böylece singleton nesnesini klonlayamazsınız.

Aşağıda bazı örnek kodlar verilmiştir.

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

Örnek Kullanım

$user_factory = UserFactory::getInstance();

Bunun sizi yapmasını engeller (bu da singleton kalıbını ihlal eder.)

BUNU YAPAMAZSIN!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }

0

Bu Singleton için doğru yol olmalı.

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

    }

} 

0

@ Jose-segura özelliklerini kullanma yöntemini beğendim, ancak alt sınıflarda statik bir değişken tanımlama ihtiyacını beğenmedim. Aşağıda, statik bir yerel değişken içindeki örnekleri sınıf adına göre dizine alınan fabrika yöntemine önbelleğe alarak önleyen bir çözüm bulunmaktadır:

<?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 ile aynıdır, sadece alt sınıflarda statik değişkene gerek yoktur.


0

Var olan herhangi bir veritabanı örneği olup olmadığını kontrol eden veritabanı sınıfı, önceki örneği döndürür.

   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


0

Bu, Veritabanı sınıfında singleton oluşturma örneğidir

tasarım desenleri 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);

o zaman dışarı koymak -

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

3 örnek oluşturmamak için yalnızca tek örnek kullan


0

Hızlı örnek:

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

Umut yardım et.


-4

İşte $ var = new Singleton () olarak arama ve yeni nesne oluşturup oluşturmadığını test etmek için 3 değişken oluşturma yeteneği sağlayan örneğim:

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

5
Bunun dışında bir singleton değil. Singleton sınıfının birden çok örneğini oluşturabilirsiniz.
Andrew Moore

Ne de olsa bence, çünkü hangi örnek Singleton sınıfını etkiliyor olursa olsun, değişiklikler Singleton'un tüm örnekleri içindir. Yukarıda iki işlev daha ekledim. Şimdi, bir örnekte verileri değiştirmeyi ve diğerlerini kontrol etmeyi deneyelim. Yani, Singleton değil mi ve hayırsa - yanlış olan nedir?
bboydev

5
Singleton, kendisinin yalnızca bir örneğine izin veren bir sınıftır. Birden çok örnek oluşturarak, bu prensibi geçersiz kılarsınız.
Andrew Moore
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.