【问题标题】:PHP json_encode encoding numbers as stringsPHP json_encode 将数字编码为字符串
【发布时间】:2009-09-07 21:14:55
【问题描述】:

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

array('id' => 3)

变成

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

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

【问题讨论】:

标签: php javascript json


【解决方案1】:

请注意,自 PHP 5.3.3 起,there's a flag 用于自动转换数字(在 PHP 5.3.0 中添加了 options 参数):

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

【讨论】:

  • 请注意 JSON_NUMERIC_CHECK 需要 PHP 5.3.3。
  • 工作完美,直到它将数字标签转换为整数,在 IE 中炸毁 .toLowerCase()。小心,这个解决方案很简单但过于热心。
  • 如果你的字符串不是数字而是这样的内容,它会有一些副作用: 5252788e16597 。参考:bugs.php.net/bug.php?id=64695
  • JSON_NUMERIC_CHECK 尝试通过解析字符串来自动猜测字符串是否为数字。如果您考虑一下,那是非常不可靠的。它将 all 看起来像数字的属性转换为数字(不仅是您想要的那些),并且只有当它们看起来像数字时才会这样做。如果不是不安全的话,那至少是不稳定的。使用生成的 JSON 的代码可能依赖于其中一种类型。如果这些期望没有得到满足,就会发生奇怪的事情。如果您关心良好做法和安全性,您应该有选择地转换您想要的值。
  • 正如 Brad 和 wadim 所提到的,JSON_NUMERIC_CHECK 具有将合法字符串转换为数值的副作用。为了克服这个问题,如果您知道每个字段的类型,您可以使用以下解决方法:将“标记”(例如“this_is_a_string”)连接到任何字符串字段的值,然后使用 JSON_NUMERIC_CHECK 选项执行 json_encode,最后从 json 字符串中删除了标记:$cleaned_json= str_replace('this_is_a_string', '', $marked_json)。不优雅,但对我有用。
【解决方案2】:

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

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

如果我没记错的话,这似乎和你描述的一样?

我得到了输出:

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

所以,在这种情况下,整数还没有被转换为字符串。


不过,这可能取决于我们使用的 PHP 版本:已经纠正了几个 json_encode 相关的错误,具体取决于 PHP 的版本...

