PHP + PDO + MySQL: Wie gebe ich in PHP ganzzahlige und numerische Spalten aus MySQL als Ganzzahlen und Zahlen zurück?

83

Ich habe diese Frage einige Male bei Stack Overflow wiederholt gesehen, aber keiner hat das Problem ausreichend untersucht (oder zumindest auf eine Weise, die für mich hilfreich ist).

Das Problem ist, dass eine DB-Abfrage ganzzahlige Datentypen in PHP für ganzzahlige Spalten zurückgeben sollte. Stattdessen gibt die Abfrage jede Spalte als Zeichenfolgentyp zurück.

Ich habe sichergestellt, dass "PDO :: ATTR_STRINGIFY_FETCHES" falsch ist, nur um sicherzustellen, dass die Ergebnisse nicht in Zeichenfolgen umgewandelt werden.

Antworten, die ich gesehen habe:

  • Das geht nicht
    • Nein, es funktioniert unter Mac OS X installiertem PHP / MySQL
  • Geben Sie cast all Ihre Werte in Ihren Code ein
    • Nein, das werde ich nicht tun
  • Mach dir keine Sorgen, PHP ist lose geschrieben
    • Meine Daten werden als JSON ausgegeben und von vielen anderen Diensten verwendet. Einige erfordern die Daten im richtigen Format

Aus meiner Forschung geht hervor, dass dies ein Problem bei der Treiberimplementierung ist.

Viele Quellen behaupten, dass der native MySQL-Treiber die Rückgabe numerischer Typen nicht unterstützt. Dies scheint nicht zu stimmen, da es unter Mac OS X funktioniert. Es sei denn, sie wollen sagen, dass "der native MySQL-Treiber unter Linux die Funktion nicht unterstützt".

Dies bedeutet, dass der Treiber / die Umgebung, die ich unter Mac OS X installiert habe, etwas Besonderes ist. Ich habe versucht, die Unterschiede zu identifizieren, um einen Fix anzuwenden, bin jedoch durch meine Kenntnisse zur Überprüfung dieser Dinge eingeschränkt.

Die Unterschiede:

  • PHP unter OS X wurde über Home Brew kompiliert und installiert
  • PHP unter Ubuntu wurde über "apt-get install php5-dev" installiert.
  • PHP unter OS X stellt eine Verbindung zu einem MySQL-Server her, der auch unter OS X ausgeführt wird
    • Serverversion: 5.1.71-log Quelldistribution
  • PHP unter Ubuntu stellt eine Verbindung zu einer Rackspace Cloud-Datenbank her
    • Serverversion: 5.1.66-0 + Squeeze1 (Debian)

Ubuntu-Umgebung

  • Version: 10.04.1
  • PHP 5.4.21-1 + debphp.org ~ lucid + 1 (cli) (erstellt: 21. Oktober 2013 08:14:37)
  • php -i

    pdo_mysql

    PDO-Treiber für MySQL => aktivierte Client-API-Version => 5.1.72

Mac OS X-Umgebung

  • 10.7.5
  • PHP 5.4.16 (cli) (erstellt: 22. August 2013, 09:05:58 Uhr)
  • php -i

    pdo_mysql

    PDO-Treiber für MySQL => aktivierte Client-API-Version => mysqlnd 5.0.10 - 20111026 - $ Id: e707c415db32080b3752b232487a435ee0372157 $

PDO-Flags verwendet

PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,

Jede Hilfe und Sachkenntnis wäre dankbar :) Ich werde auf jeden Fall wieder hier posten, wenn ich die Antwort finde.

stephenfrank
quelle
2
Es liegt in der Verantwortung von mysqlnd. Ich glaube
Ihre Common Sense
Ich habe genau die gleiche Frage, aber für MS SQL Server. Gibt es dafür eine stark typisierte Bibliothek, ähnlich wie mysqlnd? Die neuesten Treiber, die ich finden konnte, geben alle Zeichenfolgen zurück.
GSerg

Antworten:

120

Die Lösung besteht darin, sicherzustellen, dass Sie den mysqlnd- Treiber für PHP verwenden.

Woher wissen Sie, dass Sie mysqlnd nicht verwenden?

Beim Anzeigen php -iwird "mysqlnd" nicht erwähnt. Der pdo_mysqlAbschnitt wird so etwas wie diese:

pdo_mysql

PDO Driver for MySQL => enabled Client API version => 5.1.72

Wie installierst du es?

Die meisten Installationsanleitungen für L / A / M / P schlagen vor, apt-get install php5-mysqlaber der native Treiber für MySQL wird von einem anderen Paket installiert : php5-mysqlnd. Ich fand, dass dies mit dem ppa: ondrej / php5-oldstable verfügbar war .

So wechseln Sie zum neuen Treiber (unter Ubuntu):

  • Entfernen Sie den alten Treiber:
    apt-get remove php5-mysql
  • Installieren Sie den neuen Treiber:
    apt-get install php5-mysqlnd
  • Starten Sie apache2 neu:
    service apache2 restart

Wie überprüfe ich, ob der Treiber verwendet wird?

Jetzt php -iwird "mysqlnd" explizit im pdo_mysqlAbschnitt erwähnt:

pdo_mysql

PDO Driver for MySQL => enabled
Client API version => mysqlnd 5.0.10 - 20111026 - $Id:      e707c415db32080b3752b232487a435ee0372157 $

PDO-Einstellungen

