Navigation
 Startseite
 Fachbücher
 Anzeigenmarkt
 Forum
 Webmaster News
 Script Newsletter
 Push Meldungen
 Kontakt
 Script Installation
 Php
 Php Tutorials
 Lernpfade
 Webhoster Vergleich
 Impressum

Community-Bereich
 kostenlos Registrieren
 Anmelden
 Benutzerliste

Script Datenbank
 Script Archiv
 Script Top 20
 Screenshots
 Testberichte

Suche
 

Unsere Php Scripts
 Counter Script
 Umfrage Script
 Bilder Upload Script
 Terminverwaltung
 Simple PHP Forum
 RSS Grabber

Tools und Generatoren
 .htpasswd Generator
 md5 Generator
 base64 Generator
 Markdown to HTML
 Colorpicker
 Unix timestamp Tool
 Unit Test Generator
 TLD Liste
 Webkatalog‑Verzeichnis

Artfiles.de
Bietet Serviceorientierte Internetdienstleistungen...
https://www.Artfiles.de
Webspace-Mieten.d...
Webhosting mit Plesk aus Erfurt: Vier Webspace-Pak...
https://www.Webspace-Mieten.de
 
 
 

PHP mysqli_fetch_assoc() Function: Zeilen als Array lesen

Sie befinden sich: Home > Php Tutorial > PHP mysqli_fetch_assoc() Fu...

PHP mysqli_fetch_assoc() Function: Zeilen als Array lesen
Veröffentlicht am:
24.10.2026
Hits / Besucher:
2
Sprache:
  Deutsch
Tutorial Art:
eigenes
Eingetragen von:
Merkliste:
 
Beschreibung

Eine Kundenliste soll aus der Datenbank als HTML-Tabelle erscheinen, und zwischen Abfrage und Ausgabe steht in fast jedem Beispiel dieselbe Zeile: while ($row = mysqli_fetch_assoc($result)). Wie man die Abfrage selbst mit Platzhaltern absichert, zeigt das Tutorial zu mysqli Prepared Statements. Danach stellt sich die Frage, in welcher Form PHP mysqli_fetch_assoc() die Zeilen aus dem Ergebnis holt, mit welchen Datentypen und an welchen Stellen die Funktion still etwas anderes liefert als erwartet.

Illustration zum Tutorial: PHP mysqli_fetch_assoc() Function: Zeilen als Array lesen

Gemessen wurde mit PHP 8.4 gegen MySQL 8.0. Windows und Linux lieferten bis auf die Laufzeiten dieselben Arrays.

Was PHP mysqli_fetch_assoc() liefert

Eine Abfrage mit mysqli_query() liefert ein Objekt vom Typ mysqli_result, die Ergebnismenge. PHP mysqli_fetch_assoc() holt daraus genau eine Zeile und gibt sie als assoziatives Array zurück. Die Schlüssel sind die Spaltennamen, so wie sie in der Abfrage stehen. Die Werte kommen als String an, eine leere Datenbankspalte als null:

<?php

$db = new mysqli(
'localhost', 'benutzer', 'passwort', 'shop'
);
$db->set_charset('utf8mb4');

$result = $db->query(
'SELECT id, name, umsatz, notiz FROM kunde'
);
var_dump(mysqli_fetch_assoc($result));
/* array(4) {
["id"]=> string(1) "1"
["name"]=> string(5) "Meyer"
["umsatz"]=> string(7) "1234.50"
["notiz"]=> NULL
} */

Jeder weitere Aufruf liefert die nächste Zeile. Nach der letzten kommt null, und zwar bei jedem weiteren Aufruf wieder. Findet die Abfrage gar nichts, liefert schon der erste Aufruf null.

Die Signatur im Original: prozedural und objektorientiert

Die Funktion gibt es in zwei Schreibweisen, im Test lieferten beide identische Arrays:

mysqli_fetch_assoc(

mysqli_result $result
): array|null|false

public mysqli_result::fetch_assoc():
array|null|false

