Archiv verlassen und diese Seite im Standarddesign anzeigen : Singleton Pattern für DB Klasse
Hi,
Ich erweitere gerade meine MySQL Klasse mit dem singleton pattern. Dafür habe ich das untere in die DB Klasse eingefuegt.
// Die Singleton Funktion
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
In meiner index.php hatte ich nun immer diesen part:
$object=new MySQL ($dbhost,$dbuser,$dbpass,$dbname);
Und der constructor hat das dann verwendet:public function __construct($dbhost,$dbuser,$dbpassword,$dbname)
wenn ich es richtig verstanden habe faellt dieses nun weg und stattdessen benutze ich dieses
$object=MySQL::singleton ();
Was ich nun jedoch nicht verstehe, wie bekomme ich $dbhost,$dbuser,$dbpass,$dbname an die MySQL Klasse weitergereicht?
Ich hatte das bereits in einem anderen Forum versucht zu besprechen, dort ging das ganze Thema dann aber in eine Richtung der ich nicht mehr folgen konnte.
Ich hoffe mir kann hier jemand helfen, da ich einfach nicht weiter komme. Vielen Dank im Voraus.
Gruss Luka
Griecherus 26-12-2008, 23:15 Original geschrieben von Luka
Was ich nun jedoch nicht verstehe, wie bekomme ich $dbhost,$dbuser,$dbpass,$dbname an die MySQL Klasse weitergereicht?
Beispielsweise indem du der Singleton-Methode die benötigten Parameter übergibst, die sie ihrerseits an den Konstruktur der Klasse übergibt:
class Database
{
static public function singleton($db_host, $db_user, ...)
{
if (is_null(self::$_instance))
{
self::$_instance = new self($db_host, $db_user, ...);
}
return self::$_instance;
}
protected function __construct($db_host, $db_user, ...)
{
}
}
$db = Database::singleton($db_host, $db_user, $db_pass, $db_name);
Du solltest die Sichtbarkeit des Konstrukturs übrigens auf protected einschränken, wenn die Klasse als Singleton implementiert werden soll. Das verhindet nämlich das direkte Erzeugen einer Instanz der Klasse durch new.
Grüße
PHP-Desaster 26-12-2008, 23:20 Oder eine weitere Methode, die die Instanz initialisiert.
public static function initInstance($dbhost,$dbuser,$dbpassword,$dbname) {
self::$instance=new self($dbhost,$dbuser,$dbpassword,$dbname);
}
public static function getInstance() {
if(self::$instance===NULL) {
throw new Exception('Singleton not initialized');
}
return self::$instance;
}
Das Singleton-Pattern ist aber schon fast ein Anti-Pattern. Meist ist eine Registry anbrachter.
Griecherus 26-12-2008, 23:27 Oder aber durch eine Setter-Methode:
public function __set($name, $value)
{
switch ($name)
{
case 'db_host';
$this->db_host = (string)$value;
break;
...
}
}
$db = Database::singleton();
$db->host = 'localhost';
$db->user = 'me';
$db->pass = 'secret';
...
$db->connect();
Wenngleich ich keine Motivation sehe, das strukturell so zu lösen, ist es technisch eine Möglichkeit. Was das Registry-Pattern angeht, schließe ich mich PHP-Desaster an.
Ich möchte meine DB Verbindung ja in einer anderen Klasse nutzen. Daher hatte ich bisher das $object an meine Login Klasse übergeben.
Ich verstehe nun jedoch nicht wie ich es mit dem singleton mache object=MySQL::singleton (); gehört das in die index.php und ich muss weiter das $object an die Login Klasse übergeben oder gehört der Part in die die Login Klasse selber und es wird nichts mehr übergeben?
Griecherus 27-12-2008, 00:38 Original geschrieben von Luka
Ich möchte meine DB Verbindung ja in einer anderen Klasse nutzen. Daher hatte ich bisher das $object an meine Login Klasse übergeben.
Und wieso sollte das jetzt nicht mehr gehen?
$db = Database::singleton(
$db_host,
$db_user,
$db_pass,
$db_name
);
$login = new Login($db);
// login.class.php
class Login
{
protected $_db = null;
public function __construct(Database $db)
{
$this->_db = $db;
}
}
Wenn du das Singleton-Entwurfsmuster allerdings zweckentfremden und daraus einen "Globalisator" für deine Klassen machen möchtest, sieht das Ganze wieder anders aus:
class Login
{
protected $_db = null;
public function __construct()
{
// hier musst du nun natürlich dafür sorgen, dass die benötigten
// Parameter existieren, also sie entweder dem Konstruktor
// der Klasse ´Login` übergeben (was sehr unsauber gelöst
// wäre) oder sie irgendwie* aus einem/dem global Skopus
// holen
$this->_db = Database::singleton($db_host, ...);
}
}
Ich sage dabei aber nicht ohne Grund "zweckentfremden", denn dafür ist Singleton nicht gedacht, sonder das Registry Pattern (http://www.phpbar.de/w/Registry)*, das einen applikationsweiten globalen Gültigkeitsbereich (Skopus) für Parameter, Instanzen, Ressourcen usw. bereit stellt.
Hi,
ok, ich glaube ich habe das mit dem Singleton völlig falsch verstanden. Ich dachte mir das eigentlich so, ich instanziere einmal das Objekt der MySQL Klasse. Das wird dann dank singleton wie soll man sagen, abgespeichert ist vielleicht das falsche Wort, aber mir fällt nichts besseres ein. Danach muss ich dann das Objekt nicht mehr an meine anderen Klassen übergeben sondern kann einfach über singleton in jeder beliebigen Klasse darauf zugreifen.
Wenn ich mir das jetzt so anschaue, ist das aber wohl nicht der Fall. Gibt es denn ein Pattern, was genau das macht was ich beschreibe? Benutzt Ihr singleton für Eure DB Verbindung oder was macht Ihr?
Benutzt Ihr singleton für Eure DB Verbindung oder was macht Ihr?
Definitiv NEIN!
Ich arbeite meist mit einer Kombination aus Factory + Registry in meinem Application Object. Fertig!
Optimaler wäre das "Dependency Injection Design Pattern". Aber das ist meist mit Kanonen auf Spatzen in einer normalen PHP Anwendung.
PHP-Desaster 29-12-2008, 00:36 Wenn ich mir das jetzt so anschaue, ist das aber wohl nicht der Fall. Gibt es denn ein Pattern, was genau das macht was ich beschreibe? Benutzt Ihr singleton für Eure DB Verbindung oder was macht Ihr?Wieso nicht? Bei dir ist nunmal der Fall, dass dieses einzelne Objekt noch Parameter von außen benötigt, d.h. du musst die Instanz erst korrekt initialisieren.
Den Rest hat combie ja bereits sehr gut beantwortet.
|
|