MySQLi bei PHP benutzen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • MySQLi bei PHP benutzen

    Hallo,

    ich habe im Internet gelesen das es eine neue MySQL Erweiterung bei PHP5 gibt (halt MySQLi ;)).

    Ich bin jetzt etwas verwirrt. So wie ich das im PHP Manual lese ist mysqlii selbst schon eine Klasse auf die man objektorientiert zugreifen kann?

    Ich habe mit MySQL Meine eigene Datenbank Klasse gemacht mit eigenene Funktionen für die Querys und Verbinden usw.

    Hat es einen Sinn das ich die Funktionen in mysqli umändere? In den Funktionen greife ich ja dann auch wiederum auf die mysqli Klasse zu?

    Als Beispiel:

    Quellcode

    1. class db
    2. {
    3. private $db_host = "localhost";
    4. private $db_username = "user";
    5. private $db_password = "";
    6. private $db_database = "db1";
    7. private $result = NULL;
    8. function __construct()
    9. {
    10. mysqli::__construct($this->db_host, $this->db_username, $this->db_password, $this->db_database);
    11. if(mysqli_connect_error())
    12. {
    13. $this->error(mysqli_connect_errno());
    14. }
    15. }
    16. function select_db()
    17. {
    18. mysqli::select_db($this->db_database) OR $this->error(mysqli_connect_errno());
    19. }
    20. }
    Alles anzeigen


    Werden die Klassen dann nicht verschachtelt oder so?

    EDIT: Noch kurz eine Frage, damit ich kein extra Thema dafür eröffnen muss: Wenn ich ein Formular habe und diese Daten verarbeiten möchte. Sollte ich die Abfrage ob bestimmte Felder leer sind vor dem aufrufen und abschicken der Werte an eine Funktion des Objektes machen oder in der Funktion selbst?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Illidan ()

  • Es gibt verschiedene Best Practices bzw Design Patterns.

    Einmal könntest du die Datenbank komplett kapseln. Das heißt die DB Klasse verwaltet eine Instanz von MySQLi.
    Dann kannst du gleichzeitig pdo, mysqli oder andere Schnittstellen für oracle, etc nutzen.
    Der Nachteil daran ist, dass du dich auf die Schnittstelle mit den wenigsten Features einschränkst.

    Eine andere Variante ist es MySQLi zu erweitern. Stichwort Vererbung.
    Vererbung macht auf jeden Fall mehr Sinn als die Klasse direkt zu nutzen, damit du deine Methoden u.U. anders nennen kannst, neue Features hinzufügen kannst, die Verbindungsparameter per Default ändern kannst, etc.
    Auch kannst du die Schnittstelle einfach austauschen. Was du gerade feststellst, weil du von den mysql Funktionen auf die mysqli Klasse wechselst.

    Im kostenlosen Online Buch findest du weitere Informationen wie du korrekt von MySQLI erbst: professionelle-softwareentwick…mming-php.mysqli.oop.html
    Konkret fehlt bei dir das "extends".

    Zu deiner zweiten Frage erstelle bitte ein extra Thema mit etwas mehr Informationen ;)
  • Vielen Dank erstmal für die Antwort!

    Wenn die DB Klasse eine Instanz von MySQLi verwendet, dann ist es doch so gemeint das ich eine Hauptklasse habe und in der mehrere Objekte mit der jeweiligen Datenbank Typ erstelle? Die Funktionen von der DB Klasse greifen dann auf die Objekte hinzu? Wär das so richtig?
    Weil wenn das so ist, dann habe ich das jetzt so gemacht und mich damit wirklich übelst aufgeregt :S

    Das mit der Vererbung ist mir auch in den Sinn gekommen. Nur wusste ich nicht ganz ob das was wird falls da etwas von meiner Klasse überschrieben wird, aber wenn man die ganzen Methoden anders benannt sollte es ja gehen!
    Ich guck mir den Link mal an und denke ich bevorzuge das auch mit der Vererbung. Danke!
    Vererbung hatten wir in der Schule in JAVA und in PHP ist es ja gar nicht so sehr anders!
  • du kannst deine Lösung dann ja nochmal posten, dann geben wir dir nochmal Feedback.
    Ein weiteres Design Pattern, dass du auf deine DB anwenden solltest ist das Singleton.

    Das sorgt dafür, dass du das construct - also in deinem Fall der Verbindungsaufbau - nur einmalig ausführst.
    Ich benutze übrigens immer das PDO - eine Singleton Klasse findest du in unserem Wiki: [wiki]Einführung in PDO[/wiki]
  • Bis jetzt sieht es so bei mir aus:

    Quellcode

    1. <?php
    2. /**
    3. * company - vEcho
    4. * website - www.vecho.de
    5. * copyright - (c) 2009-2010
    6. * file path/name - ./database.php
    7. */
    8. if(!(defined('FUNCTIONS_DB_INCLUDED'))) {
    9. exit;
    10. }
    11. class db
    12. {
    13. private $db_host = "localhost";
    14. private $db_username = "root";
    15. private $db_password = "";
    16. private $db_database = "datenbank";
    17. private $result = NULL;
    18. private $mysqli;
    19. public function error($error, $errno)
    20. {
    21. global $language, $smarty;
    22. $smarty->assign('error', $error);
    23. $smarty->assign('errno', $errno);
    24. $smarty->display('error.tpl');
    25. die();
    26. }
    27. public function __construct()
    28. {
    29. $this->mysqli = new mysqli($this->db_host, $this->db_username, $this->db_password, $this->db_database);
    30. if(mysqli_connect_errno() != 0)
    31. {
    32. $this->error(mysqli_connect_error());
    33. }
    34. }
    35. public function select_db()
    36. {
    37. $this->mysqli->select_db($this->db_host, $this->db_database) OR $this->error($this->mysqli->error, $this->mysqli->errno);
    38. }
    39. public function query($query)
    40. {
    41. $this->result = $this->mysqli->query($query) OR $this->error($this->mysqli->error, $this->mysqli->errno);
    42. }
    43. public function fetch_array()
    44. {
    45. return $this->result->fetch_array(MYSQLI_ASSOC);
    46. }
    47. public function affected_rows()
    48. {
    49. return $this->mysqli->affected_rows;
    50. }
    51. public function getData($select)
    52. {
    53. $this->result = $this->mysqli->query($select) OR $this->error($this->mysqli->error, $this->mysqli->errno);
    54. return $this->result->fetch_array(MYSQLI_BOTH);
    55. }
    56. public function addData($query)
    57. {
    58. $this->result = $this->mysqli->query($query) OR $this->error($this->mysqli->error, $this->mysqli->errno);
    59. return $this->result;
    60. }
    61. public function real_escape_string($val)
    62. {
    63. return $this->mysqli->real_escape_string($val);
    64. }
    65. }
    66. ?>
    Alles anzeigen


    Das mit Singleton muss ich mir noch mal durchlesen, so auf den ersten Blick ersetzt eine statische Methode den Konstruktor und gibt das Objekt zurück - kann das sein oo"?

    Das man evtl. PDO benutzen solte habe ich auch öfters gelesen, ich denke aber das wird ziemlich kompliziert und ich müsste mich dann auch erstmal darein arbeiten =/.
    Nebenbei lerne ich ja beim erstellen der eigenen Datenbank Klasse :P
  • Hi,

    abgesehen vom Lernfaktor ist diese Umsetzung nicht sehr sinnvoll, da du einfach nur alle Funktionen mapst. Den Aufwand kannste dir sparen, wenn du einfach die vorhandene Klasse benutzt.

    Quellcode

    1. public function real_escape_string($val) {
    2. return $this->mysqli->real_escape_string($val);
    3. }



    Ich würde Smarty auch aus der Klasse verbannen, denn die Datenbankklasse hat nichts mit der Verarbeitung der Ausgabe zu tun.
    Du hast auch keine Möglichkeit auf Fehler anders zu reagieren, wenn du diese z.B in eine Log Datei schreiben möchtest.
  • Wie kann ich den korrekt abfragen ob die Anweisung erfolgreich abgelaufen ist oder nicht?

    Quellcode

    1. public function getData($select)
    2. {
    3. self::$result = self::$db->query($select);
    4. if(!self::$result)
    5. {
    6. throw new Exception($language['DB_GETDATA_ERROR']);
    7. }
    8. else
    9. {
    10. return self::$result->fetch_array(MYSQLI_BOTH);
    11. }
    12. }
    Alles anzeigen


    Würde das so stimmen? Ich glaub durch das if(!self::$result) fragt der doch nur ob dieser Wert nicht der am Anfang zugewiesene Wert (NULL) ist?
    Das bedeutet sobald ich über eine andere Funktion self::$result ändere und meine Query nicht funktioniert hat würde er dennoch in den else-Bereich kommen.

    Würde das sonst gehen?

    Quellcode

    1. public function getData($select)
    2. {
    3. if(!self::$result = self::$db->query($select))
    4. {
    5. throw new Exception($language['DB_GETDATA_ERROR']);
    6. }
    7. else
    8. {
    9. return self::$result->fetch_array(MYSQLI_BOTH);
    10. }
    11. }
    Alles anzeigen
  • sorry, gerade auf dem Sprung. Zu welcher Klasse gehört getData?

    Also hier man ein Beispiel unter Benutzung der Klasse von professionelle-softwareentwick…mming-php.mysqli.oop.html

    Quellcode

    1. public function getData($select) {
    2. try {
    3. return self::$db->query($select)
    4. } catch(MySQLi_QueryException $e) {
    5. return null; // fehler in der abfrage
    6. }
    7. }
  • getData gehört zu meiner Datenbank Klasse.

    Danke erstmal, ich blick jetzt langsam gar nicht mehr durch - oh man =/.

    Vielleicht sollte ich erstmal wirklich das mit der Datenbank Klasse hinkriegen und dann weiter machen, irgendwie funktioniert jetzt gar nichts mehr ^^".

    EDIT: Ich hab jetzt nochmal von vorne angefangen, mich verwirrt immer noch self:: und $this. Ich weis das $this zu einem Objekt gehört und mit self:: kann ich eine Klasse ansteuern ohne das Objekt zu erstellen aber z.B. bei dieser Seite die du gepostet hast wird $this->error verwendet. Weswegen wird da nicht self::error verwendet?

    Ich denk sicher mal das es langsam nervt das ich hier so oft mein Quellcode poste aber ich hab die Klasse schon jetzt 3 mal umprogrammiert und mich nervt es irgendwie langsam das ich es immer falsch habe :(

    Naja, wollte wissen ob das so stimmt?

    Quellcode

    1. //.. Exception Klassen
    2. class myDB extends mysqli
    3. {
    4. public $foo = '';
    5. private $result = NULL;
    6. private static $myDB = NULL;
    7. public static function getInstance()
    8. {
    9. if(null === self::$myDB)
    10. {
    11. self::$myDB = new self();
    12. }
    13. return self::$myDB;
    14. }
    15. private function __construct()
    16. {
    17. parent::__construct(CONFIGURATION::DB_HOST, CONFIGURATION::DB_USER, CONFIGURATION::DB_PASSWORD, CONFIGURATION::DB_DATABASE, CONFIGURATION::DB_PORT);
    18. }
    19. public function select_database($database)
    20. {
    21. self::$myDB->select_db($database);
    22. if(self::$myDB->error)
    23. {
    24. throw new MySQLi_Exception(self::$myDB->error, self::$myDB->errno);
    25. }
    26. }
    27. public function newQuery($query)
    28. {
    29. self::$result = self::$myDB->query($query);
    30. if(self::$myDB->error)
    31. {
    32. throw new MySQLi_QueryException(self::$myDB->error, self::$myDB->errno);
    33. }
    34. }
    35. public function fetchArray($query)
    36. {
    37. return self::$result->fetch_array(MYSQLI_ASSOC);
    38. }
    39. }
    40. $myDB = myDB::getInstance();
    41. $myDB->foo = 'Hello<br />';
    42. echo $myDB->foo;
    43. try
    44. {
    45. $myDB->select_database('vegb');
    46. }
    47. catch(MySQLi_Exception $e)
    48. {
    49. echo "Ging nicht<br />";
    50. echo $e;
    51. }
    Alles anzeigen


    Wenn ich eine Datenbank Abfrage mache wie oben muss ich dann jedes mal so ein try-catch Ding machen um die Exception abzufangen =/?

    Danke erstmal! :S

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Illidan ()

  • Der Zugriff mit self::$myDB ist falsch - auch wenn er funktionert.
    Diese Variable verwendest du einzig und allein im Konstruktor.

    Bei nicht statischen Methoden bist du ja schon im Objekt drinne. Dort verwendest du eifnach "$this" statt "self::$result".
    Und bei statischen Methoden (im Beispiel brauchst du keine) verwendest du einfach self::getInstance() statt self::$myDB.

    Brauchst du überhaupt eine Funktion für select_database? Denn eigentlich wird die doch schon im construct gesetzt.
    Ich habe dir eine FetchArray Methode mal leicht umgeschrieben - ist diese so wie gewollt?

    Zu deiner Frage ob du nun um jedes Query ein try/catch machen sollst.
    Nein, du musst nicht jede Exception explizit fangen - zumal doch eigentlich nicht mit einem Fehler zu rechnen ist.
    Wenn das Query fehlschlägt bricht dein Programm halt ab.

    Ich habe um mein ganzes Projekt ein großes try/catch

    index.php

    Quellcode

    1. try {
    2. // hier wird die komplette Seite generiert
    3. FrontController::dispatch();
    4. } catch(Exception $e) {
    5. }


    hier nochmal die MySQLI Datenbank

    Quellcode

    1. class myDB_Exception extends Exception {
    2. }
    3. class myDB_ConnectionException extends MySQLi_Exception {
    4. }
    5. class myDB_QueryException extends MySQLi_Exception {
    6. }
    7. class myDB extends MySQLi {
    8. private static $myDB = NULL;
    9. private function __construct() {
    10. parent::__construct(CONFIGURATION::DB_HOST, CONFIGURATION::DB_USER, CONFIGURATION::DB_PASSWORD, CONFIGURATION::DB_DATABASE, CONFIGURATION::DB_PORT);
    11. if (mysqli_connect_error()) {
    12. throw new myDB_ConnectionException(mysqli_connect_error(), mysqli_connect_errno());
    13. }
    14. }
    15. public static function getInstance() {
    16. if(null === self::$myDB) {
    17. self::$myDB = new self();
    18. }
    19. return self::$myDB;
    20. }
    21. public function query($query) {
    22. $result = parent::query($query);
    23. if ($this->error) {
    24. throw new myDB_QueryException($this->error, $this->errno);
    25. }
    26. }
    27. function fetchArray($query) {
    28. return array_pop($this->query($query)->fetch_row());
    29. }
    30. }
    Alles anzeigen
  • Yeah, vielen vielen Dank! Hat mir jetzt auf jeden Fall weiter geholfen!

    Meine Datenbank Klasse funktioniert jetzt soweit und du hast Recht - select_database brauche ich nicht.
    Deine fetchArray Methode gibt nicht ganz das zurück was ich haben wollte. Das sollte alle Werte als array zurückgeben so das ich es mit ner While Schleife anzeigen könnte.
    Aber array_pop bringt mir was bei getData wo nur ein Wert zurück gegeben wird ;).

    Mein Konstruktor hat jetzt keine Parameter. Die werden ja sowieso nicht verwendet, deswegen braucht der doch eigentlich auch keine oo?

    Und ich kann ruhig das try/catch Gerüst auf jeder meiner Hauptseiten (also index.php, entry.php) verwenden?
  • Das try/catch kannst du ruhig verwenden.
    Wie gesagt: Wenn du langfristig Model View Controller durchziehst, hast du am Ende sowieso nur noch eine index.php die auf entry.php zugreift.

    Ja, die Konstruktor Parameter in meinem Beispiel sind falsch. Ich habe das gerade korrigiert, falls sich andere den Code kopieren.
    Ich sehe du hast es begriffen ;)