Das MySQL-Integer-Feld wird in PHP als Zeichenfolge zurückgegeben

127

Ich habe ein Tabellenfeld in einer MySQL-Datenbank:

userid INT(11)

Also rufe ich es mit dieser Abfrage auf meine Seite:

"SELECT userid FROM DB WHERE name='john'"

Dann mache ich für die Behandlung des Ergebnisses:

$row=$result->fetch_assoc();

$id=$row['userid'];

Wenn ich das tue:

echo gettype($id);

Ich bekomme eine Schnur. Sollte das nicht eine ganze Zahl sein?

luca
quelle
2
Die MySQL-Abfrage gibt Zeilenwerte an, keine Zeilentypen oder andere zugehörige Informationen. Nur die Rohdaten, die in jeder Tabellenzelle enthalten sind. Sie müssen dies in PHP
Dan Hanly
Wenn Sie die Spaltentypen
RichardTheKiwi
Für die Leser beinhaltet die ausgewählte Antwort das Durchlaufen der Ergebnisse. Aber es gibt eine bessere Lösung. stackoverflow.com/a/1197424/5079380
Amr ElAdawy
1
@DanHanly - Technisch gesehen gibt die MYSQL-Abfrage (in PHP) eine Zeichenfolgendarstellung des Zellenwerts zurück. Der tatsächliche Zellenwert, der in der Datenbank für eine 32-Bit-Ganzzahl gespeichert ist, ist ... eine 32-Bit-Ganzzahl, keine Ziffernfolge .
ToolmakerSteve
Für mich, als ich verwendet habe, habe $conn->query("your query")ich die Ganzzahlfelder als Zeichenfolge erhalten, aber als ich verwendet habe, habe $conn->prepare("your query")ich die Parameter so erhalten, wie sie in der Datenbank waren
Bar Tzadok

Antworten:

129

Wenn Sie mit PHP Daten aus einer MySQL-Datenbank auswählen, wird der Datentyp immer in eine Zeichenfolge konvertiert. Sie können es mit dem folgenden Code wieder in eine Ganzzahl konvertieren:

$id = (int) $row['userid'];

Oder mit der Funktion intval():

$id = intval($row['userid']);
Michiel Pater
quelle
79
Nachdem ich aus einem Postgres-Hintergrund zu MySQL gekommen bin, muss ich sagen, dass dies ein großer Schmerz im Arsch ist. Wenn Sie eine Zeile in Postgres abgerufen haben, müssen Sie sicherstellen, dass die Elemente im Zeilenarray die entsprechenden Datentypen haben. Jetzt muss ich Code schreiben, um jedes Element manuell in den erwarteten Datentyp umzuwandeln.
GordonM
25
Ich habe gerade einige Tests unter Windows mit Laravel und MySQL auf demselben Schema und Datenbankserver durchgeführt. Unter Windows wird der Primärschlüssel als Ganzzahl zurückgegeben und unter Linux als Zeichenfolge.
AturSams
Ok, es ist eine gute Idee, aber was ist, wenn Sie Tausende von Feldern abrufen müssen? Dieser Vorgang dauert eine Weile. In meinem Beispiel rufe ich die Anzahl der Ansichten für jeden Beitrag ab, drucke dann meinen gesamten Beitrag in einer Tabelle aus und erlaube dem Benutzer, nach Ansicht auf- und absteigend zu sortieren, aber nach "1" bis "9" "oder" 9 "bis" 1 ", so dass Sie an erster Stelle" 9999 "," 91 "," 8111 "," 7 "usw. haben
könnten
@zehelvion hast du jemals eine Lösung dafür gefunden?
Felipe Francisco
2
Jedes zurückgegebene Feld ist eine Zeichenfolge ODER NULL .
Liam
73

Verwenden Sie den mysqlnd (nativen Treiber) für PHP.

Wenn Sie auf Ubuntu sind:

sudo apt-get install php5-mysqlnd
sudo service apache2 restart

Wenn Sie auf Centos sind:

sudo yum install php-mysqlnd
sudo service httpd restart

Der native Treiber gibt Integer-Typen entsprechend zurück.

Bearbeiten:

Wie @Jeroen hervorgehoben hat, funktioniert diese Methode nur für PDO.
Wie @LarsMoelleken hervorgehoben hat, funktioniert diese Methode mit mysqli, wenn Sie auch die Option MYSQLI_OPT_INT_AND_FLOAT_NATIVE auf true setzen.