/* Fetches one row of data from the result set
and returns it as an associative array. Each
subsequent call to this function will return
the next row within the result set, or null
if there are no more rows.

result - a mysqli_result object returned by
mysqli_query(), mysqli_store_result(),
mysqli_use_result() or
mysqli_stmt_get_result()
returns - an associative array representing
the fetched row, where each key in
the array represents the name of one
of the result set's columns, null if
there are no more rows in the result
set, or false on failure.

If two or more columns of the result have the
same name, the last column will take
precedence and overwrite any previous data.
To access multiple columns with the same name,
mysqli_fetch_row() may be used to fetch the
numerically indexed array, or aliases may be
used in the SQL query select list to give
columns different names. */

Der Rückgabetyp von PHP mysqli_fetch_assoc() hat drei Teile: ein Array für jede Zeile, null für das Ende der Ergebnismenge und false für einen Fehler beim Abruf selbst, der im Alltag kaum vorkommt. Der Satz über gleichnamige Spalten klingt beiläufig, führt aber bei jedem JOIN zu verschwundenen Werten. Dazu weiter unten mehr.

Die while-Schleife mit PHP mysqli_fetch_assoc()

Die Zeile, die Einsteiger am meisten verwirrt, sieht aus wie ein Vergleich mit einem fehlenden Gleichheitszeichen. Sie ist eine Zuweisung. In jedem Durchlauf holt PHP mysqli_fetch_assoc() die nächste Zeile und legt sie in $row ab, und die Schleife prüft, ob das Ergebnis dieser Zuweisung wahr ist:

<?php

$result = $db->query(
'SELECT id, name FROM kunde ORDER BY name'
);

echo '<table>';
while ($row = mysqli_fetch_assoc($result)) {
echo '<tr><td>', (int) $row['id'], '</td><td>',
htmlspecialchars($row['name']), '</td></tr>';
}
echo '</table>';

Ein Array mit mindestens einer Spalte gilt in PHP immer als wahr, auch wenn sein einziger Wert '0' ist. Im Test liefen Zeilen mit dem Wert '0' problemlos durch. Nach der letzten Zeile kommt null, das gilt als falsch, und die Schleife endet. Eine Endlosschleife ist also nicht zu befürchten. Objektorientiert lautet die Bedingung while ($row = $result->fetch_assoc()).

Auch foreach ($result as $row) funktioniert, die Zeilen sind dieselben assoziativen Arrays. Ein foreach beginnt bei einem gepufferten Ergebnis aber immer von vorn, während while am Ende stehen bleibt. Warum eine zweite while-Schleife leer bleibt und wie man den Zeiger zurücksetzt, erklärt das Tutorial zu mysqli_data_seek().

fetch_assoc, fetch_array und fetch_row im Vergleich

Neben PHP mysqli_fetch_assoc() gibt es fünf Geschwister, die dieselbe Ergebnismenge in anderer Form liefern. Die Tabelle zeigt, was beim Abruf von SELECT id, name, aktiv für den ersten Datensatz tatsächlich herauskam:

Abruf Ergebnis am Ende
fetch_assoc() ['id' => '1', 'name' => 'Meyer', 'aktiv' => '1'] null
fetch_row() [0 => '1', 1 => 'Meyer', 2 => '1'] null
fetch_array() beide Formen in einem Array, sechs Einträge für drei Spalten null
fetch_object() Objekt der Klasse stdClass mit den Eigenschaften id, name, aktiv null
fetch_column() nur der Wert der ersten Spalte, hier '1' false
fetch_all() alle Zeilen, ohne Angabe mit Nummern als Schlüssel leeres Array

Ohne zweiten Parameter sieht eine Zeile aus mysqli_fetch_array() so aus:

<?php

$result = $db->query(
'SELECT id, name, aktiv FROM kunde'
);
print_r(mysqli_fetch_array($result));
/* [0] => 1, [id] => 1,
[1] => Meyer, [name] => Meyer,
[2] => 1, [aktiv] => 1 */

Die doppelten Werte bei mysqli_fetch_array() sind kein Fehler in der Abfrage. Ohne zweiten Parameter gilt der Modus MYSQLI_BOTH, und jede Spalte steht einmal unter ihrer Nummer und einmal unter ihrem Namen im Array. Mit MYSQLI_ASSOC entspricht die Funktion genau fetch_assoc(), mit MYSQLI_NUM genau fetch_row(). Ein anderer Wert wirft einen ValueError. Wer von PDO kommt, findet in fetch_assoc() das Gegenstück zu fetch(PDO::FETCH_ASSOC) und in fetch_column(), verfügbar seit PHP 8.1, das zu fetchColumn().

Ob Namen, Positionen, alle Zeilen oder ein einzelner Wert gebraucht werden, entscheidet über die Abrufart:

flowchart TD
    A[mysqli_result] --> B{Was wird gebraucht?}
    B -->|Zeile mit Namen| C[fetch_assoc]
    B -->|Zeile nach Position| D[fetch_row]
    B -->|alle Zeilen| E[fetch_all mit ASSOC]
    B -->|ein einzelner Wert| F[fetch_column]
    C --> G{Ergebnis null?}
    D --> G
    G -->|nein| H[Zeile verarbeiten]
    H --> C
    G -->|ja| I[Ende der Ergebnismenge]

Bei fetch_column() kann die Schleife zu früh enden, bei PHP mysqli_fetch_assoc() nicht. Die Funktion liefert einen einzelnen Wert, und der kann '0' sein. Im Test endete eine while-Schleife deshalb sofort, weil der erste Wert '0' war. Am Ende der Ergebnismenge liefert fetch_column() false, nicht null, und genau darauf gehört die Prüfung:

<?php

$result = $db->query('SELECT menge FROM lager');

/* falsch: endet beim ersten Wert '0' */
while ($wert = $result->fetch_column()) {
echo $wert, "\n";
}

/* richtig: erst false bedeutet das Ende */
while (($wert = $result->fetch_column()) !== false) {
echo $wert ?? '(NULL)', "\n";
}

Alle Zeilen auf einmal mit mysqli_fetch_all()

Soll die Liste sortiert, gefiltert oder mehrfach ausgegeben werden, ist ein Array mit allen Zeilen praktischer als eine Schleife. Die Sammelschleife mit $alle[] = $row und PHP mysqli_fetch_assoc() funktioniert, kürzer ist mysqli_fetch_all(). Ohne Parameter fehlen dort allerdings die Spaltennamen:

<?php

$result = $db->query('SELECT id, name FROM kunde');
$alle = $result->fetch_all();
/* [[0 => '1', 1 => 'Meyer'], [0 => '2', ...]] */

$result = $db->query('SELECT id, name FROM kunde');
$alle = $result->fetch_all(MYSQLI_ASSOC);
/* [['id' => '1', 'name' => 'Meyer'], ...] */

$namen = array_column($alle, 'name', 'id');
/* [1 => 'Meyer', 2 => 'Schulz'] */

Ohne Parameter nutzt fetch_all() den Modus MYSQLI_NUM, die Spaltennamen fehlen also. Mit MYSQLI_ASSOC entsteht dieselbe Struktur wie aus der Sammelschleife, und array_column() macht daraus bei Bedarf eine Zuordnung von ID zu Name. Nach fetch_all() steht der Lesezeiger am Ende, ein folgendes fetch_assoc() liefert null.

JOIN: wenn zwei Spalten gleich heißen

Im Handbuch steht die Regel in einem unscheinbaren Absatz, in der Praxis löst sie die verwirrendsten Fehler aus. Haben zwei Spalten denselben Namen, gibt es im Array nur einen Schlüssel dafür. Für diesen Test hatte die Tabelle kunde nur die Spalten id und name, die Tabelle bestellung die Spalten id, kunde_id, name und betrag. Der Kunde hatte die ID 7, seine Bestellung die ID 101:

<?php

$result = $db->query(
'SELECT k.*, b.* FROM kunde k
JOIN bestellung b ON b.kunde_id = k.id'
);
var_export($result->fetch_assoc());
/* ['id' => '101', 'name' => 'Tastatur',
'kunde_id' => '7', 'betrag' => '49.90'] */

ID und Name des Kunden sind verschwunden, ohne Warnung. Die zuletzt genannte Spalte gewinnt. Mit SELECT b.*, k.* kehrte sich das Ergebnis um, dann standen '7' und 'Meyer' im Array, und ID und Artikelname der Bestellung fehlten. Das Tabellenkürzel k. gehört nicht zum Schlüssel. Bei dieser Abfrage mit sechs Spalten, von denen zwei Namen doppelt vorkommen, behielt fetch_row() alle sechs Werte, fetch_array() lieferte zehn Einträge: sechs Nummern, aber nur vier Namen. Die saubere Lösung sind Aliase, damit liefert PHP mysqli_fetch_assoc() vier eindeutige Schlüssel:

<?php

$result = $db->query(
'SELECT k.id AS kunde_id, k.name AS kunde,
b.id AS bestell_id, b.name AS artikel
FROM kunde k
JOIN bestellung b ON b.kunde_id = k.id'
);

Aus welcher Tabelle eine Spalte stammt, verraten die Metadaten von fetch_fields(). Im Test standen dort k.id, k.name, b.id und so weiter, obwohl das Array diese Unterscheidung nicht mehr kennt.

Strings statt Zahlen: die Typen im Array

Eine Shop-Schnittstelle gibt die Daten als JSON aus, und dort steht "id":"1" statt "id":1. Ein Vergleich wie $row['bestand'] === 0 greift nie. Beides hat dieselbe Ursache: Mit mysqli_query() liefert PHP mysqli_fetch_assoc() jeden Wert als String, auch Ganzzahlen, Gleitkommazahlen und Datumswerte. Eine Treiberoption ändert das, sie muss vor dem Verbindungsaufbau gesetzt werden:

<?php

$db = mysqli_init();
$db->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
$db->real_connect(
'localhost', 'benutzer', 'passwort', 'shop'
);

$result = $db->query(
'SELECT id, umsatz, rabatt, aktiv FROM kunde'
);
var_dump($result->fetch_assoc());
/* id int(1), umsatz string "1234.50",
rabatt float(0.1), aktiv int(1) */

Ganzzahlen und Gleitkommazahlen kamen danach als echte Typen an, aber nicht alles. DECIMAL blieb ein String, und das ist für Geldbeträge sogar gewollt, weil ein float Rundungsfehler mitbringt. TINYINT(1) wurde zu int(1), nicht zu bool. Datumswerte blieben Strings, ebenso der Höchstwert einer BIGINT UNSIGNED-Spalte, der nicht in eine PHP-Ganzzahl passt. Ohne jede Option lieferten vorbereitete Anweisungen mit get_result() bereits native Zahlen. Das liegt am binären Protokoll, wie es im Tutorial zu Prepared Statements zum Einsatz kommt.

NULL-Werte und Schlüssel wie COUNT(*)

Eine Spalte mit dem Datenbankwert NULL fehlt nicht im Array. Sie steht dort mit dem Wert null, und daran scheitert isset():

<?php

$result = $db->query(
'SELECT notiz FROM kunde WHERE id = 1'
);
$row = $result->fetch_assoc();

var_dump(isset($row['notiz']));
/* false, obwohl die Spalte da ist */
var_dump(array_key_exists('notiz', $row));
/* true */

echo $row['notiz'] ?? '(keine Notiz)';

Der Schlüssel ist immer der Text aus der Abfrage. Aus SELECT COUNT(*), MAX(umsatz) wurden im Test die Schlüssel 'COUNT(*)' und 'MAX(umsatz)', aus SELECT Name der Schlüssel 'Name' mit großem N. Wer sich beim Lesen nicht vertippen will, vergibt einen Alias: SELECT COUNT(*) AS anzahl ergibt $row['anzahl']. Für einen einzelnen Wert wie diesen ist fetch_column() ohnehin die kürzere Wahl.

Fehler rund um PHP mysqli_fetch_assoc()

Seit PHP 8.1 wirft mysqli bei einem Fehler in der Abfrage von sich aus eine Exception, und zwar dort, wo der Fehler entsteht:

<?php

try {
$result = $db->query(
'SELECT id, name FROM kunden'
);
} catch (mysqli_sql_exception $e) {
error_log($e->getMessage());
/* Table 'shop.kunden' doesn't exist */
exit('Abfrage fehlgeschlagen');
}

Im Test lauteten die Meldungen etwa Unknown column 'preis' in 'field list' mit dem Code 1054 oder You have an error in your SQL syntax mit 1064. Mehr zu den Nummern steht im Tutorial zu mysqli_errno(). In älterem Code steht dagegen oft mysqli_report(MYSQLI_REPORT_OFF). Dann liefert die fehlerhafte Abfrage nur false, und der Fehler erscheint eine Zeile später bei PHP mysqli_fetch_assoc(): prozedural als TypeError: mysqli_fetch_assoc(): Argument #1 ($result) must be of type mysqli_result, false given, objektorientiert als Call to a member function fetch_assoc() on false. Die Ursache steckt in beiden Fällen in der Zeile davor.

