为什么我不必在 JS 中解码/解析 PHP 生成的 JSON 字符串

Why don't I have to decode/parse a JSON string generated by PHP in JS

本文关键字:PHP 字符串 JSON 解析 不必 JS 解码 为什么      更新时间:2023-09-26

要在JS脚本中使用一些变量,我只需将它们设置在带有JSON的包装器中,如下所示:

<?php // Variables for JS
$vars = array(
    'fetchPath' => "$home/my-url.php",
);
?>
<script>
var phpVars = <?php echo json_encode($vars); ?>;
</script>

这导致

<script>
var phpVars = {"fetchPath":"http:'/'/my.website.com'/my-url.php"};
</script>

现在,当我尝试从 JS 脚本解析此值时,我收到意外的令牌错误。但是,当我简单地将变量用作对象时,它可以完美地工作。换句话说,我可以简单地访问phpVars.fetchPath,而无需将该值转换回对象表示形式。

在使用Perl,PHP和Javascript数小时后,我是否完全失去了理智,并且您不必在JS中解码JSON字符串 - 还是发生了其他事情?

当你这样做时:

<script>
var phpVars = <?php echo json_encode($vars); ?>;
</script>

你正在用PHP生成JavaScript代码。因此,实际进入浏览器的是:

<script>
var phpVars = /*...THE_JSON_GOES_HERE...*/;
</script>

请注意,它不在引号或任何内容中。您的示例代码将生成一个看起来像 {"fetchPath":"/path/to/my-url.php"} 的 JSON 字符串,因此浏览器将看到的是:

<script>
var phpVars = {"fetchPath":"http:'/'/my.website.com'my-url.php"};
</script>

由于 JSON 是 JavaScript 对象初始值设定项语法的子集,因此这是完全有效的 JavaScript 代码。解析脚本标记内容的解析器将其解析为代码,而不是 JSON。但这没关系,因为只要它用作右侧值(例如,在=的右侧或传递到函数等),JSON 就是有效的 JavaScript。

JSON 是根据 JavaScript 文字的语法建模的。

当你把一些JSON放到JavaScript程序的中间,就好像它是JavaScript代码一样,那么它就被视为JavaScript代码,并被解析为一组JavaScript文字。

那么,在哪些情况下,您是否需要解析JSON

当您以非 JavaScript 代码的格式获取 JSON 时(例如,当您使用 XMLHttpRequest 通过 HTTP 获取 JSON 资源时),它会放在一个字符串中。然后,您需要将 JSON 显式转换为 JavaScript 对象。

这就是JSON的全部意义所在:它是JavaScript对象表示法 - 一种被JavaScript原生理解的格式。

var json = {"a": 1, "b": false, "c": null, "d": [1, 2, 3], "e": {"f": 1}};

是完全有效的JavaScript,这就是PHP json_encode函数从以下结构中产生的,例如:

$json = array(
    'a' => 1, 
    'b' => false, 
    'c' => null, 
    'd' => array(1, 2, 3), 
    'e' => array(
        'f' => 1
    )
);

如果您从 XMLHttpRequest(又名 AJAX)请求中检索字符串'{"a": 1, "b": false, "c": null, "d": [1, 2, 3], "e": {"f": 1}}',则需要parseJSON。响应正文将是一个字符串,需要使用 parseJSON 将其转换为 JavaScript 对象。这只是一个例子。在nodejs中打开JSON文件是另一个。

在您的示例中,您实际上将json_encode输出嵌入到某个 JavaScript 源代码(由 <script> 标记定义)。这就是为什么 JavaScript 解释器会追上 JSON 语法并从中构造一个 JavaScript 对象。

一些并不总是清楚的术语:

  • PHP 和 JavaScript 是不同的语言,不直接交互:它们不共享变量,不共享任何类型的资源......它们甚至不在同一台计算机上运行!PHP在服务器上运行(假设,爱尔兰Google数据中心某处的DELL计算机),JavaScript在浏览器中运行(假设,慕尼黑附近的奶奶的笔记本电脑)。

    你经常使用 PHP 来生成 JavaScript 代码。浏览器不知道也不关心代码是如何生成的:它只看到生成的源代码,并显示是否应该:使用浏览器的"查看源代码"功能(通常映射到Ctrl+U 快捷方式)。

  • JavaScript和JSON是不同的语言,几乎没有共同的功能。JavaScript是一种编程语言,JSON是一种数据格式。唯一的关系是JSON创建者的想法是将他的语言基于JavaScript语法的(非常有限的)子集。这个机智的想法允许使用 eval() 函数从 JavaScript 代码中读取正确格式的 JSON——换句话说,他发明了一种新格式,他不必编写解析器!

    (当然,没有人再使用eval()了,随着JSON的流行,每个人都编写了正确的解析器。

还有一个细节...生成JSON的PHP函数实际上允许生成部分JSON,从技术上讲,这不是有效的JSON

echo json_encode(array('A', 'B')); // Valid JSON: ["A","B"]
echo json_encode('Leopoldo Alas "Clarín"'); // JSON fragment: "Leopoldo Alas '"Clar'u00edn'""

这个技巧经常被"滥用",将原始输入注入到生成的 JavaScript 代码中,因为如果你的数据碰巧包含 JavaScript 语法中具有特殊含义的字符,则没有简单的方法来避免导致解析错误:

<?php
$writer = 'Leopoldo Alas "Clarín"';
?>
var writer = "<?php echo $writer; ?>";
var writer = "Leopoldo Alas "Clarín"";
                             ^^^^^^
SyntaxError: Unexpected identifier
    at Object.exports.runInThisContext (vm.js:53:16)
    at Object.<anonymous> ([stdin]-wrapper:6:22)
    at Module._compile (module.js:413:34)
    at node.js:544:27
    at _combinedTickCallback (node.js:370:9)
    at process._tickCallback (node.js:401:11)

简单的答案:

您没有使用引号

这首先由服务器端的 PHP 解析,因此 php 标签中的任何内容都将被渲染并返回到浏览器(这是解析 javascript 的浏览器):

<script>
var phpVars = <?php echo json_encode($vars); ?>;
</script>

在浏览器上生成的文本将是:

<script>
var phpVars = {"foo": "bar"};
</script>

如果您使用的是引号...

<script>
var phpVars = <?php echo "'" . json_encode($vars) . "'" ; ?>;
</script>

这将在浏览器上变成以下 html:

<script>
var phpVars = '{"foo": "bar"}';
</script>

那么在上面的情况下,你需要解析结果,因为只是一个字符串:

<script>
var phpVars = '{"foo": "bar"}';
vars = JSON.parse(phpVars);
//vars is now a JS valid object
</script>

所以答案是你的 php 正在回显一个文本,该文本实际上不会在 JS 中表示为字符串,而是作为对象表示法对象。JSON.parse 用于处理有效 JS 值(数组、对象、数字等)的字符串表示形式。