PHP + PDO + MySQL: come faccio a restituire colonne intere e numeriche da MySQL come numeri interi e numerici in PHP?


85

Ho visto questa domanda ripetuta alcune volte su Stack Overflow ma nessuna esplora sufficientemente il problema (o almeno in un modo che mi è utile)

Il problema è che una query DB dovrebbe restituire tipi di dati interi in PHP per colonne intere. La query restituisce invece ogni colonna come un tipo di stringa.

Ho assicurato che "PDO :: ATTR_STRINGIFY_FETCHES" se falso solo per assicurarmi che i risultati non venissero trasmessi alla stringa.

Risposte che ho visto:

  • Non si può fare
    • No, funziona su Mac OS X installato PHP / MySQL
  • Digita cast tutti i tuoi valori nel codice
    • No, non lo farò
  • Non preoccuparti, PHP è digitato in modo approssimativo
    • I miei dati vengono emessi come JSON e vengono utilizzati da molti altri servizi, alcuni richiedono i dati nel formato corretto

Dalla mia ricerca ho capito che questo è un problema di implementazione del driver.

Molte fonti affermano che il driver nativo di MySQL non supporta la restituzione di tipi numerici. Questo non sembra vero dato che funziona su Mac OS X. A meno che non vogliano dire che "il driver nativo di MySQL su Linux non supporta la funzionalità".

Ciò implica che c'è qualcosa di speciale nel driver / ambiente che ho installato su Mac OS X. Ho cercato di identificare le differenze per applicare una correzione, ma sono limitato dalla mia conoscenza di come controllare queste cose.

Le differenze:

  • PHP su OS X è stato compilato e installato tramite Home Brew
  • PHP su Ubuntu è stato installato tramite "apt-get install php5-dev"
  • PHP su OS X si connette a un server MySQL in esecuzione anche su OS X
    • Versione server: distribuzione dell'origine 5.1.71-log
  • PHP su Ubuntu si sta connettendo a un database Rackspace Cloud
    • Versione server: 5.1.66-0 + squeeze1 (Debian)

Ambiente Ubuntu

  • Versione: 10.04.1
  • PHP 5.4.21-1 + debphp.org ~ lucid + 1 (cli) (costruito: 21 ottobre 2013 08:14:37)
  • php -i

    pdo_mysql

    PDO Driver for MySQL => versione API client abilitata => 5.1.72

Ambiente Mac OS X.

  • 10.7.5
  • PHP 5.4.16 (cli) (costruito: 22 agosto 2013 09:05:58)
  • php -i

    pdo_mysql

    PDO Driver for MySQL => versione API client abilitata => mysqlnd 5.0.10 - 20111026 - $ Id: e707c415db32080b3752b232487a435ee0372157 $

Bandiere DOP utilizzate

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,

Qualsiasi aiuto e competenza sarebbero apprezzati :) Sicuramente pubblicherò qui se trovo la risposta.


2
È responsabilità di mysqlnd. Credo
Il tuo buon senso

Ho esattamente la stessa domanda, ma per MS SQL Server. Esiste una libreria fortemente tipizzata per questo, simile a mysqlnd? Gli ultimi driver che ho trovato restituiscono tutte le stringhe.
GSerg

Risposte:


122

La soluzione è assicurarsi di utilizzare mysqlnd driver per php.

Come fai a sapere che non stai usando mysqlnd?

Durante la visualizzazione php -i, non ci sarà alcun menzione di "mysqlnd". La pdo_mysqlsezione avrà qualcosa del genere:

pdo_mysql

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

come lo installi?

La maggior parte delle guide di installazione per L / A / M / P suggeriscono, apt-get install php5-mysqlma il driver nativo per MySQL è installato da un pacchetto diverso:php5-mysqlnd . Ho scoperto che questo era disponibile con ppa: ondrej / php5-oldstable .

Per passare al nuovo driver (su Ubuntu):

  • Rimuovi il vecchio driver:
    apt-get remove php5-mysql
  • Installa il nuovo driver:
    apt-get install php5-mysqlnd
  • Riavvia apache2:
    service apache2 restart

Come posso verificare che il driver sia in uso?

Ora php -imenzionerò "mysqlnd" esplicitamente nella pdo_mysqlsezione:

pdo_mysql

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

Impostazioni PDO

Assicurati che PDO::ATTR_EMULATE_PREPARESsia false(controlla le impostazioni predefinite o impostalo):
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Assicurati che PDO::ATTR_STRINGIFY_FETCHESsia false(controlla le impostazioni predefinite o impostalo):
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

Valori restituiti

  • I tipi a virgola mobile (FLOAT, DOUBLE) vengono restituiti come float PHP.
  • I tipi interi (INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT †) vengono restituiti come numeri interi PHP.
  • I tipi a virgola fissa (DECIMAL, NUMERIC) vengono restituiti come stringhe.

† BIGINT con un valore maggiore di un int con segno a 64 bit (9223372036854775807) restituirà una stringa (o 32 bit su un sistema a 32 bit)

    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)

3
Nota che anche con questa versione di mysqlnd abilitata, DECIMALS verrà comunque inviato come stringhe ... (anche se FLOATS verrà restituito come float!): / Fonte: l'ho testato.
Pere

4
Nota anche che PDO :: ATTR_STRINGIFY_FETCHES non ha nulla a che fare con questo - ho provato e non ha alcun effetto sul risultato, e in questo post l' utente @Josh Davis dice che non è correlato a MySQL.
Pere

1
Grazie, ho approfondito e aggiornato con note sul tipo DECIMAL.
stephenfrank

4
@pere questo è il comportamento giusto. DECIMAL non è un tipo numerico. È un formato stringa per i numeri. Quindi puoi tornare: 0.30come "0.30"invece di 0.3. I decimali sono usati per questo ... quindi questo è un comportamento corretto
Max Cuttins

perché è un dannato compromesso? Ho bisogno PDO::ATTR_EMULATE_PREPARESdi utilizzare un parametro denominato più di una volta
Gaby_64

5

Questa risposta accettata funziona e sembra essere la risposta più popolare su Google per questa domanda. Il mio problema è che devo distribuire un'applicazione in più ambienti e non sempre ho la possibilità di installare il driver giusto, inoltre ho bisogno che i decimali siano numerici, non stringhe. Quindi ho creato una routine per digitare maiuscole e minuscole prima della codifica JSON, che può essere facilmente modificata per adattarsi. È un po 'come lanciarlo in orbita.

Innanzitutto, utilizza "mostra colonne da" per ottenere le colonne dalla tabella. query mysql "MOSTRA COLONNE DA tabella come 'colmunname'": domande

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

Quindi inserisci i tipi in un array indicizzato dal nome della colonna per semplificare l'iterazione. Presuppone che i risultati impostati dalle colonne dello spettacolo si trovino in una variabile denominata $ column_from_table. http://php.net/manual/en/function.array-column.php

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

Successivamente vogliamo rimuovere la parentesi dal tipo, che sarà qualcosa come varchar (32) o decimal (14,6)

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

Ora abbiamo un array associato con il nome della colonna come indice e il tipo formattato come valore, ad esempio:

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

Ora, quando effettui la selezione dalla tabella, puoi iterare sui risultati e trasmettere il valore al tipo appropriato:

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;
}

L'istruzione switch può essere facilmente modificata per adattarla e potrebbe includere funzioni di data, ecc. Ad esempio, nel mio caso una terza parte sta inserendo i valori di valuta nel database come decimale, ma quando prendo quei dati e devo restituirli come JSON, ho bisogno che siano numeri, non stringhe.

Testato con PHP 7, 7.2 e JQuery 2, 3.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.