Singleton Pattern

Posted in PHP, 11.02.2016 23:02

Erzeugungsmuster zur Erstellung genau EINER Instanz eines Objekts. Weitere Instanzen oder Klonen des Objects soll verhindert werden.

z.B Zend_Auth



     * Singleton instance
     *
     * @var Zend_Auth
     */
    protected static $_instance = null;


    /**
     * Singleton pattern implementation makes "new" unavailable
     *
     * @return void
     */
    protected function __construct()
    {}

    /**
     * Singleton pattern implementation makes "clone" unavailable
     *
     * @return void
     */
    protected function __clone()
    {}

    /**
     * Returns an instance of Zend_Auth
     *
     * Singleton pattern implementation
     *
     * @return Zend_Auth Provides a fluent interface
     */
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

DebuggerEcho (komplexeres Bsp)

 
namespace de\phpdesignpatterns\util\debug;

require_once 'Debugger.php';

class DebuggerEcho implements Debugger {

// in einer statischen Eigenschaft wird die Instanz gespeichert
    private static $instance = null;

// getInstance soll die einzige Funktion sein, durch die
// eine Instanz erzeugt werden kann

    public static function getInstance() {
        if (self::$instance == null) {
            self::$instance = new DebuggerEcho();
        }
        return self::$instance;
    }

// durch die protected-Deklaration wird der Konstruktor von außen unerreichbar
// dadurch kann durch den new-Operator keine weitere Instanz erzeugt werden

    protected function __construct() {
    }

// durch die private-Deklaration wird das 
// Klonen bereits vorhandener Instanzen verhindert

    private function __clone() {}

    public function debug($message) {
        echo "{$message}\n";
    }
}

$debuggerObi = DebuggerEcho::getInstance();
$debuggerObi->debug('Nutze die Macht, Luke!');

// $debuggerVader = clone $debuggerObi; // erzeugt Fatal error !

$debuggerVader = DebuggerEcho::getInstance();
$debuggerVader->debug('Luke, ich bin Dein Vater!');

if ($debuggerObi === $debuggerVader) {
    echo "Die beiden Debugger sind das selbe Objekt.\n"; // wird ausgegeben
} else {
    echo "Die beiden Debugger sind *NICHT* das selbe Objekt.\n";
}

Ausgabe mit PHP 5.3 (wichtig wg. Namespace-Deklaration!):

 Nutze die Macht, Luke!
Luke, ich bin Dein Vater!
Die beiden Debugger sind das selbe Objekt.

Das Debugger-Interface schreibt nur eine Funktion vor (debug):

 
namespace de\phpdesignpatterns\util\debug;

interface Debugger {
    public function debug($message);
}

 

Ausgabe mit PHP 5.3 (wichtig wg. Namespace-Deklaration!):

 
Nutze die Macht, Luke!
Luke, ich bin Dein Vater!
Die beiden Debugger sind das selbe Objekt.

Das Debugger-Interface schreibt nur eine Funktion vor (debug):

Variation: DebuggerLog

Singleton-Pattern parametrisiert. Es sollen abhängig von einem Parameter jeweils nur eine Instanz / Parameter zugelassen werden. Hier: der Name der Log-Datei wird übergeben. Wenn bereits eine Instanz für die Log-Datei existiert, sollen keine weiteren erzeugt werden. Lösung: die Klasseneigenschaft $instance wird als Array definiert.

 
namespace de\phpdesignpatterns\util\debug;

require_once 'Debugger.php';

class DebuggerLog implements Debugger {

    protected $logfile = null;
    // statische Klasseneigenschaft als Array
    private static $instances = array();

    // pro Parameter (Logfile) soll nur eine Instanz zugelassen werden
    
    public static function getInstance($logfile) {
        if (!isset(self::$instances[$logfile])) {
            self::$instances[$logfile] = new DebuggerLog($logfile);
        }
        return self::$instances[$logfile];
    }

    
    protected function __construct($logfile) {
        $this->logfile = $logfile;
    }
    private function __clone() {}

    public function debug($message) {
        error_log("{$message}\n", 3, $this->logfile);
    }
}

$debuggerObi = DebuggerLog::getInstance('./obi.log');
$debuggerObi->debug('Nutze die Macht, Luke!');

$debuggerVader = DebuggerLog::getInstance('./vader.log');
$debuggerVader->debug('Luke, ich bin Dein Vater!');

if ($debuggerObi === $debuggerVader) {
    echo "Die beiden Debugger sind das selbe Objekt.\n";
} else {
    echo "Die beiden Debugger sind *NICHT* das selbe Objekt.\n";
}