PHP + PDO + MySQL: як повернути цілі та числові стовпці з MySQL як цілі числа та цифри в PHP?


85

Я бачив, як це запитання повторювалося кілька разів у Stack Overflow, але жодне недостатньо досліджувало проблему (або, принаймні, корисним для мене способом)

Проблема полягає в тому, що запит БД повинен повертати цілі типи даних у PHP для цілочисельних стовпців. Натомість запит повертає кожен стовпець як тип рядка.

Я переконався, що "PDO :: ATTR_STRINGIFY_FETCHES", якщо значення false, лише для того, щоб переконатися, що результати не передаються в рядок.

Відповіді, які я бачив:

  • Це неможливо зробити
    • Ні, це працює на встановленому Mac OS X PHP / MySQL
  • Введіть в коді всі свої значення
    • Ні, я не буду цього робити
  • Не хвилюйтеся з цього приводу, PHP вводиться вільно
    • Мої дані виводяться у форматі JSON і використовуються багатьма іншими службами, деякі вимагають даних у правильному форматі

З мого дослідження я зрозумів, що це проблема реалізації драйверів.

Багато джерел стверджують, що власний драйвер MySQL не підтримує повернення числових типів. Це не здається правдою, оскільки це працює на Mac OS X. Якщо вони не хочуть сказати, що "власний драйвер MySQL в Linux не підтримує цю функцію".

Це означає, що в драйвері / середовищі, яке я встановив на Mac OS X, є щось особливе. Я намагався виявити відмінності, щоб застосувати виправлення, але я обмежений своїми знаннями про те, як перевірити ці речі.

Відмінності:

  • PHP на OS X був скомпільований та встановлений через Home Brew
  • PHP на Ubuntu було встановлено за допомогою "apt-get install php5-dev"
  • PHP на OS X - це підключення до сервера MySQL, який також працює на OS X
    • Версія сервера: 5.1.71-log Розподіл джерел
  • PHP на Ubuntu підключається до хмарної бази даних Rackspace
    • Версія сервера: 5.1.66-0 + squeeze1 (Debian)

Середовище Ubuntu

  • Версія: 10.04.1
  • PHP 5.4.21-1 + debphp.org ~ lucid + 1 (cli) (побудовано: 21 жовтня 2013 р. 08:14:37)
  • php -i

    pdo_mysql

    Драйвер PDO для MySQL => увімкнена версія клієнтського API => 5.1.72

Середовище Mac OS X.

  • 10.7.5
  • PHP 5.4.16 (cli) (побудовано: 22 серпня 2013 09:05:58)
  • php -i

    pdo_mysql

    Драйвер PDO для MySQL => версія клієнтського API => mysqlnd 5.0.10 - 20111026 - $ Id: e707c415db32080b3752b232487a435ee0372157 $

Використовуються прапори PDO

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,

Будемо вдячні за будь-яку допомогу та досвід :) Я точно надішлю сюди, якщо знайду відповідь.


2
Це відповідальність mysqlnd. Я вірю
Ваш здоровий глузд

У мене точно таке ж питання, але щодо MS SQL Server. Чи існує для цього сильно набрана бібліотека, схожа на mysqlnd? В останніх версіях драйверів я міг би знайти повернути всі рядки.
GSerg

Відповіді:


121

Рішення полягає в тому, щоб переконатися, що ви використовуєте драйвер mysqlnd для php.

Звідки ви знаєте, що не використовуєте mysqlnd?

При перегляді php -i, що не буде НЕ згадати про «mysqlnd». pdo_mysqlСекція матиме що - щось на зразок цього:

pdo_mysql

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

Як його встановити?

Більшість посібників по установці для L / A / M / P припускає , apt-get install php5-mysqlале рідний драйвер для MySQL встановлений на інший пакет: php5-mysqlnd. Я виявив, що це було доступно з ppa: ondrej / php5-oldstable .

Щоб перейти на новий драйвер (на Ubuntu):

  • Видаліть старий драйвер:
    apt-get remove php5-mysql
  • Встановіть новий драйвер:
    apt-get install php5-mysqlnd
  • Перезапустіть apache2:
    service apache2 restart

Як перевірити, чи використовується драйвер?

Зараз php -iявно згадаю "mysqlnd" у pdo_mysqlрозділі:

pdo_mysql

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

Налаштування PDO

Переконайтеся, що PDO::ATTR_EMULATE_PREPARESце так false(перевірте за замовчуванням або встановіть його):
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Переконайтеся, що PDO::ATTR_STRINGIFY_FETCHESце так false(перевірте за замовчуванням або встановіть його):
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

Повернуті значення

  • Типи з плаваючою комою (FLOAT, DOUBLE) повертаються як плаваючі PHP.
  • Цілі цілі типи (INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT †) повертаються як цілі числа PHP.
  • Типи фіксованих точок (ДІСЯЧНІ, ЧИСЛОВІ) повертаються у вигляді рядків.

† BIGINT зі значенням, більшим за 64-бітний підписаний int (9223372036854775807), повернеться у вигляді рядка (або 32 біти в 32-бітовій системі)

    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
Зверніть увагу, що навіть якщо ця версія mysqlnd увімкнена, DECIMALS все одно будуть надсилатися як рядки ... (хоча FLOATS будуть повертатися як плаваючі!): / Джерело: Я тестував це.
Пере

4
Також зверніть увагу, що PDO :: ATTR_STRINGIFY_FETCHES не має нічого спільного з цим - я спробував, і це не впливає на результат, і в цьому дописі користувач @Josh Davis каже, що це не пов'язано з MySQL.
Пере

1
Дякую, я розібрався далі і доповнив примітками про тип DECIMAL.
stephenfrank

4
@pere це правильна поведінка. DECIMAL не є числовим типом. Це формат рядків для чисел. Тож ви можете повернутися: 0.30як "0.30"замість 0.3. Для цього використовуються десяткові
числа

чому це проклятий компроміс? Мені потрібно PDO::ATTR_EMULATE_PREPARESвикористовувати названий параметр більше одного разу
Gaby_64

4

Ця прийнята відповідь працює, і, схоже, є найпопулярнішою відповіддю на це питання в Google. Моя проблема полягає в тому, що мені потрібно розгорнути програму в декількох середовищах, і я не завжди маю можливість встановити правильний драйвер, плюс мені потрібні десяткові знаки, щоб бути числовими, а не рядками. Тому я створив рутину для введення регістру перед кодуванням JSON, яку легко модифікувати відповідно. Це як би витягнути його з орбіти.

Спочатку використовуйте "показати стовпці з", щоб отримати стовпці з таблиці. запит mysql "ПОКАЗАТИ СТОЛЬЦИ З ТАБЛИЦІ, як" colmunname "": запитання

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

Потім отримайте типи в масив, індексований іменем стовпця, щоб полегшити перегляд. Припускає, що набір результатів із стовпців шоу міститься у змінній з назвою $ columns_from_table. http://php.net/manual/en/function.array-column.php

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

Далі ми хочемо видалити дужки з типу, який буде приблизно таким як varchar (32) або десятковий (14,6)

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

Тепер у нас є пов’язаний масив з ім’ям стовпця як індексом та відформатованим типом як значенням, наприклад:

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

Тепер, коли ви робите вибір із вашої таблиці, ви можете переглядати результати та призначати значення відповідному типу:

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

Оператор switch можна легко модифікувати, щоб він міг відповідати, і він міг би включати функції дати і т. Д. Наприклад, у моєму випадку третя сторона вводить значення валют у базу даних як десяткову, але коли я захоплюю ці дані і їх потрібно повернути як JSON, мені потрібно, щоб це були числа, а не рядки.

Перевірено за допомогою PHP 7, 7.2 та JQuery 2, 3.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.