Erstellen des Singleton-Entwurfsmusters in PHP5

Lesezeit: 7 Minuten

Erstellen des Singleton Entwurfsmusters in PHP5
Andreas Moore

Wie würde man eine Singleton-Klasse mit PHP5-Klassen erstellen?

  • Wer braucht Singletons in PHP

    – Gordon

    14. April 2011 um 6:47 Uhr

  • @Andrew Instanziieren Sie dann keine zweite Instanz, die eine Verbindung zur Datenbank herstellt. Übergeben Sie diese Instanz dorthin, wo sie benötigt wird. Die Notwendigkeit für einen Singleton ist ein Code Smell. Mehr bei gooh.posterous.com/singletons-in-php

    – Gordon

    15. April 2011 um 7:02 Uhr


  • @Andrew Mmmmkay. Nichts für ungut, aber ich schlage vor, Sie besorgen sich ein Buch über Softwarequalität, bevor wir diese Diskussion fortsetzen. Singletons vereinfachen nicht, sondern erschweren die normale Wartung und Entwicklung. Tatsächlich ist es umgekehrt: Es sind Unit-Tests, die die Entwicklung vereinfachen und überhaupt erst ermöglichen.

    – Gordon

    15. April 2011 um 17:07 Uhr


  • @Andrew: Sie gehen jetzt davon aus, dass Sie nur eine Datenbankverbindung benötigen. Was passiert, wenn sich Ihre Anforderungen ändern und Sie eigentlich mit 2 Datenbankservern sprechen müssen? Ganz zu schweigen davon, wenn Sie Ihrem Team nicht vertrauen können, Dinge zu tun rechts, das Erstellen eines Singletons wird Ihnen nicht im Geringsten helfen. Machen Sie die Dinge von Anfang an richtig und holen Sie sich ein Team, dem Sie vertrauen können, und es wird Ihnen gut gehen.

    – ircmaxell

    15. April 2011 um 17:10 Uhr

  • Nur weil das Singleton überstrapaziert wurde, ist es noch lange kein schlechtes Muster, das vermieden werden sollte. Hasse den Singleton nicht. Manchmal ist es eine perfekte Lösung für ein bestimmtes Problem. Beginnen Sie besser damit, zu argumentieren, warum wir es nicht verwenden sollten, anstatt nur zu versuchen, es emotional zu entwerten.

    – Gilles Lesire

    11. Dezember 2015 um 10:49 Uhr


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

    }
}

Benutzen:

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

$fact == $fact2;

Aber:

$fact = new UserFactory()

Wirft einen Fehler.

Sehen http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static um den Gültigkeitsbereich statischer Variablen und die Gründe für die Einstellung zu verstehen static $inst = null; funktioniert.

  • Um die beiden Instanzen zu vergleichen, sollten Sie === anstelle von == verwenden. == gibt wahr zurück, wenn $fakt1 und $fakt2 beide derselben Klasse angehören, aber === gibt nur wahr zurück, wenn sie beide dieselbe Instanz desselben Objekts sind.

    – Keith Twombley

    15. Oktober 2008 um 1:02 Uhr

  • Die Klonmethode sollte auch privat sein

    – Alex Petrow

    10. April 2013 um 4:22 Uhr

  • Wird diese Methode die Instanz von UserFactory nicht jedes Mal auf null zurücksetzen, wenn Sie Instance() aufrufen? In Java wäre die $inst-Variable ein privates statisches Attribut, das nicht immer wieder zurückgesetzt werden sollte, sonst könnten Sie es genauso gut nicht zu einem Singleton machen.

    – Rudy García

    7. Juni 2013 um 14:55 Uhr


  • Hier ist eine gute Beschreibung, warum und wie das Deklarieren der Variablen als statisch in der Funktion so funktioniert, wie der Autor beabsichtigt: php.net/manual/en/…

    – Hereswhatidid

    24. Januar 2015 um 5:48 Uhr


  • Sie sollten $inst = new self(); nicht $inst = new UserFactory(); für alle, die später darauf stoßen. +1 für die Verwendung einer integrierten PHP-Methodik.

    – Liger

    18. Februar 2015 um 3:27 Uhr


Erstellen des Singleton Entwurfsmusters in PHP5
Teil

Leider bricht die Antwort von Inwdr, wenn es mehrere Unterklassen gibt.

Hier ist eine korrekte vererbbare Singleton-Basisklasse.

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

