Il campo intero MySQL viene restituito come stringa in PHP


127

Ho un campo tabella in un database MySQL:

userid INT(11)

Quindi lo sto chiamando alla mia pagina con questa query:

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

Quindi per gestire il risultato faccio:

$row=$result->fetch_assoc();

$id=$row['userid'];

Ora se lo faccio:

echo gettype($id);

Ricevo una stringa. Non dovrebbe essere un numero intero?


2
la query MySQL fornisce valori di riga non tipi di riga o qualsiasi altra informazione associata. Solo i dati non elaborati presenti in ogni cella della tabella. Dovrai renderlo conto in PHP
Dan Hanly,

Se hai bisogno dei tipi di colonna, vedi qui forums.whirlpool.net.au/archive/526795
RichardTheKiwi

Per i lettori, la risposta selezionata implica l'iterazione dei risultati. Ma c'è una soluzione migliore. stackoverflow.com/a/1197424/5079380
Amr ElAdawy

1
@DanHanly - tecnicamente, la query MYSQL (in PHP) restituisce una rappresentazione in formato stringa del valore della cella - il valore effettivo della cella memorizzato nel database per un numero intero a 32 bit è ... un numero intero a 32 bit, non una stringa di cifre .
ToolmakerSteve

per me, quando ho usato $conn->query("your query")ho ottenuto i campi interi come stringa ma quando ho usato $conn->prepare("your query")ho ottenuto i parametri come erano nel database
Bar Tzadok

Risposte:


129

Quando selezioni i dati da un database MySQL utilizzando PHP, il tipo di dati verrà sempre convertito in una stringa. Puoi riconvertirlo in un numero intero usando il seguente codice:

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

O usando la funzione intval():

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

79
Arrivato a MySQL da un background di Postgres, sento il bisogno di dire che questo è un grande dolore nel culo. Quando hai recuperato una riga in Postgres sei sicuro che gli elementi nell'array della riga avessero tipi di dati appropriati. Ora devo scrivere il codice per trasmettere manualmente ogni elemento al tipo di dati che mi aspetto.
GordonM,

25
Ho appena fatto alcuni test su Windows con Laravel e Mysql sullo stesso schema e server di database. Su Windows la chiave primaria viene restituita come numero intero e su Linux è una stringa.
AturSams,

Ok è una buona idea, ma cosa succede se hai migliaia di campi da recuperare? Questo processo richiede un po 'di tempo. Nel mio esempio, recupero il numero di visualizzazioni per ciascun post, quindi stampo tutti i miei post in una tabella, consento all'utente di ordinare per Visualizza asc e desc, ma ordina da "1" a "9 "o" 9 "a" 1 ", quindi al primo posto potresti avere" 9999 "," 91 "," 8111 "," 7 ", ecc ...
KeizerBridge

@zehelvion hai mai trovato una soluzione a questo?
Felipe Francisco,

2
Ogni campo restituito sarà una stringa O NULL .
Liam,

73

Usa mysqlnd (driver nativo) per php.

Se sei su Ubuntu:

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

Se sei su Centos:

sudo yum install php-mysqlnd
sudo service httpd restart

Il driver nativo restituisce i tipi interi in modo appropriato.

Modificare:

Come ha sottolineato @Jeroen, questo metodo funzionerà immediatamente per PDO.
Come ha sottolineato @LarsMoelleken, questo metodo funzionerà con mysqli se imposti anche l'opzione MYSQLI_OPT_INT_AND_FLOAT_NATIVE su true.

Esempio:

$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);

Non vedo alcuna prova di questo stamento. In esecuzione con mysqlnd e mysqli, vengono restituiti chiaramente i valori stringa.
Jeroen,

@Jeroen sei sicuro? C'è molta documentazione disponibile. stackoverflow.com/questions/1197005/...
Advait

sì. Guarda anche i commenti qui sotto. L'hai provato tu stesso? come sembra ora, anche mysqlnd restituisce i tipi appropriati solo se si usano istruzioni preparate. esempio: $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);restituisce: array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
Jeroen il

