Bidang integer MySQL dikembalikan sebagai string dalam PHP

127

Saya memiliki bidang tabel dalam database MySQL:

userid INT(11)

Jadi saya memanggilnya ke halaman saya dengan pertanyaan ini:

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

Kemudian untuk menangani hasil yang saya lakukan:

$row=$result->fetch_assoc();

$id=$row['userid'];

Sekarang jika saya lakukan:

echo gettype($id);

Saya mendapatkan string. Bukankah ini bilangan bulat?

luca
sumber
2
kueri MySQL memberikan nilai baris bukan tipe baris atau informasi terkait lainnya. Hanya data mentah yang ada di setiap sel tabel. Anda harus menjelaskan ini dalam PHP
Dan Hanly
Jika Anda memerlukan jenis kolom, lihat di sini forums.whirlpool.net.au/archive/526795
RichardTheKiwi
Untuk pembaca, jawaban yang dipilih melibatkan iterasi melalui hasil. Tetapi ada solusi yang lebih baik. stackoverflow.com/a/1197424/5079380
Amr ElAdawy
1
@DanHanly - secara teknis, permintaan MYSQL (dalam PHP) mengembalikan representasi string dari nilai sel - nilai sel aktual yang disimpan dalam database untuk integer 32-bit adalah ... integer 32-bit, bukan deretan digit .
ToolmakerSteve
bagi saya, ketika saya menggunakan $conn->query("your query")saya mendapat bidang bilangan bulat sebagai string tetapi ketika saya menggunakan $conn->prepare("your query")saya mendapat parameter karena mereka dalam database
Bar Tzadok

Jawaban:

129

Ketika Anda memilih data dari database MySQL menggunakan PHP, tipe data akan selalu dikonversi ke string. Anda dapat mengubahnya kembali menjadi integer menggunakan kode berikut:

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

Atau dengan menggunakan fungsi intval():

$id = intval($row['userid']);
Michiel Pater
sumber
79
Setelah datang ke MySQL dari latar belakang Postgres saya merasa perlu untuk mengatakan bahwa ini adalah rasa sakit yang luar biasa. Ketika Anda mengambil sebuah baris di Postgres, Anda bisa yakin bahwa elemen-elemen dalam array baris memiliki tipe data yang sesuai. Sekarang saya harus menulis kode untuk secara manual melemparkan setiap elemen ke tipe data yang saya harapkan.
GordonM
25
Saya hanya melakukan beberapa tes pada Windows dengan Laravel dan Mysql pada skema dan server database yang sama. Pada Windows kunci utama dikembalikan sebagai Integer dan di Linux itu adalah String.
AturSams
Ok itu ide yang bagus tetapi bagaimana jika Anda memiliki ribuan bidang untuk diambil? Proses ini memakan waktu cukup lama .. Dalam contoh saya, saya mengambil jumlah tampilan untuk setiap posting, kemudian saya mencetak semua posting saya dalam sebuah tabel, saya mengizinkan pengguna untuk mengurutkan berdasarkan Lihat dan desc, tetapi itu mengurutkan dengan "1" ke "9 "atau" 9 "hingga" 1 "sehingga Anda dapat memiliki" 9999 "," 91 "," 8111 "," 7 ", dll ...
KeizerBridge
@zehelvion apakah Anda pernah menemukan solusi untuk ini?
Felipe Francisco
2
Setiap bidang yang dikembalikan akan berupa string ATAU NULL .
Liam
73

Gunakan mysqlnd (driver asli) untuk php.

Jika Anda menggunakan Ubuntu:

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

Jika Anda menggunakan Centos:

sudo yum install php-mysqlnd
sudo service httpd restart

Pengandar asli mengembalikan tipe integer dengan tepat.

Edit:

Seperti @Jeroen telah tunjukkan, metode ini hanya akan bekerja di luar kotak untuk PDO.
Seperti yang ditunjukkan oleh @LarsMoelleken, metode ini akan berfungsi dengan mysqli jika Anda juga mengatur opsi MYSQLI_OPT_INT_AND_FLOAT_NATIVE menjadi true.

Contoh:

$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);
advait
sumber
Saya tidak melihat bukti dari ratapan ini. Berjalan dengan mysqlnd dan mysqli, nilai string jelas dikembalikan.
Jeroen
@ Joen, kamu yakin? Ada banyak dokumentasi yang tersedia. stackoverflow.com/questions/1197005/…
advait
Iya. Lihat juga komentar di bawah. Apakah Anda mengujinya sendiri? seperti yang terlihat sekarang, bahkan mysqlnd hanya mengembalikan tipe yang sesuai jika Anda menggunakan pernyataan yang sudah disiapkan. contoh: $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);pengembalian: array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
Jeroen
1
Bukan bagaimana saya memahaminya, itu harus bekerja sama dengan PDO dan Mysqli. Bahkan pada tautan yang Anda posting di atas dalam komentar, dengan jelas dinyatakan bahwa HANYA BEKERJA DENGAN PERNYATAAN YANG DIPERSIAPKAN dan bukan permintaan inline sesuai OP. kutipan dari halaman itu: Tapi ini hanya PHP 5.3 (asalkan versi PHP 5.3 Anda dikompilasi dengan mysqlnd (dan bukan libmysql lama)), dan tampaknya hanya menjadi kasus untuk pernyataan yang disiapkan :-(
Jeroen
7
Anda juga dapat menggunakan "MYSQLI_OPT_INT_AND_FLOAT_NATIVE" untuk mysqli
Lars Moelleken
20

Solusi termudah yang saya temukan:

Anda bisa memaksa json_encode untuk menggunakan angka aktual untuk nilai yang terlihat seperti angka:

json_encode($data, JSON_NUMERIC_CHECK) 

(sejak PHP 5.3.3).

Atau Anda bisa memasukkan ID Anda ke int.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];
Larney
sumber
1
Menggunakan json_encodestring untuk melemparkan ke int jika memungkinkan seperti menggunakan mikroskop untuk mencekik kuku.
LibertyPaul
7
Ini akan mematahkan semua kode pos dan nomor telepon. Cara yang baik untuk memperkenalkan Bug di Aplikasi Anda. Solusinya HARUS menghormati datatype kolom mysql, jangan mencoba menebak dari nilai.
Max Cuttins
1
Max Cuttins, poin Anda valid. Namun, jika Anda dapat menjelaskan semua tipe data yang diharapkan dari DB, ini akan menjadi rute yang tepat untuk diambil.
Ifedi Okonkwo
1
Ini akan menyakiti Anda ketika Anda kadang memiliki id semacam seperti '06'. Bendera ini akan mengonversinya menjadi 6. Yang mana salah karena id itu harus tetap berada di belakang nol.
Hassan Dad Khan
Ini adalah solusi bagus untuk nilai yang dibuat oleh UNIX_TIMESTAMP(), misalnya.
David
18

Solusi saya adalah untuk melewatkan hasil permintaan $rsdan mendapatkan array assoc dari data yang dicor sebagai pengembalian:

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

Contoh penggunaan:

$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
sumber
2
Solusi hebat kecuali 'NULL' juga merupakan tipe variabel yang digunakan oleh fungsi settype (). Jadi kode Anda mengubah semua nilai NULL yang dikembalikan oleh basis data (nilai di mana gettype () == 'NULL') menjadi tipe 'string' dengan nilai '', 'integer' dengan nilai 0, atau tipe 'float' dengan nilai 0,0. Anda tidak perlu memanggil settype jika is_null ($ data [$ i] [$ name]) benar.
Winter Dragoness
Saya suka teknik mastermind, tetapi pengkodeannya bisa lebih sederhana .
ToolmakerSteve
13

Tidak. Terlepas dari tipe data yang didefinisikan dalam tabel Anda, pengandar MySQL PHP selalu menyajikan nilai baris sebagai string.

Anda perlu memberikan ID Anda ke int.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];
BoltClock
sumber
6
Bukan PHP yang bertanggung jawab (langsung) untuk perilaku ini, itu adalah driver basis data. Jika Anda berinteraksi dengan database Postgres dari PHP, Anda akan mendapatkan kembali tipe data yang sesuai.
GordonM
5

Saya suka jawaban Chad, terutama ketika hasil kueri akan diteruskan ke javascript di browser. Javascript berurusan dengan entitas numerik seperti sebagai angka tetapi membutuhkan kerja ekstra untuk berurusan dengan entitas seperti numerik sebagai string. yaitu harus menggunakan parseInt atau parseFloat pada mereka.

Membangun pada solusi Chad Saya menggunakan ini dan sering kali persis apa yang saya butuhkan dan membuat struktur yang dapat dikodekan JSON agar mudah berurusan dengan 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;
    }
}

Menambahkan string numerik ke 0 menghasilkan tipe numerik dalam PHP dan mengidentifikasi tipe tersebut dengan benar sehingga angka floating point tidak akan terpotong menjadi bilangan bulat.

d'Artagnan Evergreen Barbosa
sumber
5

Ini terjadi ketika PDO::ATTR_EMULATE_PREPARESdiatur ke truepada koneksi.

Hati-hati, mengaturnya untuk falsemelarang penggunaan parameter lebih dari sekali. Saya percaya ini juga mempengaruhi kualitas pesan kesalahan yang datang kembali.

Charlie
sumber
2

Anda dapat melakukan ini dengan ...

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

... tergantung pada ekstensi yang ingin Anda gunakan. Yang pertama tidak direkomendasikan karena ekstensi mysql sudah usang. Yang ketiga masih eksperimental.

Komentar di hyperlink ini berfungsi dengan baik untuk menjelaskan cara mengatur tipe Anda dari string lama polos ke tipe aslinya dalam database.

Beberapa kerangka kerja juga mengabstraksi ini (CodeIgniter menyediakan $this->db->field_data()).

Anda juga bisa melakukan menebak - seperti perulangan di baris yang dihasilkan dan menggunakan is_numeric () pada masing-masing. Sesuatu seperti:

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

Ini akan mengubah apa pun yang terlihat seperti angka menjadi satu ... pasti tidak sempurna.

Chad Hedgcock
sumber
Tidak berfungsi untuk mengapung. Mereka lulus tes is_numeric. Anda harus menguji untuk mengapung terlebih dahulu.
Martin van Driel
@MartinvanDriel atau string apa pun yang hanya berisi angka, tetapi harus berupa string
treeface
@MartinvanDriel Coba tambahkan:if (is_float()) { $value = (float)$value; }
adjwilli
2

Dalam proyek saya, saya biasanya menggunakan fungsi eksternal yang "menyaring" data yang diambil mysql_fetch_assoc.

Anda bisa mengganti nama bidang di tabel Anda sehingga intuitif untuk memahami tipe data mana yang disimpan.

Misalnya, Anda dapat menambahkan akhiran khusus untuk masing-masing bidang numerik: jika useridadalah INT(11)Anda dapat mengubah nama itu userid_iatau jika itu adalah UNSIGNED INT(11)Anda dapat mengubah nama userid_u. Pada titik ini, Anda dapat menulis fungsi PHP sederhana yang menerima sebagai input array asosiatif (diambil dengan mysql_fetch_assoc), dan menerapkan casting ke "nilai" yang disimpan dengan "kunci" khusus itu.

Didax
sumber
1

Jika pernyataan yang disiapkan digunakan, jenisnya akan int jika perlu. Kode ini mengembalikan array baris, di mana setiap baris adalah array asosiatif. Seperti jika fetch_assoc()dipanggil untuk semua baris, tetapi dengan info jenis yang diawetkan.

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
sumber
1

MySQL memiliki driver untuk banyak bahasa lain, mengonversi data menjadi string "membakukan" data dan menyerahkannya kepada pengguna untuk mengetikkan nilai cast ke int atau lainnya

Wolfgang
sumber
1
Saya percaya tipe primitif cukup banyak "standar"? Jika pengemudi khusus bahasa tidak dapat memenuhi kebutuhan untuk bahasa itu, saya akan mengatakan itu sangat mengecewakan
Chung
1

Dalam kasus saya mysqlnd.soekstensi telah diinstal. TAPI saya belum melakukannya pdo_mysqlnd.so. Jadi, masalah telah diselesaikan dengan mengganti pdo_mysql.sodengan pdo_mysqlnd.so.

Anton
sumber
0

Saya suka teknik mastermind , tetapi codingnya bisa lebih sederhana:

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

Saya juga menambahkan memeriksa permintaan yang mengembalikan false daripada set hasil.
Dan memeriksa baris dengan bidang yang memiliki nilai nol.
Dan jika tipe yang diinginkan adalah string, saya tidak membuang waktu untuk itu - itu sudah menjadi string.


Saya tidak repot menggunakan ini di sebagian besar kode php; Saya hanya mengandalkan konversi tipe otomatis php. Tetapi jika meminta banyak data, untuk kemudian melakukan perhitungan aritmatika, masuk akal untuk menggunakan tipe optimal di muka.

ToolmakerSteve
sumber