PHP json_encode将数字编码为字符串


142

我在使用PHP json_encode函数时遇到一个问题。它将数字编码为字符串,例如

array('id' => 3)

变成

"{ ["id": "3", ...)

当js遇到这些值时,它将它们解释为字符串,并且对其执行数字操作失败。有谁知道防止json_encode数字编码为字符串的方法?谢谢!


原来,这是特定于版本的问题。有时,从MySql数据库中提取数据将保持正确的类型。在旧版本中,它可能以字符串形式返回所有内容。我今天早上写过这件事。shakyshane.com/blog/output-json-from-php.html
shane

1
我遇到了同样的问题,并且能够在模型中使用Laravel的Mutators解决我的问题。它使您可以修改模型中的值。laravel.com/docs/eloquent#accessors-and-mutators我不太首先得到它,但这个问题的帮助:stackoverflow.com/questions/16985656/...
爵士

Answers:


28

我做了一个非常快速的测试:

$a = array(
    'id' => 152,
    'another' => 'test',
    'ananother' => 456,
);
$json = json_encode($a);
echo $json;

如果我没记错的话,这似乎就像你所描述的那样?

我得到的输出:

{"id":152,"another":"test","ananother":456}

因此,在这种情况下,整数尚未转换为字符串。


尽管如此,这可能取决于我们使用的PHP版本:根据PHP版本,已经纠正了一些与json_encode相关的错误...

