如何在 PHP 中以整数和数字的形式从 MySQL 返回整数和数字列?

问题是数据库查询应该为整数列返回 PHP 中的整数数据类型。相反,查询将每个列作为字符串类型返回。

我已经确保“ PDO: : ATTR _ STRINGIFY _ FETCHES”如果 假的只是为了确保结果没有被强制转换为字符串。

我看到的答案是:

  • 这是不可能的
    • 没有,它在安装了 PHP/MySQL 的 Mac OS X 上工作
  • 键入强制转换代码中的所有值
    • 不,我不会那么做的
  • 不用担心,PHP 是松散类型的
    • 我的数据以 JSON 格式输出,并被许多其他服务使用,有些服务需要正确格式的数据

从我的研究中我了解到这是一个驱动程序实现问题。

许多来源声称 MySQL 本机驱动程序不支持返回数值类型。这似乎不是真的,因为它可以在 Mac OS X 上工作。除非他们的意思是说“在 Linux上的 MySQL 本地驱动程序不支持这个功能”。

这意味着我在 Mac OS X 上安装的驱动程序/环境有一些特殊之处。我一直试图找出这些不同之处,以便应用一个修复程序,但我的知识限制了我如何检查这些东西。

区别在于:

  • OS X 上的 PHP 是通过 Home Brew 编译和安装的
  • Ubuntu 上的 PHP 是通过“ apt-get install php5-dev”安装的
  • OS X 上的 PHP 连接到同样运行在 OS X 上的 MySQL 服务器
    • 服务器版本: 5.1.71-log Source 发行版
  • Ubuntu 上的 PHP 正在连接到 Rackspace 云数据库
    • 服务器版本: 5.1.66-0 + 挤压1(Debian)

Ubuntu 环境

  • 版本: 10.04.1

  • PHP 5.4.21-1 + debphp.org ~ lucid + 1(cli)(编译: Oct 21201308:14:37)

  • Php-i

    Pdo _ mysql

    启用了 MySQL = > 的 PDO 驱动程序 客户端 API 版本 = > 5.1.72

Mac OS X 环境

  • 10.7.5

  • PHP 5.4.16(cli)(编译: Aug 22201309:05:58)

  • Php-i

    Pdo _ mysql

    启用了 MySQL = > 的 PDO 驱动程序 客户端 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,
29102 次浏览

The solution is to ensure that you are using the mysqlnd driver for php.

How do you know that you're not using mysqlnd?

When viewing php -i, there will be no mention of "mysqlnd". The pdo_mysql section will have something like this:

pdo_mysql


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

How do you install it?

Most installation guides for L/A/M/P suggest apt-get install php5-mysql but the native driver for MySQL is installed by a different package: php5-mysqlnd. I found that this was available with the ppa:ondrej/php5-oldstable.

To switch to the new driver (on Ubuntu):

  • Remove the old driver:
    apt-get remove php5-mysql
  • Install the new driver:
    apt-get install php5-mysqlnd
  • Restart apache2:
    service apache2 restart

How do I check that the driver is being used?

Now php -i will mention "mysqlnd" explicitly in the pdo_mysql section:

pdo_mysql


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

PDO settings

Ensure that PDO::ATTR_EMULATE_PREPARES is false (check your defaults or set it):
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Ensure that PDO::ATTR_STRINGIFY_FETCHES is false (check your defaults or set it):
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

Returned values

  • Floating-point types (FLOAT, DOUBLE) are returned as PHP floats.
  • Integer types (INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT †) are returned as PHP integers.
  • Fixed-Point types (DECIMAL, NUMERIC) are returned as strings.

† BIGINTs with a value greater than a 64 bit signed int (9223372036854775807) will return as a string (or 32 bits on a 32 bit system)

    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)

This accepted answer works, and seems to be the most popular answer on Google for this question. My issue is that I need to deploy an application to multiple environments and I don't always have the ability to get the right driver installed, plus I need decimals to be numeric, not strings. So I created a routine to type case before JSON encoding, which is easily modified to suit. It's kinda like nuking it from orbit.

First, use "show columns from" to get the columns from the table. mysql query "SHOW COLUMNS FROM table like 'colmunname'":questions

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

Then get the types into an array indexed by the column name to make it easy to iterate over. Assumes results set from show columns is in a variable named $columns_from_table. http://php.net/manual/en/function.array-column.php

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

Next we want to remove the parenthetical from the type, which is going to be something like varchar(32) or decimal(14,6)

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

Now we have an associated array with the column name as the index and the formatted type as the value, for example:

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

Now, when you do your select from your table you can iterate over the results and cast the value to the appropriate type:

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

The switch statement can be easily modified to suit, and could include date functions, etc. For example, in my case a 3rd party is pushing currency values into the database as a decimal, but when I grab that data and need to return it as JSON, I need those to be numbers, not strings.

Tested with PHP 7, 7.2 and JQuery 2, 3.

In php-8.1.0RC1/ are native types even for EMULATE_PREPARES, https://github.com/php/php-src/tree/c18b1aea289e8ed6edb3f6e6a135018976a034c6 So in future it should be possible to omit PDO::ATTR_EMULATE_PREPARES => false, option.