1
Non come lo capisco, dovrebbe funzionare allo stesso modo con DOP e Mysqli. Anche sul link che pubblichi sopra nel commento si afferma chiaramente che FUNZIONA SOLO CON DICHIARAZIONI PREPARATE e non in linea query come da PO. citazione da quella pagina: Ma questo è solo PHP 5.3 (a condizione che la tua versione di PHP 5.3 sia compilata con mysqlnd (e non con la vecchia libmysql)), e sembra essere il caso solo per le dichiarazioni preparate :-(
Jeroen l'

7
puoi anche usare "MYSQLI_OPT_INT_AND_FLOAT_NATIVE" per mysqli
Lars Moelleken l'

20

La soluzione più semplice che ho trovato:

Puoi forzare json_encode a usare numeri reali per valori che sembrano numeri:

json_encode($data, JSON_NUMERIC_CHECK) 

(dal PHP 5.3.3).

Oppure potresti semplicemente trasmettere il tuo ID a un int.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

1
Usare una json_encodecorda per lanciare int se possibile è come usare il microscopio per soffocare le unghie.
LibertyPaul,

7
Ciò interromperà tutti i codici postali e il numero di telefono. Buon modo per introdurre bug nella tua app. La soluzione DEVE rispettare il tipo di dati della colonna mysql, non tentare di indovinare dal valore.
Max Cuttins,

1
Max Cuttins, il tuo punto è valido. Tuttavia, se riesci a tenere conto di tutti i tipi di dati previsti dal DB, questa sarebbe una strada perfetta da prendere.
Ifedi Okonkwo,

1
Questo ti farà del male quando un giorno hai ID di qualche tipo come '06'. Questo flag lo convertirà in 6. Il che è sbagliato perché quegli ID dovrebbero mantenere gli zeri finali.
Hassan Dad Khan,

Questa è un'ottima soluzione per i valori creati UNIX_TIMESTAMP(), ad esempio.
David,

18

La mia soluzione è passare il risultato della query $rse ottenere un array assoc dei dati castati come ritorno:

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

Esempio di utilizzo:

$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

2
Ottima soluzione tranne 'NULL' è anche un tipo di variabile utilizzato dalla funzione settype (). Quindi il tuo codice cambia tutti i valori NULL restituiti dal database (valori dove gettype () == 'NULL') nel tipo 'stringa' con '' valore, tipo 'intero' con valore 0 o tipo 'float' con valore 0.0. Non è necessario chiamare settype se is_null ($ data [$ i] [$ name]) è true.
Winter Dragoness,

Mi piace la tecnica di mastermind, ma la codifica può essere più semplice .
ToolmakerSteve

13

No. Indipendentemente dal tipo di dati definito nelle tabelle, il driver MySQL di PHP serve sempre i valori delle righe come stringhe.

Devi trasmettere il tuo ID a un int.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

6
Non è PHP responsabile (direttamente) di questo comportamento, è il driver del database. Se stai interfacciando con un database Postgres di PHP, riceverai i tipi di dati appropriati.
GordonM,

5

Mi piace la risposta di Chad, soprattutto quando i risultati della query verranno passati a javascript in un browser. Javascript gestisce in modo pulito entità come numeri come numeri, ma richiede ulteriore lavoro per gestire entità come numeri come stringhe. cioè deve usare parseInt o parseFloat su di essi.

Basandomi sulla soluzione di Chad, lo uso ed è spesso esattamente ciò di cui ho bisogno e crea strutture che possono essere codificate in JSON per una facile gestione in JavaScript.

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

L'aggiunta di una stringa numerica a 0 produce un tipo numerico in PHP e identifica correttamente il tipo in modo che i numeri in virgola mobile non vengano troncati in numeri interi.


5

Questo succede quando PDO::ATTR_EMULATE_PREPARESè impostato sutrue su sulla connessione.

Attento, impostandolo su falsenon consente l'uso dei parametri più di una volta. Credo che influisca anche sulla qualità dei messaggi di errore che ritornano.


2

Puoi farlo con ...

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

... a seconda dell'estensione che si desidera utilizzare. Il primo non è raccomandato perché l'estensione mysql è obsoleta. Il terzo è ancora sperimentale.

I commenti a questi collegamenti ipertestuali fanno un buon lavoro nel spiegare come impostare il tipo da una semplice stringa vecchia al suo tipo originale nel database.

Alcuni framework astraggono anche questo (fornisce CodeIgniter $this->db->field_data()).

Potresti anche fare congetture - come scorrere le righe risultanti e usare is_numeric () su ciascuna. Qualcosa di simile a:

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

Ciò trasformerebbe tutto ciò che sembra un numero in uno ... sicuramente non perfetto.


Non funziona per i galleggianti. Passano il test is_numeric. Dovresti prima provare per i float.
Martin van Driel,

@MartinvanDriel o qualsiasi stringa che contenga solo numeri, ma dovrebbe essere una stringa
treeface

@MartinvanDriel Prova ad aggiungere:if (is_float()) { $value = (float)$value; }
adjwilli,

2

Nel mio progetto di solito utilizzo una funzione esterna con cui "filtra" i dati recuperati mysql_fetch_assoc .

È possibile rinominare i campi nella tabella in modo che sia intuitivo capire quale tipo di dati è archiviato.

Ad esempio, puoi aggiungere un suffisso speciale a ciascun campo numerico: se useridè un INT(11)puoi rinominarlo userid_io se è un UNSIGNED INT(11)puoi rinominarlo userid_u. A questo punto, puoi scrivere una semplice funzione PHP che riceve come input l'array associativo (recuperato con mysql_fetch_assoc) e applicare il casting al "valore" memorizzato con quegli speciali "tasti".


1

Se vengono utilizzate istruzioni preparate, il tipo sarà int dove appropriato. Questo codice restituisce una matrice di righe, in cui ogni riga è una matrice associativa. Come se fetch_assoc()fosse stato chiamato per tutte le righe, ma con informazioni sul tipo conservate.

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

1

MySQL ha driver per molte altre lingue, convertendo i dati in string "standardizza" i dati e lascia all'utente la digitazione di valori in int o altri


1
Credo che i tipi primitivi siano praticamente uno "standard"? Se un guidatore specifico della lingua non fosse in grado di soddisfare le esigenze di quella lingua, direi che è molto deludente
Chung

1

Nel mio caso l' mysqlnd.soestensione era stata installata. MA non l'ho fatto pdo_mysqlnd.so. Quindi, il problema era stato risolto sostituendolo pdo_mysql.socon pdo_mysqlnd.so.


0

Mi piace la tecnica di mastermind , ma la codifica può essere più semplice:

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

Ho anche aggiunto il controllo della query restituendo false anziché un set di risultati.
E controllando una riga con un campo che ha un valore nullo.
E se il tipo desiderato è una stringa, non ci spreco tempo, è già una stringa.


Non mi preoccupo di usare questo nella maggior parte del codice php; Mi baso solo sulla conversione automatica del tipo di php. Ma se si eseguono query su molti dati, per eseguire calcoli aritmetici, è sensato eseguire il cast dei tipi ottimali in anticipo.

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.