此测试已使用PHP 5.2.6进行;我在PHP 5.2.9和5.3.0中得到了同样的东西;我没有另一个5.2.x版本可以测试,尽管:-(

您正在使用哪个版本的PHP?还是您的测试用例比您发布的示例更复杂?

也许有关http://bugs.php.net/的一个错误报告?例如,错误#40503:json_encode整数转换与PHP不一致


也许Bug#38680也可能引起您的兴趣,顺便说一句?


谢谢马丁。我正在使用5.2.9。我想知道数字数据是否已从数据库中以字符串形式读取?我确定字段类型是int,但是我想不出另一种解释。我将在您的系统上尝试快速测试,看看是否得到相同的结果。
克里斯·巴恩希尔

12
可以5.2.9左右; 如果您的数据来自数据库,则可能是问题所在:我经常看到数据来自数据库,所有内容都转换为字符串(我已经使用PDO和mssql看到过;但是,如果我没记错的话,这种情况也会发生对于PHP <5.3中的MySQL,当新的mysqlnd驱动程序尚不存在时;要检查数据的外观,可以使用var_dump,它输出数据各部分的类型。
Pascal MARTIN

(续)认为数值的数据类型是字符串?有任何想法吗?
克里斯·巴恩希尔

1
我不完全了解“为什么从MySQL作为字符串返回数据”的技术原因;可能与PHP和MySQL之间的驱动程序有关;这是(至少在某些情况下)由PHP 5.3附带的新mysqlnd驱动程序纠正的内容(请参见blog.ulf-wendel.de/?p=184;在页面中搜索“整数”以找到有趣的内容句子);; 但我同意这不是很好^^
Pascal MARTIN

由json_encode()返回的数字数据不在引号中没关系,它仍然是字符串。json_encode()函数的返回值是一个字符串。关于MySQL将所有字段都返回为字符串,是的,我也遇到了PDO的问题。在我看来,您应该始终在PHP中将期望为数字的值转换为整数(或浮点数),以确保不信任MySQL或任何其他数据库返回具有正确类型的值。
理查德·诺普

351

请注意,自PHP 5.3.3起,有一个用于自动转换数字的标志(在PHP 5.3.0中添加了options参数):

$arr = array( 'row_id' => '1', 'name' => 'George' );
echo json_encode( $arr, JSON_NUMERIC_CHECK ); // {"row_id":1,"name":"George"}

4
请注意,JSON_NUMERIC_CHECK需要PHP 5.3.3。
罗伯特

10
完美工作直到将数字标签转换为整数,然后在IE中炸毁.toLowerCase()为止。请注意,此解决方案很简单,但过于热情。
布拉德·科赫

6
你是我的英雄,爱它。
Petrogad 2012年

5
如果您的字符串不是数字,而是类似这样的内容,则会产生一些副作用:5252788e16597。参考:bugs.php.net/bug.php?id = 64695
TonyQ,

20
JSON_NUMERIC_CHECK尝试通过尝试解析字符串来自动猜测字符串是否为数字。如果您考虑一下,那将是非常不可靠的。它将所有看起来数字的属性转换为数字(不仅是所需的数字),并且仅当它们看起来像数字时才这样做。如果不是不安全的话,那至少是摇晃的。使用产生的JSON的代码可能依赖于一种类型。如果这些期望得不到满足,就会发生奇怪的事情。如果您关心良好做法和安全性,则应该有选择地转换所需的值。
wadim

35

同样,我正在从数据库(PostgreSQL)读取数据,而一切都是字符串。我们遍历每一行,并用它来完成最终的结果数组,所以我使用了

$result_arr[] = array($db_row['name'], (int)$db_row['count']);

在循环中强制将其设为整数值。当我这样做json_encode($result_arr),现在,它正确格式化为一个数字。这使您可以控制来自数据库的数字是多少。

编辑:

json_encode()函数还具有使用该JSON_NUMERIC_CHECK标志作为它的第二个参数来动态执行此操作的能力。您需要谨慎使用它,尽管如文档中此用户示例所示(复制如下):http : //uk3.php.net/manual/en/function.json-encode.php#106641

<?php
// International phone number
json_encode(array('phone_number' => '+33123456789'), JSON_NUMERIC_CHECK);
?>

然后,您将获得以下JSON:

{"phone_number":33123456789}

是的,看来问题出在数据库适配器,它不能解释数据类型,而不是json_encode功能。这是最正确的答案,但是要小心,因为JSON_NUMERIC_CHECK还会转换电话号码和其他数字字符串值,这可能导致前导零或“ +”的问题。我建议在数据库读取功能中更正此问题。
caesarsol 2014年


7

我遇到同样的问题(PHP-5.2.11 / Windows)。我正在使用此解决方法

$json = preg_replace( "/\"(\d+)\"/", '$1', $json );

它用数字本身替换用引号引起来的所有(非负整数)数字(“ 42”变为“ 42”)。

另请参见PHP手册中的此注释


感谢您的代码,但是可惜它在我的json上不起作用,因为我有一个数字作为对象名,并且它似乎使json无效:(
SSH

@SSHThis,也许您应该使用此语法将数组转换为JSON编码的数组,而不是对象。$json_array = json_encode($some_array, false);因此false参数告诉PHP不要执行对象转换。
海德

使用该解决方法根本不安全。您将获得具有以下结构的无效json:json_encode(array(-1=>'que', '0'=>'-1'))
Alex Yaroshevich 2013年

$this->data = preg_replace("/\" *?: *?(\d+)/", '":"$1"', $this->data);
反过来说

我将原始正则表达式更改为`“ /\"(\d+\.?\d*)\"/”`以包含小数,另外一点是当字符串也是正确的时候,使用JSON_NUMERIC_CHECK的人将面临问题科学计数法中的数字。例如19E008。JSON_NUMERIC_CHECK会将其转换为190000 ...
Sahib Khan

3

以下测试确认将类型更改为字符串会导致json_encode()返回一个数字作为JSON字符串(即,用双引号引起来)。使用settype(arr [“ var”],“ integer”)或settype($ arr [“ var”],“ float”)进行修复。

<?php

class testclass {
    public $foo = 1;
    public $bar = 2;
    public $baz = "Hello, world";
}

$testarr = array( 'foo' => 1, 'bar' => 2, 'baz' => 'Hello, world');

$json_obj_txt = json_encode(new testclass());
$json_arr_txt = json_encode($testarr);

echo "<p>Object encoding:</p><pre>" . $json_obj_txt . "</pre>";
echo "<p>Array encoding:</p><pre>" . $json_arr_txt . "</pre>";

// Both above return ints as ints. Type the int to a string, though, and...
settype($testarr["foo"], "string");
$json_arr_cast_txt = json_encode($testarr);
echo "<p>Array encoding w/ cast:</p><pre>" . $json_arr_cast_txt . "</pre>";

?>

2

为了完整性(因为我还不能添加评论),让我也将此详细信息添加为另一个答案:

(编辑:要在意识到源数据(即,在OP的情况下,是数据库结果集)可能是问题之后(通过将数字列作为字符串返回)来读取,而json_encode()实际上不是问题的根源)

这两个“ mysql_fetch_array ”的手册页:

返回与获取的行相对应的字符串数组

...和“ mysql_ fetch_ row ”:

返回与获取的行相对应的字符串的数字数组

明确指出:返回数组中的条目将是字符串。

(我在phpBB2中使用DB类(是的,我已经过时了!),该类的“ sql_fetchrow()”方法使用“ mysql_fetch_array()”)

没有意识到这一点,我最终还是找到了这个问题,并理解了这个问题!:)

正如Pascal Martin在其后续评论中所述,我相信一种解决方案可以从源头解决“不正确的类型”问题(即通过使用“ mysql_field_type() ”函数并在获取后立即进行转换),(或一般而言,其他提取方法(例如“对象”?))会更好。


2

所以Pascal MARTIN在这里没有得到足够的认可。对于具有数百个服务器端功能的现有项目,无法在每个JSON返回上检查数字值。

我用php-mysqlnd替换了php-mysql,问题消失了。数字是数字,字符串是字符串,布尔值是布尔值。


0

在处理数据库中的数据时,我也遇到了同样的问题。基本上,问题是PHP中将数组中要转换为json的类型识别为字符串而不是整数。就我而言,我做了一个查询,该查询从数据库列计数行返回数据。PDO驱动程序不能将列识别为int,但可以识别为字符串。我通过在受影响的列中将类型转换为int来解决。


0
$rows = array();
while($r = mysql_fetch_assoc($result)) {
    $r["id"] = intval($r["id"]); 
    $rows[] = $r;
}
print json_encode($rows);  

0

这是PHP版本的问题,有同样的问题将我的PHP版本升级到5.6解决了问题




-1

只是遇到了同样的问题,数据库是将值作为字符串返回的。

我用它作为解决方法:

$a = array(
    'id' => $row['id'] * 1,
    'another' => ...,
    'ananother' => ...,
);
$json = json_encode($a);

也就是说,将值乘以1即可将其转换为数字

希望对某人有帮助


使用乘法器不是最有效的解决方案。考虑在json_encode上使用JSON_NUMERIC_CHECK,因为它将自动修复它
Erick

-2

json_encode以JSON格式序列化一些数据结构,以通过网络发送。因此,所有内容均为字符串类型。就像当您从$ _POST或$ _GET接收到某些参数时一样。

如果必须对发送的值进行数字运算,只需先将它们转换为int(使用PHP中的intval()函数或Javascript中的parseInt()),然后执行这些运算即可。


那不是他在说什么。他说的是json在数字周围用双引号引起来。
JasonWoof

对于JSON,它确实保留类型。想象一下写出一个文字JavaScript对象,任何带引号的值都变成字符串,但没有带引号的数字都变成整数,0x [0-9a-z]变成十六进制等。PHP与类型有差异,例如,没有这样的东西一个关联数组,只是对象或索引数组等
。– bucabay

对。他遇到的问题是他有一个php变量,他认为类型是int,因为它来自int类型的DB列。但实际上,PHP变量的类型为字符串,因此为JSON中的引号。
JasonWoof

-2

好吧,PHP json_encode()返回一个字符串。

您可以在js代码中使用parseFloat()或parseInt():

parseFloat('122.5'); // returns 122.5
parseInt('22'); // returns 22
parseInt('22.5'); // returns 22

谢谢。我希望有一种更优雅的方法。
克里斯·巴恩希尔

1
是的,最安全的方法是解析它们。但是,难道不是Javascript的类型很松散吗?
mauris

只是注释:它是松散类型的,仍然会是“ 1” +1的结果... 11-因此,使用JS时,您应该比使用强类型语言时更加专心,因为它们会警告您,JS会按照您的意愿去做认为最好的办法是处理字符串数字...
SamiSalami 2012年

是的,但这不是重点,json_encode不应在数字字段中添加引号。
andreszs 2015年

-3

就像oli_arborum所说,我认为您可以使用a preg_replace来完成工作。只需像这样更改命令:

$json = preg_replace('#:"(\d+)"#', ':$1', $json);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.