Zwei verwandte Meldungen haben andere Gründe. Ein INSERT liefert true statt eines Ergebnisses, ein Abruf darauf endet mit Call to a member function fetch_assoc() on true. Und nach dem Freigeben mit free() meldet jeder Abruf mysqli_result object is already closed. Wer alten Code mit mysql_fetch_assoc() ohne i übernimmt, bekommt unter PHP 8 Call to undefined function mysql_fetch_assoc(). Die mysql-Erweiterung ist seit PHP 7.0 entfernt. Sie lieferte am Ende false, die mysqli-Funktion dagegen null.

Beim Umstellen genügt das fehlende i nicht. PHP mysqli_fetch_assoc() erwartet ein Ergebnis aus mysqli_query(), und das verlangt die Verbindung als ersten Parameter. Aus mysql_query($sql) wird mysqli_query($db, $sql), die Schleife darunter bleibt bis auf das i gleich:

<?php

/* alt, seit PHP 7.0 nicht mehr vorhanden */
$res = mysql_query('SELECT id, name FROM kunde');
while ($row = mysql_fetch_assoc($res)) {
echo $row['name'], "\n";
}

/* neu */
$result = mysqli_query(
$db, 'SELECT id, name FROM kunde'
);
while ($row = mysqli_fetch_assoc($result)) {
echo $row['name'], "\n";
}

Tempo und Speicher der Abrufarten

Gemessen an 50.000 Zeilen mit sechs Spalten, jeweils der beste von drei Läufen. Die ersten vier Zeilen zeigen die Laufzeit der Schleife, die letzten drei den Speicher, den das Array aus fetch_all() belegt:

Abruf Windows Linux
fetch_assoc() in while 7,6 ms 6,2 ms
fetch_row() 6,9 ms 5,7 ms
fetch_array() mit beiden Formen 9,0 ms 8,3 ms
fetch_object() 10,7 ms 7,0 ms
fetch_all(), Array mit Nummern 18,7 MiB 18,7 MiB
fetch_all(MYSQLI_ASSOC) 26,4 MiB 26,4 MiB
fetch_all(MYSQLI_BOTH) 41,6 MiB 41,6 MiB

Bei der Laufzeit liegen die Abrufarten so dicht beieinander, dass die Wahl nach Lesbarkeit fallen darf. PHP mysqli_fetch_assoc() kostet gegenüber fetch_row() weniger als eine Millisekunde auf 50.000 Zeilen. Beim Speicher entscheidet dagegen, ob alles auf einmal geholt wird. Eine while-Schleife ließ den Speicher im Test nicht wachsen, während fetch_all() je nach Modus zwischen 18,7 und 41,6 MiB belegte. Die Ergebnismenge selbst hält zusätzlich Speicher, bis sie freigegeben wird. Wann sich das lohnt, zeigt das Tutorial zu mysqli_free_result(). Ungepuffert mit MYSQLI_USE_RESULT funktioniert PHP mysqli_fetch_assoc() genauso, die Zeilen kommen dann aber erst beim Abruf vom Server.

Fazit

Die Schleife mit PHP mysqli_fetch_assoc() endet zuverlässig, weil nach der letzten Zeile null kommt und jedes nicht leere Array als wahr gilt. Fallen stecken woanders. fetch_all() liefert ohne Parameter nur Nummern, bei einem JOIN überschreibt die letzte gleichnamige Spalte still die vorherige, und alle Werte kommen als String an, solange keine Treiberoption etwas anderes verlangt.

Aliase in der Abfrage lösen die häufigsten dieser Probleme auf einen Schlag: eindeutige Schlüssel beim JOIN, lesbare Namen statt 'COUNT(*)'. Meldet PHP mysqli_fetch_assoc() einen TypeError oder ein false, liegt der Fehler fast immer in der Abfrage eine Zeile weiter oben.

 

Tags:

 

 

Kommentare (0)

Noch keine Kommentare. Sei der Erste!

Melde dich an, um einen Kommentar zu schreiben.
Bücherregal mit drei Büchern: 'PHP 4 - Grundlagen und Profiwissen' von Hanser Verlag, 'Webdesign in a Nutshell' von O'Reilly Verlag, und 'Webgestaltung' von Galileo Computing.