此测试是使用 PHP 5.2.6 进行的;我对 PHP 5.2.9 和 5.3.0 也有同样的看法;不过,我没有另一个 5.2.x 版本可供测试:-(

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

也许关于http://bugs.php.net/ 的一份错误报告可能与此相关?比如Bug #40503 : json_encode integer conversion is inconsistent with PHP?


顺便说一句,也许Bug #38680 也会让你感兴趣?

【讨论】:

  • 谢谢马丁。我正在使用 5.2.9。我想知道数字数据是否作为字符串从数据库中读取?我确定字段类型是 int,但我想不出另一种解释。我会在我的系统上尝试你的快速测试,看看我是否得到相同的结果。
  • OK 大约 5.2.9 ;如果您的数据来自数据库,问题可能就在那里:我经常看到数据来自数据库,所有内容都转换为字符串(我在 PDO 和 mssql 中看到过这种情况;但是,如果我没记错的话,这也会发生对于 PHP
  • (续)认为数值的数据类型是字符串?有什么想法吗?
  • 我不太清楚“为什么数据以字符串形式从 MySQL 返回”的技术原因 ;;可能与 PHP 和 MySQL 之间的驱动程序有关;;这是(至少在某些情况下)由 PHP 5.3 附带的新 mysqlnd 驱动程序纠正的东西(参见blog.ulf-wendel.de/?p=184;在页面中搜索“整数”以找到有趣的句子);;但我同意这不好^^
  • 我用7还是有这个问题
【解决方案3】:

试试 $arr = array('var1' => 100, 'var2' => 200);
$json = json_encode( $arr, JSON_NUMERIC_CHECK);

但它只适用于 PHP 5.3.3。看看这个 PHP json_encode 更改日志 http://php.net/manual/en/function.json-encode.php#refsect1-function.json-encode-changelog

【讨论】:

  • 这对我有用。在 debian 挤压 6.0.5 上默认安装 PHP+apache,数据来自 postgre db
【解决方案4】:

所以Pascal MARTIN 在这里没有得到足够的信任。对于具有数百个服务器端功能的现有项目,检查每个 JSON 返回的数值是不可行的。

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

【讨论】:

    【解决方案5】:

    我同样在从数据库(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 也会转换电话号码和其他数字字符串值,这可能会导致前导零或“+”出现问题...我建议在数据库中纠正这个问题阅读功能。
    【解决方案6】:

    为了完整起见(因为我还不能添加 cmets),让我也添加这个细节作为另一个答案:

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

    “mysql_fetch_array”的手册页:

    返回对应于获取行的字符串数组,

    ...和“mysql_ fetch_ row”:

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

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

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

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

    正如 Pascal Martin 在他的后续 cmets 中所说,我相信一种解决方案可以从源头解决“不正确的类型”问题(即通过使用“mysql_field_type()”函数并在 fetch 之后立即进行转换,(或其他 fetch 方法,如“object”?))通常会更好。

    【讨论】:

      【解决方案7】:
      $rows = array();
      while($r = mysql_fetch_assoc($result)) {
          $r["id"] = intval($r["id"]); 
          $rows[] = $r;
      }
      print json_encode($rows);  
      

      【讨论】:

        【解决方案8】:

        以下测试确认将类型更改为字符串会导致 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>";
        
        ?>
        

        【讨论】:

          【解决方案9】:

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

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

          【讨论】:

            【解决方案10】:

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

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

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

            【讨论】:

            • 谢谢。我希望有一个更优雅的方法。
            • 是的,最安全的方法是解析它们。但同样,Javascript 的类型不是很松散吗?
            • 只是一个评论:它是松散类型的,“1”+1 的结果仍然是...... 11 - 所以使用 JS 你应该比强类型语言更专心,因为它们会警告你,如果处理字符串数字,JS 只会做它认为最好的事情......
            • 是的,但这不是重点,json_encode 不应该在数字字段中添加引号。
            【解决方案11】:

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

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

            用数字本身替换引号中的所有(非负整数)数字('“42”'变成'42')。

            另见this comment in PHP manual。

            【讨论】:

            • 感谢您的代码,但遗憾的是它不适用于我的 json,因为我有一个数字作为对象名称,它似乎使 json 无效:(
            • @SSHThis,也许你应该使用这种语法将数组转换为 JSON 编码的数组而不是对象。 $json_array = json_encode($some_array, false); 所以 false 参数告诉 PHP 不要进行对象转换。
            • 使用这种解决方法根本不安全。您将获得具有以下结构的无效 json:json_encode(array(-1=&gt;'que', '0'=&gt;'-1'))
            • 我遇到了另一个问题,我需要在 PHP 7.0 中将整数编码为字符串并使用 $this-&gt;data = preg_replace("/\" *?: *?(\d+)/", '":"$1"', $this-&gt;data);
            • 我会将原来的正则表达式更改为` "/\"(\d+\.?\d*)\"/" ` 以包含小数,另一个注意事项是使用 JSON_NUMERIC_CHECK 的人将面临当字符串也是科学计数法中的正确数字时出现问题。例如,19E008。 JSON_NUMERIC_CHECK 会将其转换为 190000...
            【解决方案12】:

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

            【讨论】:

              【解决方案13】:

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

              【讨论】:

                【解决方案14】:

                将值转换为 int 或 float 似乎可以解决问题。例如:

                $coordinates => array( 
                    (float) $ap->latitude,
                    (float) $ap->longitude 
                );
                

                【讨论】:

                  【解决方案15】:

                  如果出现任何问题,您可以使用 (int) !!它会正常工作的。

                  【讨论】:

                    【解决方案16】:

                    我在 curl 发送 json 时遇到了这个问题,它需要一些字段是整数,而其他字段是字符串,但字符串字段的一些值实际上是数字,所以 JSON_NUMERIC_CHECK 不起作用,因为它转换了所有看起来像数对数。 我找到的解决方案是在表示字符串值的字段中添加代表未来双引号的字符,在我的情况下,我使用了 @,因为我知道在我的数据中不可能有这个字符

                    $analysis = array(
                    
                    'SampleAnalysisId'  => $record[3],
                    'DisplayValue' => '@'.$record[4].'@',
                    'MeasurementUnit' => '@'.$record[5].'@',
                    'SampleAnalysisConclusionId'  => $record[6],
                    'Uncertaint' => '@'.$record[7].'@',
                    'K' => '',
                    'QuantificationLimit' => '@'.$record[8].'@',
                    'DetectionLimit' => '@'.$record[9].'@',
                    'Veff' => ''
                    

                    );

                    然后在编码后,我将双引号替换为空,然后将“@”替换为双引号。

                    $str = json_encode($analysis,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
                    $str = str_replace('@','"',str_replace('",',',',str_replace(':"',':',$str)));
                    

                    根据我的需要生成一个格式化的 json

                    [{"SampleAnalysisId":10479,"DisplayValue":"6,3","MeasurementUnit":"mg/L","SampleAnalysisConclusionId":1,"Uncertaint":"0,194463","K":,"QuantificationLimit":"1","DetectionLimit":"0,30","Veff":"}]
                    

                    【讨论】:

                      【解决方案17】:

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

                      我将其用作解决方法:

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

                      将值乘以 1 以将其转换为数字

                      希望对某人有所帮助

                      【讨论】:

                      • 使用乘数并不是最有效的解决方案。考虑在 json_encode 上使用 JSON_NUMERIC_CHECK,因为它会自动修复它
                      【解决方案18】:

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

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

                      【讨论】:

                      • 他说的不是这个。他说的是 json 在数字周围有双引号。
                      • 在 JSON 的情况下,它确实保存了类型。想象一下写出一个文字 JavaScript 对象,任何带引号的值都变成字符串,但不带引号的数字变成整数,0x[0-9a-z] 变成十六进制等。PHP 存在类型差异,例如,没有这样的东西关联数组,只是对象或索引数组等。
                      • 正确。他遇到的问题是他有一个 php 变量,他认为该变量具有 int 类型,因为它来自 int 类型的 DB 列。但实际上 PHP 变量的类型是字符串,因此 JSON 中的引号。
                      猜你喜欢
                      • 1970-01-01
                      • 2014-09-27
                      • 1970-01-01
                      • 1970-01-01
                      • 2019-03-02
                      • 2021-02-27
                      • 2012-07-09
                      • 1970-01-01
                      相关资源
                      最近更新 更多