Testcode:

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

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

  • Dies kommt der korrekten Singleton-Implementierung bisher am nächsten. Auch das Einwerfen sollte in Erwägung gezogen werden __Wach auf() Methode zur Vermeidung von Deserialisierung.

    – Robert Roßmann

    27. Oktober 2013 um 21:25 Uhr

  • Tatsächlich müssen Sie entweder eine Ausnahme auslösen oder manuell einen Fehler auslösen. Wenn Sie die Funktion als geschützt/privat deklarieren, wird nur eine E_WARNING ausgelöst, die besagt, dass sie nicht auf die Methode zugreifen kann, aber andernfalls fortfahren würde.

    – Robert Roßmann

    28. Oktober 2013 um 21:29 Uhr

  • Danke. Ich habe normalerweise alle Warnungen etc. in Ausnahmen umgewandelt, also habe ich den Unterschied vergessen, als ich getestet habe 😛

    – Teil

    28. Oktober 2013 um 22:43 Uhr

  • Dies ist die einzige Lösung, die ich gefunden habe, die mehrere Unterklassen richtig behandelt. Danke!

    – Bob Dankert

    22. Mai 2019 um 16:16 Uhr

Erstellen des Singleton Entwurfsmusters in PHP5
selbstbewusste Suppe

PHP 5.3 ermöglicht die Erstellung einer vererbbaren Singleton-Klasse über spätes statisches Binden:

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

Dies löst das Problem, dass vor PHP 5.3 jede Klasse, die ein Singleton erweitert hat, statt ihrer eigenen eine Instanz ihrer übergeordneten Klasse erzeugt hat.

Jetzt können Sie Folgendes tun:

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

Und $foo wird eine Instanz von Foobar statt einer Instanz von Singleton sein.

  • Spätes statisches Binden ist in der Tat eine sehr gute Sache in PHP 5.3. Schade, dass ich es immer noch nicht verwenden kann.

    – AntonioCS

    21. Dezember 2009 um 10:52 Uhr

  • Von @ggsonic: "subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());".

    – Brock Adams

    1. Dezember 2011 um 5:39 Uhr

  • Das funktioniert überhaupt nicht, es ist einfach so, dass Foobar die erste Klasse war, die Sie gebaut haben?

    – Chris KL

    10. September 2012 um 6:40 Uhr

  • noch eine Klonmöglichkeit ….. “$a=Singleton::getInstance(); $b=unserialize(serialize($a)); $a!==$b;”

    – Bortunac

    15. Oktober 2012 um 5:05 Uhr

  • Dies funktioniert nicht, wenn es mehr als eine Unterklasse gibt! $instance befindet sich in Singleton, nicht in der Unterklasse. Nachdem eine Unterklasse instanziiert wurde, gibt getInstance() diese Instanz für alle Unterklassen zurück.

    – Teil

    8. April 2013 um 2:22 Uhr

1646918651 499 Erstellen des Singleton Entwurfsmusters in PHP5
Abraham Tugalow

Das Echte und Moderne Möglichkeit, Singleton-Muster zu erstellen, ist:

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

}

So, jetzt können Sie es gerne verwenden.

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

Wie Sie sehen, ist diese Realisierung viel flexibler.

Sie sollten wahrscheinlich eine private __clone()-Methode hinzufügen, um das Klonen einer Instanz zu verbieten.

private function __clone() {}

Wenn Sie diese Methode nicht einschließen, wird Folgendes möglich

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

jetzt $inst1 !== $inst2 – sie sind nicht mehr dieselbe Instanz.

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

benutzen:

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

Antwort:

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

Wenn Sie PHP 5.4 verwenden: Merkmal Es ist eine Option, sodass Sie die Vererbungshierarchie nicht verschwenden müssen, um die zu haben Singleton-Muster

und beachten Sie auch, ob Sie verwenden Züge oder erweitert Singleton Das lose Ende von Klasse 1 bestand darin, Singleton von untergeordneten Klassen zu erstellen, wenn Sie die folgende Codezeile nicht hinzufügen:

   protected static $inst = null;

in der Kinderklasse

das unerwartete Ergebnis wird sein:

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

1646918651 70 Erstellen des Singleton Entwurfsmusters in PHP5
hungneox

protected  static $_instance;

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

Dieser Code kann für jede Klasse gelten, ohne sich um den Klassennamen zu kümmern.

988080cookie-checkErstellen des Singleton-Entwurfsmusters in PHP5

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy