PHP + PDO + MySQL: как я могу возвращать целочисленные и числовые столбцы из MySQL как целые числа и числа в PHP?

Я видел, как этот вопрос повторялся несколько раз при переполнении стека, но ни один из них не исследовал проблему (или, по крайней мере, так, как это полезно для меня).

Проблема заключается в том, что запрос БД должен возвращать целочисленные типы данных в 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 Cloud
    • Версия сервера: 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,

Любая помощь и опыт будут оценены:) Я обязательно отправлюсь туда, если найду ответ.

Ответ 1

Решение состоит в том, чтобы убедиться, что вы используете драйвер 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.
  • Типы неподвижных точек (DECIMAL, NUMERIC) возвращаются как строки.

† 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)

Ответ 2

Этот принятый ответ работает и, похоже, является наиболее популярным ответом в Google на этот вопрос. Моя проблема заключается в том, что мне нужно развернуть приложение в нескольких средах, и у меня не всегда есть возможность установить нужный драйвер, плюс мне нужно, чтобы десятичные числа были числовыми, а не строковыми. Поэтому я создал подпрограмму для ввода регистра case перед кодировкой 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.