Beispiel:

$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);
advait
quelle
Ich sehe keinen Beweis für dieses Stament. Bei Ausführung mit mysqlnd und mysqli werden eindeutig Zeichenfolgenwerte zurückgegeben.
Jeroen
@ Jeroen bist du sicher? Es gibt viele Dokumentationen. stackoverflow.com/questions/1197005/…
advait
Ja. Schauen Sie sich auch die Kommentare unten an. Hast du das selbst getestet? Wie es jetzt aussieht, gibt sogar mysqlnd nur dann geeignete Typen zurück, wenn Sie vorbereitete Anweisungen verwenden. Beispiel: gibt $link = mysqli_connect('localhost', 'root', ''); mysqli_set_charset($link,'utf8'); $result = mysqli_query($link,'SELECT CAST(\'3.51\' AS DECIMAL(3,2))'); $row = mysqli_fetch_assoc($result); var_dump($row);zurück: array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
Jeroen
1
Nicht so wie ich es verstehe, sollte es gleichermaßen mit PDO und Mysqli funktionieren. Selbst auf dem Link, den Sie oben im Kommentar posten, wird klargestellt, dass er NUR MIT VORBEREITETEN ERKLÄRUNGEN und nicht mit Inline-Abfragen gemäß OP funktioniert. Zitat von dieser Seite: Dies ist jedoch nur PHP 5.3 (vorausgesetzt, Ihre Version von PHP 5.3 ist mit mysqlnd (und nicht mit altem libmysql) kompiliert) und scheint nur für vorbereitete Anweisungen der Fall zu sein :-(
Jeroen
7
Sie können auch "MYSQLI_OPT_INT_AND_FLOAT_NATIVE" für mysqli
Lars Moelleken
20

Einfachste Lösung, die ich gefunden habe:

Sie können json_encode zwingen, tatsächliche Zahlen für Werte zu verwenden, die wie Zahlen aussehen:

json_encode($data, JSON_NUMERIC_CHECK) 

(seit PHP 5.3.3).

Oder Sie können Ihre ID einfach in einen Int umwandeln.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];
Larney
quelle
1
Wenn möglich, verwenden Sie einen json_encodeString, um int zu gießen, wie ein Mikroskop, um Nägel zu ersticken.
LibertyPaul
7
Dadurch werden alle Postleitzahlen und Telefonnummern zerstört. Gute Möglichkeit, Bugs in Ihre App einzuführen. Die Lösung MUSS den Datentyp der MySQL-Spalte berücksichtigen und nicht versuchen, den Wert zu erraten.
Max Cuttins
1
Max Cuttins, dein Punkt ist gültig. Wenn Sie jedoch alle von der Datenbank erwarteten Datentypen berücksichtigen können, ist dies der perfekte Weg.
Ifedi Okonkwo
1
Dies wird Ihnen weh tun, wenn Sie irgendwann IDs wie '06' haben. Dieses Flag konvertiert es in 6. Was falsch ist, weil diese IDs immer hinter Nullen stehen sollten.
Hassan Dad Khan
Dies ist eine großartige Lösung für Werte UNIX_TIMESTAMP(), die beispielsweise von erstellt wurden.
David
18

Meine Lösung besteht darin, das Abfrageergebnis zu übergeben $rsund ein Assoc-Array der gegossenen Daten als Rückgabe zu erhalten:

function cast_query_results($rs) {
    $fields = mysqli_fetch_fields($rs);
    $data = array();
    $types = array();
    foreach($fields as $field) {
        switch($field->type) {
            case 3:
                $types[$field->name] = 'int';
                break;
            case 4:
                $types[$field->name] = 'float';
                break;
            default:
                $types[$field->name] = 'string';
                break;
        }
    }
    while($row=mysqli_fetch_assoc($rs)) array_push($data,$row);
    for($i=0;$i<count($data);$i++) {
        foreach($types as $name => $type) {
            settype($data[$i][$name], $type);
        }
    }
    return $data;
}

Anwendungsbeispiel:

