tobi85: mysqli_result

Hallo,

ich möchte gerade von mysql zu mysqli umstellen.

Bei folgender Funktion habe ich ein problem, da es wohl mysqli_result nicht gibt. Wie kann ich denn die Daten einfach ausgeben lassen.

$q = "SELECT * FROM artikel WHERE id='$id' ";
$res = mysql_query($q);
$text = mysql_result($res,0,'text');

neu aber mit Fehler: Call to undefined function mysqli_result()

$q = "SELECT * FROM artikel WHERE id='$id' ";
$mysqli = new mysqli(dbserver,dbuser,dbpass,dbname);
$res = $mysqli->query($q);
$text = mysqli_result($res,0,'text');
  1. mysql_result() liefert Dir den Wert einer Spalte für alle Rows des Result-Set, wenn ich das richtig verstehe. Was es bei einem SELECT * macht, kann ich mir jetzt nicht recht vorstellen. Bekommst Du dann ein Array aus Arrays mit den Werten der Trefferzeilen?

    Jedenfalls solltest Du nicht das OO-API und das prozedurale API mischen. Das macht man nur zur Verwirrung der Russen.

    Wie wäre es hiermit:

    $res = $mysqli->query($q);
    $text = $res->fetch_all(MYSQLI_NUM);   // oder MYSQLI_ASSOC
    

    Dann bekommst du ein Array aus Arrays mit den Zeileninhalten. Wenn Du es Zeile für Zeile verarbeiten möchtest, dann gibt's auch $res->fetch_assoc.

    Ein Hinweis am Rande, vermutlich überflüssig, aber wer weiß...: Das $mysqli Objekt legst Du nur einmal zu Beginn des PHP Scripts an, also da, wo Du bisher den mysql_connect gemacht hast, und speicherst es global, danach verwendest Du es für jede Query (es sei denn, du weißt was du tust und hast gute Gründe, mehrere Connections parallel zu halten).

    Rolf

    1. Hallo und danke, aber wie speicher ich das mysqli-Objekt Global? Das war schon mal meine Frage in einem anderen Post...

      $mysqli = new mysqli(dbserver,dbuser,dbpass,dbname);

      1. function initDatabase()
        {
           global $mysqli;
           $mysqli = new mysqli(dbserver,dbuser,dbpass,dbname);
        }
        
        function getData()
        {
           global $mysqli;
           $mysqli->query(...);
        }
        
        1.    global $mysqli;
          

          Ich weiß nicht ...

          ich finde (wennschon, dennschon):

          $GLOBALS['db_con'] = new mysqli(dbserver,dbuser,dbpass,dbname);
          

          und

          $res = $GLOBALS['db_con']->query(...)
          

          irgendwie deutlicher.

      2. Was ich eben nicht mehr hinein editieren konnte: Wenn Du nur eine Spalte aus der Tabelle brauchst, dann solltest Du das im SELECT Statement auch zum Ausdruck bringen - gerade dann, wenn die Tabelle viele Spalten hat. Sonst transferierst Du jede Menge Wegwerf-Daten vom Server ins PHP.

      3. Hallo,

        aber wie speicher ich das mysqli-Objekt Global?

        gar nicht. Gewöhn dir globale Variablen von Anfang an ab. Nutze stattdessen Dependency Injection. Es beschreibt, dass die Klassen ihre Abhängigkeiten übergeben bekommen (injected), anstatt dass diese danach fragen müssen (etwa in globalen Variablen). Dies sorgt dafür, dass deine Klassen saubere Boundaries haben, die dir später das Testen stark erleichern werden.

        Frage sich nur, von welcher Klasse ich da rede: ArtikelRepository. Wie du anhand des Namens erkennen kannst, empfehle ich dir, hier direkt das Repository-Pattern zu verwenden. Geh zunächst mal einen Schritt zurück vom Code und überlege dir, was du da hast.

        Du hast einen Datenspeicher (in diesem Fall eine relationale Datenbank, mysql), und darin sind Business-Objekte von dir gespeichert (Artikel). Das Repository beschreibt eine Möglichkeit, auf einen Datenspeicher zuzugreifen. In Ermangelung von UML-Künsten meinerseits ohne Zeichnung: das Repository hat eine Methode, die als Parameter die id bekommt und dein Artikel-Objekt zurückgibt. Das Repository braucht dabei intern die mysql-Verbindung.

        Also probier mal zum Start sowas hier:

        $mysqli = new mysqli(/* ... */);
        $repo = new ArtikelRepository($mysqli);
        $artikel = $repo->findById(1);
        
        class ArtikelRepository {
           private $mysqli;
           public function __construct($mysqli) {
              $this->mysqli = $mysqli;
           }
        
           public function findById($id) {
              $res = $this->mysqli->query(/*...*/);
              $obj = $res->fetchAssoc(); // kenne die genaue Syntax nicht mehr
              return new Artikel($obj->name, $obj->preis /* usw *);
           }
        }
        
        class Artikel {
           private $name;
           private $preis;
        
           public function __construct($name, $preis) {
              $this->name = $name;
              $this->preis = $preis;
           }
        }
        

        Wie gesagt: wenn dir die Klasse Artikel nicht brauchst (im Sinne von Domain-Driven Design willst du dort deine Business-Logik ablegen!), kannst du in findById auch direkt $res->fetchAssoc() zurückgeben, dann hast du in $artikel ein assoziatives Array mit deinen Tabelleninhalten.

        Viele Grüße, Matti

    2. Also bei fetch_all bekomme ich auch eine Fehlermeldung.

      Call to undefined method mysqli_result::fetch_all()

      1. Sollte nicht sein. Zeig mal den Code im Zusammenhang.

        1. 	global $mysqli;
          	$q = "SELECT * FROM artikel LIMIT 10";
          	$res = $mysqli->query($q);
          	$text = $res->fetch_all(MYSQLI_NUM);
          	print_r($text);
          
  2. Hallo,

    ich möchte gerade von mysql zu mysqli umstellen.

    Bei folgender Funktion habe ich ein problem, da es wohl mysqli_result nicht gibt. Wie kann ich denn die Daten einfach ausgeben lassen.

    $q = "SELECT * FROM `artikel` WHERE id='$id' ";
    $res = mysql_query($q);
    $text = mysql_result($res,0,'text');
    

    neu aber mit Fehler:

    Versuchen wird das mal richtig:

    Deine Tabelle habe ein Feld "id" und eines "name". Dieses solltest Du auch angeben, denn sonst

    • ist das Erfebnis "Zufall"
    • die Ergebnismenge größer als nötig.
    $q = 'SELECT `name` FROM artikel WHERE `id`=' . intval($id); # Nur sicher ist sicher!
    if ($res = mysql_query($q) {
       if  mysqli_num_rows($res) == 0) {
           // Hier ist was zu tun, wenn die Abfrage ein leeres (kein) Ergebnis liefert?
       } else if ( mysqli_num_rows($res) == 1 ) {
           $row = mysqli_fetch_assoc($res);
           $text = $row['name']; ## Dein Ergebnis
       } else {
          // Hier ist was zu tun, wenn die Abfrage unvermutet mehrere Ergebnisse liefert?
       }
    } else {
        // Hier ist was zu tun, wenn MySQL einen Fehler meldet?
        // siehe: http://php.net/manual/de/mysqli.error.php
    }
    

    Daneben fällt mir noch auf. dass die Abfrage "eher ungewöhlich" ist. Meist fallen diese komplexer aus. Frage deshalb: Hast Du mehrere Abfragen und verwendest Du womöglich das Ergebnis dieser Abfrage als Bestandteil weiterer Abfragen, vor allem in der where-Klausel?

    1. Zufall ist das Ergebnis nicht, der Server liefert die Columns so aus wie in der Table definiert; und davon bekommt er die erste. Trotzdem ist's natürlich besser, nichts Unnötiges zu bestellen.

      Noch eine Anmerkung zu global - da hatte es ja schon im anderen Thread von tobi85 Diskussion zu gegeben: Ja, es gibt 'böse' Konstrukte, und global ist eins davon. Schöner wäre auf jeden Fall ein Repository-Objekt, das die Connection als private Eigenschaft enthält, und die Datenbankzugriffe als Methoden anbietet. Dieses Objekt legt man dann einmal in der Script-Initialisierung an und reicht es überall hin durch. Ob man die Refaktorierung so weit treibt, hängt von der verfügbaren Arbeitszeit ab. Und vom PHP Knowhow. Wenn man "nur" von mysql auf mysqli umstellen will, ist ein globales Connection-Objekt meiner Meinung nach eine lässliche Sünde. Einen gewissen Runtime-Kontext hat man immer.

      Rolf

      1. Zufall ist das Ergebnis nicht, der Server liefert die Columns so aus wie in der Table definiert; und davon bekommt er die erste.

        Ja. Genau das nennt man "Zufall", weil die Tabelle ja mal - durch das Einfügen einer Spalte - neu definiert werden könnte. Wenn dann und deswegen wieder der Programmierer tätig werden muss, dann begann eine Abfrage mit "SELECT *"

        Schlimmer noch: Es könnten - sogar eine Zeitlang unentdeckt - Werte aus der falschen Spalte geliefert werden, was im Einzelfall höchst unwillkommen sein kann.

    2. $res = mysql_query() kann natürlich NICHT gehen. Das muss schon mysqli_query() sein ...

      Eine Klammer fehlte auch noch.

      //$con = mysqli_connect("my_host", "my_user", "my_password", "my_database");
      
      $q = 'SELECT `name` FROM artikel WHERE `id`=' . intval($id); # Nur sicher ist sicher!
      if ( $res = mysqli_query($con, $q) ) {
         if  ( mysqli_num_rows($res) == 0 ) {
             // Hier ist was zu tun, wenn die Abfrage ein leeres (kein) Ergebnis liefert?
         } else if ( mysqli_num_rows($res) == 1 ) {
             $row = mysqli_fetch_assoc($res);
             $text = $row['name']; ## Dein Ergebnis
         } else {
            // Hier ist was zu tun, wenn die Abfrage unvermutet mehrere Ergebnisse liefert?
         }
      } else {
          // Hier ist was zu tun, wenn MySQL einen Fehler meldet?
          // siehe: http://php.net/manual/de/mysqli.error.php
      }