问题描述
我已经在Stack Overflow上重复了几次这个问题,但没有一个充分探讨这个问题(或至少以对我有帮助的方式)
问题在于,数据库查询应在PHP中为整数列返回整数数据类型。而是查询将每一列作为字符串类型返回。
我已经确保”PDO::ATTR_STRINGIFY_FETCHES”为false只是为了确保结果不会被强制转换为字符串。
我见过的答案:
-
做不到
-
不,它可以在安装了PHP /MySQL的Mac OS X上运行
-
-
在代码中键入强制类型转换
-
不,我不会那样做
-
-
不用担心,PHP是松散类型的
-
我的数据以JSON格式输出,并由许多其他服务使用,其中一些服务要求数据格式正确
-
从我的研究中,我了解到这是驱动程序实施的问题。
许多消息来源声称MySQL本机驱动程序不支持返回数字类型。这似乎并不正确,因为它可以在Mac OS X上运行。除非他们的意思是说“ Linux上的MySQL本机驱动程序不支持该功能”。
这意味着我在Mac OS X上安装的驱动程序/环境有一些特殊之处。我一直在尝试找出差异以便应用修复程序,但是我对如何检查这些问题的了解有限。
区别:
-
OS X上的PHP是通过Home Brew编译并安装的
-
通过“ apt-get install php5-dev”在Ubuntu上安装了PHP。
-
OS X上的PHP正在连接到也在OS X上运行的MySQL服务器
-
服务器版本:5.1.71-log源分发
-
-
Ubuntu上的PHP正在连接到Rackspace云数据库
-
服务器版本:5.1.66-0 + squeeze1(Debian)
-
Ubuntu环境
-
版本:10.04.1
-
PHP 5.4.21-1 + debphp.org〜lucid + 1(CLI)(内置:2013年10月21日08:14:37)
-
php -i pdo_mysql MySQL的PDO驱动程序=>已启用的客户端API版本=> 5.1.72
Mac OS X环境
-
10.7.5
-
PHP 5.4.16(CLI)(建立:2013年8月22日09: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,
任何帮助和专业知识将不胜感激:)如果我找到答案,我一定会在这里发布。
最佳办法
解决方案是确保您使用的是php的mysqlnd驱动程序。
您怎么知道您没有使用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
将在pdo_mysql
部分中明确提及”mysqlnd”:
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整数形式返回。
-
Fixed-Point类型(DECIMAL,NUMERIC)作为字符串返回。
†值大于64位有符号整数(9223372036854775807)的BIGINT将作为字符串返回(或在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)
次佳办法
这个公认的答案有效,并且似乎是Google在此问题上最受欢迎的答案。我的问题是,我需要将应用程序部署到多个环境中,但我并不总是能够安装正确的驱动程序,另外,我需要使用小数点表示数字而不是字符串。因此,我创建了一个在JSON编码之前键入case的例程,可以轻松对其进行修改以适合需要。这有点像从轨道上挪开它。
首先,使用“显示列来源”从表中获取列。 mysql query “SHOW COLUMNS FROM table like ‘colmunname'”:questions
$query = 'SHOW COLUMNS FROM ' . $table; //run with mysqli or PDO
然后将类型放入由列名索引的数组中,以使其易于迭代。假定来自show列的结果集在名为$ 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。