$dbconn = mysqli_connect('localhost','user','passwd','tablename');
$rs = mysqli_query($dbconn, "SELECT * FROM Matches");
$matches = cast_query_results($rs);
// $matches is now a assoc array of rows properly casted to ints/floats/strings
mastermind202
quelle
2
Eine großartige Lösung mit Ausnahme von 'NULL' ist auch ein Variablentyp, der von der Funktion settype () verwendet wird. Ihr Code ändert also alle von der Datenbank zurückgegebenen NULL-Werte (Werte, bei denen gettype () == 'NULL') in den Typ 'string' mit dem Wert '', den Typ 'integer' mit dem Wert 0 oder den Typ 'float' mit dem Wert 0.0. Sie müssen Settype nicht aufrufen, wenn is_null ($ data [$ i] [$ name]) wahr ist.
Winter Dragoness
Ich mag die Technik von Mastermind, aber die Codierung kann einfacher sein .
ToolmakerSteve
13

Nein. Unabhängig vom in Ihren Tabellen definierten Datentyp liefert der MySQL-Treiber von PHP immer Zeilenwerte als Zeichenfolgen.

Sie müssen Ihre ID in ein int umwandeln.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];
BoltClock
quelle
6
Es ist nicht PHP, das (direkt) für dieses Verhalten verantwortlich ist, sondern der Datenbanktreiber. Wenn Sie eine Schnittstelle zu einer Postgres-Datenbank aus PHP herstellen, erhalten Sie die entsprechenden Datentypen zurück.
GordonM
5

Ich mag die Antwort von Chad, besonders wenn die Abfrageergebnisse in einem Browser an Javascript weitergegeben werden. Javascript behandelt sauber numerische Entitäten als Zahlen, erfordert jedoch zusätzliche Arbeit, um numerisch ähnliche Entitäten als Zeichenfolgen zu behandeln. dh muss parseInt oder parseFloat auf ihnen verwenden.

Aufbauend auf der Lösung von Chad verwende ich diese und es ist oft genau das, was ich brauche und erstelle Strukturen, die JSON-codiert werden können, um den Umgang mit Javascript zu vereinfachen.

while ($row = $result->fetch_assoc()) {
    // convert numeric looking things to numbers for javascript
    foreach ($row as &$val) {
        if (is_numeric($val))
            $val = $val + 0;
    }
}

Das Hinzufügen einer numerischen Zeichenfolge zu 0 erzeugt einen numerischen Typ in PHP und identifiziert den Typ korrekt, sodass Gleitkommazahlen nicht in Ganzzahlen abgeschnitten werden.

d'Artagnan Immergrüne Barbosa
quelle
5

Dies geschieht, wenn die Verbindung aktiviert PDO::ATTR_EMULATE_PREPARESist true.

Wenn Sie jedoch falsefestlegen, dass die Verwendung von Parametern mehr als einmal nicht zulässig ist. Ich glaube, es wirkt sich auch auf die Qualität der zurückkommenden Fehlermeldungen aus.

Charlie
quelle
2

Sie können dies tun mit ...

  1. mysql_fetch_field ()
  2. mysqli_result :: fetch_field_direct oder
  3. PDOStatement :: getColumnMeta ()

... abhängig von der Erweiterung, die Sie verwenden möchten. Die erste wird nicht empfohlen, da die MySQL-Erweiterung veraltet ist. Der dritte ist noch experimentell.

In den Kommentaren zu diesen Hyperlinks wird gut erklärt, wie Sie Ihren Typ von einer einfachen alten Zeichenfolge auf den ursprünglichen Typ in der Datenbank setzen.

Einige Frameworks abstrahieren dies ebenfalls (CodeIgniter bietet $this->db->field_data()).

Sie können auch raten - wie das Durchlaufen der resultierenden Zeilen und die Verwendung von is_numeric () für jede Zeile . Etwas wie:

foreach($result as &$row){
 foreach($row as &$value){
  if(is_numeric($value)){
   $value = (int) $value;
  }       
 }       
}

Dies würde alles, was wie eine Zahl aussieht, in eine verwandeln ... definitiv nicht perfekt.

Chad Hedgcock
quelle
Funktioniert nicht für Schwimmer. Sie bestehen den is_numeric-Test. Sie sollten zuerst auf Schwimmer testen.
Martin van Driel
@MartinvanDriel oder eine beliebige Zeichenfolge, die nur Zahlen enthält, aber eine Zeichenfolge sein sollte
Treeface
@ MartinvanDriel Versuchen Sie hinzuzufügen:if (is_float()) { $value = (float)$value; }
adjwilli
2