Stellen Sie sicher, dass dies der Fall PDO::ATTR_EMULATE_PREPARESist false(überprüfen Sie Ihre Standardeinstellungen oder stellen Sie sie ein):
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Stellen Sie sicher, dass dies der Fall PDO::ATTR_STRINGIFY_FETCHESist false(überprüfen Sie Ihre Standardeinstellungen oder stellen Sie sie ein):
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

Rückgabewerte

  • Gleitkommatypen (FLOAT, DOUBLE) werden als PHP-Floats zurückgegeben.
  • Ganzzahlige Typen (INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT †) werden als PHP-Ganzzahlen zurückgegeben.
  • Festkommatypen (DECIMAL, NUMERIC) werden als Zeichenfolgen zurückgegeben.

† BIGINTs mit einem Wert größer als ein 64-Bit-Int (9223372036854775807) werden als Zeichenfolge zurückgegeben (oder 32 Bit in einem 32-Bit-System).

    object(stdClass)[915]
      public 'integer_col' => int 1
      public 'double_col' => float 1.55
      public 'float_col' => float 1.5
      public 'decimal_col' => string '1.20' (length=4)
      public 'bigint_col' => string '18446744073709551615' (length=20)
stephenfrank
quelle
3
Beachten Sie, dass DECIMALS auch mit dieser aktivierten Version von mysqlnd als Zeichenfolgen gesendet werden ... (obwohl FLOATS als Floats zurückgegeben werden!): / Quelle: Ich habe es getestet.
Pere
4
Beachten Sie auch, dass PDO :: ATTR_STRINGIFY_FETCHES nichts damit zu tun hat - ich habe es versucht und es hat keine Auswirkungen auf das Ergebnis, und in diesem Beitrag sagt Benutzer @Josh Davis, dass es nichts mit MySQL zu tun hat .
Pere
1
Vielen Dank, ich habe weiter nachgeforscht und mit Hinweisen zum DECIMAL-Typ aktualisiert.
StephenFrank
4
@pere das ist das richtige Verhalten. DECIMAL ist kein numerischer Typ. Es ist ein Zeichenfolgenformat für Zahlen. Sie können also zurückkehren: 0.30als "0.30"statt 0.3. Dezimalstellen werden dafür verwendet ... also ist dies das richtige Verhalten
Max Cuttins
Warum ist es ein verdammter Kompromiss? Ich muss PDO::ATTR_EMULATE_PREPARESeinen benannten Parameter mehr als einmal verwenden
Gaby_64
4

Diese akzeptierte Antwort funktioniert und scheint die beliebteste Antwort auf Google für diese Frage zu sein. Mein Problem ist, dass ich eine Anwendung in mehreren Umgebungen bereitstellen muss und nicht immer die Möglichkeit habe, den richtigen Treiber zu installieren. Außerdem müssen Dezimalstellen numerisch und keine Zeichenfolgen sein. Deshalb habe ich vor der JSON-Codierung eine Routine zum Eingeben von Groß- und Kleinschreibung erstellt, die leicht angepasst werden kann. Es ist ein bisschen so, als würde man es aus dem Orbit holen.

Verwenden Sie zunächst "Spalten anzeigen von", um die Spalten aus der Tabelle abzurufen. MySQL-Abfrage "SHOW COLUMNS FROM Tabelle wie 'colmunname'": Fragen

$query = 'SHOW COLUMNS FROM ' . $table; //run with mysqli or PDO 

Holen Sie sich dann die Typen in ein Array, das durch den Spaltennamen indiziert ist, um das Durchlaufen zu vereinfachen. Angenommen, die Ergebnismenge der Show-Spalten befindet sich in einer Variablen mit dem Namen $ columns_from_table. http://php.net/manual/en/function.array-column.php

$column_types = array_column( $columns_from_table, 'Type', 'Field');

Als nächstes wollen wir die Klammer aus dem Typ entfernen, der so etwas wie varchar (32) oder decimal (14,6) sein wird.

foreach( $column_types as $col=>$type )
{
    $len = strpos( $type, '(' );
    if( $len !== false )
    {
        $column_types[ $col ] = substr( $type, 0, $len );
    }
}

Jetzt haben wir ein zugeordnetes Array mit dem Spaltennamen als Index und dem formatierten Typ als Wert, zum Beispiel:

Array
(
    [id] => int
    [name] => varchar
    [balance] => decimal
    ...
)

Wenn Sie nun Ihre Auswahl aus Ihrer Tabelle treffen, können Sie die Ergebnisse durchlaufen und den Wert in den entsprechenden Typ umwandeln:

foreach( $results as $index=>$row )
{
    foreach( $row as $col=>$value )
    {
        switch( $column_types[$col] )
        {
            case 'decimal':
            case 'numeric':
            case 'float':
            case 'double':

                $row[ $col ] = (float)$value;
                break;

            case 'integer':
            case 'int':
            case 'bigint':
            case 'mediumint':
            case 'tinyint':
            case 'smallint':

                $row[ $col ] = (int)$value;
                break;
        }

    }
    $results[ $index ] = $row;
}

Die switch-Anweisung kann leicht an die jeweiligen Anforderungen angepasst werden und Datumsfunktionen usw. enthalten. In meinem Fall werden beispielsweise Währungswerte von einem Drittanbieter als Dezimalzahl in die Datenbank übertragen, aber wenn ich diese Daten greife und sie als zurückgeben muss JSON, ich brauche Zahlen, keine Strings.

Getestet mit PHP 7, 7.2 und JQuery 2, 3.

Craig Jacobs
quelle