I've seen this question repeated a few times on Stack Overflow but none sufficiently explore the problem (or at least in a way that is helpful to me)
The problem is that a DB query should return integer data types in PHP for integer columns. Instead the query returns every column as a string type.
I've ensured that "PDO::ATTR_STRINGIFY_FETCHES" if false just to make sure results aren't being cast to string.
Answers that I've seen:
- It can't be done
- Nope, it's working on Mac OS X installed PHP/MySQL
- Type cast all your values in your code
- Nope, I won't be doing that
- Don't worry about it, PHP is loosely typed
- My data is output as JSON and is consumed by many other services, some require the data in the correct format
Из моих исследований я понимаю, что это проблема с реализацией драйвера.
Многие источники утверждают, что собственный драйвер 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,
Любая помощь и опыт будут оценены :) Я обязательно отправлю сюда ответ, если найду ответ.
Ответы:
Решение состоит в том, чтобы убедиться, что вы используете драйвер 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
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);
Возвращенные значения
† BIGINT со значением больше, чем 64-битное целое число со знаком (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)
источник
0.30
as"0.30"
вместо0.3
. Для этого используются десятичные числа ... так что это правильное поведениеPDO::ATTR_EMULATE_PREPARES
использовать именованный параметр более одного разаЭтот принятый ответ работает и, по-видимому, является самым популярным ответом на этот вопрос в Google. Моя проблема в том, что мне нужно развернуть приложение в нескольких средах, и у меня не всегда есть возможность установить правильный драйвер, плюс мне нужно, чтобы десятичные дроби были числовыми, а не строками. Поэтому я создал процедуру для ввода регистра перед кодировкой JSON, которую легко изменить. Это все равно что сбить его с орбиты.
Во-первых, используйте «показать столбцы из», чтобы получить столбцы из таблицы. mysql query "ПОКАЗАТЬ СТОЛБЦЫ ИЗ таблицы, такой как '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) или decimal (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.
источник