In meinem Projekt verwende ich normalerweise eine externe Funktion, die die abgerufenen Daten "filtert" mysql_fetch_assoc.

Sie können Felder in Ihrer Tabelle umbenennen, um intuitiv zu verstehen, welcher Datentyp gespeichert ist.

Sie können beispielsweise jedem numerischen Feld ein spezielles Suffix hinzufügen: Wenn userides ein ist INT(11), können Sie es umbenennen, userid_ioder wenn es ein ist UNSIGNED INT(11), können Sie es umbenennen userid_u. Zu diesem Zeitpunkt können Sie eine einfache PHP-Funktion schreiben, die als Eingabe das assoziative Array empfängt (abgerufen mit mysql_fetch_assoc), und das Casting auf den mit diesen speziellen "Schlüsseln" gespeicherten "Wert" anwenden.

Didax
quelle
1

Wenn vorbereitete Anweisungen verwendet werden, ist der Typ gegebenenfalls int. Dieser Code gibt ein Array von Zeilen zurück, wobei jede Zeile ein assoziatives Array ist. Als ob fetch_assoc()für alle Zeilen aufgerufen wurde, jedoch mit beibehaltenen Typinformationen.

function dbQuery($sql) {
    global $mysqli;

    $stmt = $mysqli->prepare($sql);
    $stmt->execute();
    $stmt->store_result();

    $meta = $stmt->result_metadata();
    $params = array();
    $row = array();

    while ($field = $meta->fetch_field()) {
      $params[] = &$row[$field->name];
    }

    call_user_func_array(array($stmt, 'bind_result'), $params);

    while ($stmt->fetch()) {
      $tmp = array();
      foreach ($row as $key => $val) {
        $tmp[$key] = $val;
      }
      $ret[] = $tmp;
    }

    $meta->free();
    $stmt->close();

    return $ret;
}
Fredrik
quelle
1

MySQL verfügt über Treiber für viele andere Sprachen. Die Konvertierung von Daten in Zeichenfolgen "standardisiert" Daten und überlässt es dem Benutzer, Werte in int oder andere umzuwandeln

Wolfgang
quelle
1
Ich glaube, primitive Typen sind so ziemlich ein "Standard"? Wenn ein sprachspezifischer Fahrer die Anforderungen für diese Sprache nicht erfüllen könnte, würde ich sagen, dass es sehr enttäuschend ist
Chung
1

In meinem Fall wurde eine mysqlnd.soErweiterung installiert. ABER ich hatte nicht pdo_mysqlnd.so. So hatte das Problem durch Ersetzen gelöst pdo_mysql.somit pdo_mysqlnd.so.

Anton
quelle
1

Ich mag die Technik von Mastermind , aber die Codierung kann einfacher sein:

function cast_query_results($result): array
{
    if ($result === false)
      return null;

    $data = array();
    $fields = $result->fetch_fields();
    while ($row = $result->fetch_assoc()) {
      foreach ($fields as $field) {
        $fieldName = $field->name;
        $fieldValue = $row[$fieldName];
        if (!is_null($fieldValue))
            switch ($field->type) {
              case 3:
                $row[$fieldName] = (int)$fieldValue;
                break;
              case 4:
                $row[$fieldName] = (float)$fieldValue;
                break;
              // Add other type conversions as desired.
              // Strings are already strings, so don't need to be touched.
            }
      }
      array_push($data, $row);
    }

    return $data;
}

Ich habe auch die Überprüfung auf Abfragen hinzugefügt, die false anstelle einer Ergebnismenge zurückgeben.
Und nach einer Zeile mit einem Feld suchen, das einen Nullwert hat.
Und wenn der gewünschte Typ eine Zeichenfolge ist, verschwende ich keine Zeit damit - es ist bereits eine Zeichenfolge.


Ich mache mir nicht die Mühe, dies in den meisten PHP-Codes zu verwenden. Ich verlasse mich nur auf die automatische Typkonvertierung von PHP. Wenn Sie jedoch viele Daten abfragen, um dann arithmetische Berechnungen durchzuführen, ist es sinnvoll, im Voraus die optimalen Typen zu verwenden.

ToolmakerSteve
quelle