Klassen erweitern
Mike88
- php
Hi,
ich habe es geschafft die MYSQLI Klasse zu erweitern und dadurch ist es mir möglich als Übergabeparameter verschiedene DB-Benutzer anzugeben.
class db extends mysqli
{
public function __construct($u='db_user_standard')
{
$db = parent::__construct('localhost', $u, 'passwort', 'datenbank');
}
}
...
$db = new db;
$sql = "SELECT `first_name`, `last_name` FROM `user`";
$result = $db->prepare($sql);
$result->execute();
$result->bind_result($first_name,$last_name);
funktioniert super
aber jetzt zu meinem Problem, wie schaffe ich es dass ich mit einem Aufruf diese Schritte zusammenfasse.
ich meine zB
$result = $db->mein_query($sql,array($first_name,$last_name));
vielen Dank für eure Hilfe
mfg Mike
Moin!
ich habe es geschafft die MYSQLI Klasse zu erweitern und dadurch ist es mir möglich als Übergabeparameter verschiedene DB-Benutzer anzugeben.
class db extends mysqli
{
public function __construct($u='db_user_standard')
{
$db = parent::__construct('localhost', $u, 'passwort', 'datenbank');
}
}
Warum die unterschiedlichen DB-User alle dasselbe Passwort verwenden, ist mir rätselhaft... Das ist definitiv kein gutes Design.
Der Konstruktor gibt nichts zurück. Warum speicherst du dieses "Nichts" in $db?
> ~~~php
> $db = new db;
Schlechtes Design: Du nimmst einfach den Standarduser mit dem fest definierten Passwort. Besser ist, wenn Username UND Passwort in einer Konfiguration stehen, von dort ausgelesen werden und der DB-Klasse via Konstruktor übergeben werden.
>
> $sql = "SELECT `first_name`, `last_name` FROM `user`";
>
> $result = $db->prepare($sql);
> $result->execute();
> $result->bind_result($first_name,$last_name);
>
funktioniert super
aber jetzt zu meinem Problem, wie schaffe ich es dass ich mit einem Aufruf diese Schritte zusammenfasse.
ich meine zB$result = $db->mein_query($sql,array($first_name,$last_name));
Indem du die nächste Schicht Objekt einziehst, nämlich die, die ein Objekt vom Typ "db" im Konstruktor entgegennimmt und dann eine Methode "mein_query" anbietet, welche intern mit dem db-Objekt die notwendigen Einzelschritte ausführt.
Wobei auch hier wieder die Frage nach dem schönen Design zu stellen ist: Wo sollte der auszuführende Query definiert sein? Nach meiner Meinung in einer Klasse, die nach außen hin nur verspricht, gewisse Informationen aus einem gewissen Themenbereich zu beschaffen. Heißt: Du hast eine Liste von Benutzern, und du hast eine Klasse, die ais der Liste von Benutzern Infos beschafft.
Die erste Überlegung zur Abstraktion ist: Diese User-Klasse nutzt intern die DB-Klasse, um Querys an die Datenbank zu schicken, das Ergebnis abzufragen und es dann nach außen zu geben.
Du hast also:
class Model_User
{
/**
* @var My_Db
**/
private $_db;
public function __construct(My_Db $db)
{
$this->_db = $db;
}
public function getUserById($id)
{
$query = "SELECT `first_name`, `last_name` FROM `user` WHERE `userid` = ". (int) $id;
$dbResult = $this->_db->query($query);
$result = array();
foreach ($dbResult as $row) {
$result[] = $row;
}
return $result;
}
}
class My_Db extends mysqli
{
public function __construct($username, $password)
{
parent::__construct('localhost', $username, $password, 'datenbank');
}
}
$config = array("db" => array("user" => "manfred", "password" => "hugendubel"));
// $config = parse_ini_file("config.ini"); // wäre vermutlich eleganter
$userModel = new Model_User(new MyDb($config["db"]["user"], $config["db"]["password"]));
var_dump($userModel->getUserById(23));
Vermutlich wird diese sehr enge Kopplung von User-Model an DB eine Zeit lang gut funktionieren, solange bis du entweder die Datenbank wechseln willst, oder ganz von SQL-Datenbanken wegkommst, aus irgendwelchen Gründen.
Deshalb ist es nicht verkehrt, dass das User-Model nicht direkt mit der Datenbank redet, sondern lediglich einer Zwischenschicht mitteilt, welche Art von Information gewünscht ist (im Beispiel einfach der User mit ID = 23), und diese Zwischenschicht sich drum kümmert, dass dieser Wunsch erstmal in einen Query umgesetzt wird, der danach dann an das DB-Objekt zur Ausführung übergeben wird.
Das User-Model kriegt also irgendein Objekt der Zwischenschicht und kann dem sagen: "Besorge mir User-ID 23", und wenn dieses Objekt ein Mysql-DB-Zwischenschichtobjekt ist, dann wird es diese DB befragen. Alternativ könnte aber auch ein Textdatei-Zwischenschichtobjekt übergeben worden sein, welches dieselbe Methode zum Ermitteln von User-ID 23 kennt, aber statt des Querys einfach eine Datei auf Festplatte ausliest und den Inhalt zurückliefert - natürlich in gleichartiger Aufmachung, also z.B. auch als Array oder User-Objekt.
An dieser Stelle ist dann irgendwann vielleicht auch die Erkenntnis gereift, dass das Erweitern des mysqli-Objekts vielleicht gar keine so gute Idee ist, denn dadurch sind sämtliche Methoden, die dieses Objekt anbietet, für die Schicht darüber zwingend zu nutzen. Dadurch ist man aber auch Veränderungen in diesem Objekt unterworfen und muss sie zwingend an allen Stellen, die auf dieses erweiterte Objekt zugreifen, abändern. Schöner wird es sein, wenn man das mysqli-Objekt tatsächlich kapselt, also eine neue Klasse schafft, welche dieses Objekt ENTHÄLT, nicht erweitert. Und dieses eigene Objekt bietet dann nach außen die Methoden an, die man braucht - und dies auch nur in der notwendigen Komplexität, d.h. nur die wirklich notwendigen Parameter, alles andere, vor allem alles mit Standardwerten, was man einmal für sich festlegen kann, wird dort NICHT als Parameter durchgereicht, sondern erst intern hinzugefügt.
Auf diese Weise erreicht man so nach und nach eine gute Abstraktion und insbesondere eine Trennung der einzelnen Aufgaben in definierten Schichten, so dass die Applikation am Ende mit recht wenig Aufwand an Veränderungen angepasst werden kann, die definitiv kommen werden.
- Sven Rautenberg