如何将 PHP object array 转换为 JavaScript object array
结论
json_encode() 生成的 JSON 可以直接作为 JavaScript 表达式使用,因此直接赋值即可,无需放进双引号字符串后再调用 JSON.parse():
<script>
const portfolioData = <?= json_encode(
$serviceDetails,
JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
| JSON_HEX_QUOT
| JSON_THROW_ON_ERROR
) ?>;
</script>
执行这段代码后,portfolioData 是一个 JavaScript 数组,数组中的每个元素都是对象。
为什么会出现语法错误
原代码如下:
<script>
let portfolioData = JSON.parse("<?php echo $convertData; ?>");
</script>
PHP 输出 JSON 后,浏览器接收到的代码大致是:
let portfolioData = JSON.parse("[{"services_idno":1,"services_name":"Front-End Web Development"}]");
外层 JavaScript 字符串使用了双引号:
JSON.parse("...")
JSON 内部也有大量双引号。浏览器读到 "services_idno" 前面的双引号时,会将它视为外层字符串的结束位置,导致整行代码无法通过 JavaScript 语法解析,并报出:
Uncaught SyntaxError: missing ) after argument list
错误发生在 JavaScript 解析阶段,此时 JSON.parse() 还没有运行。
把外层引号换成单引号仍然不可靠,因为数据库内容可能包含 '、换行、反斜杠或 </script> 等特殊内容。
推荐写法:直接输出 JSON
<?php
$serviceDetails = Services::services_find_all();
?>
<script>
const portfolioData = <?= json_encode(
$serviceDetails,
JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
| JSON_HEX_QUOT
| JSON_THROW_ON_ERROR
) ?>;
console.log(portfolioData);
console.log(portfolioData[0].services_name);
</script>
生成的 JavaScript 大致如下:
const portfolioData = [
{
"services_idno": 1,
"services_name": "Front-End Web Development",
"services_desc": "We Can build a great looking website...",
"services_image": "front.webp"
}
];
JSON 本身是合法的 JavaScript 表达式,可以直接赋值,不需要 JSON.parse()。
JSON_HEX_* 选项用于处理可能影响内联 <script> 的字符。比如数据库内容中含有 </script> 时,未经处理的输出可能会让脚本元素提前结束。JSON_THROW_ON_ERROR 会在编码失败时抛出异常,避免程序静默得到 false 或无效输出。
如果确实需要使用 JSON.parse()
有些程序要求先把数据保存为字符串,再进行解析。这种情况下,应让 PHP 再执行一次字符串编码,而不是手工添加引号:
<?php
$serviceDetails = Services::services_find_all();
$json = json_encode(
$serviceDetails,
JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
| JSON_HEX_QUOT
| JSON_THROW_ON_ERROR
);
?>
<script>
const portfolioData = JSON.parse(
<?= json_encode(
$json,
JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
| JSON_HEX_QUOT
| JSON_THROW_ON_ERROR
) ?>
);
</script>
第二次 json_encode() 会把 JSON 文本编码成合法的 JavaScript 字符串。当前场景不需要这层转换,直接赋值更简单。
也可以把 JSON 放在独立元素中
数据量较大,或者需要把数据与执行代码分开时,可以使用 application/json:
<script type="application/json" id="portfolio-data">
<?= json_encode(
$serviceDetails,
JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
| JSON_HEX_QUOT
| JSON_THROW_ON_ERROR
) ?>
</script>
<script>
const jsonElement = document.getElementById('portfolio-data');
const portfolioData = JSON.parse(jsonElement.textContent);
console.log(portfolioData);
</script>
这种写法也建议保留 JSON_HEX_TAG,因为 HTML 解析器仍可能将数据中的 </script> 识别为元素的结束标签。
PHP 对象的属性要求
如果 $serviceDetails 中保存的是 PHP 对象,json_encode() 通常只能自动编码可访问的公共属性。例如:
class Service
{
public int $services_idno;
public string $services_name;
}
对于 private 或 protected 属性,可以先把对象转换为数组,也可以让类实现 JsonSerializable:
class Service implements JsonSerializable
{
private int $services_idno;
private string $services_name;
public function jsonSerialize(): array
{
return [
'services_idno' => $this->services_idno,
'services_name' => $this->services_name,
];
}
}
注意事项
- 不要通过字符串拼接手工转义 JSON。
- 不要用
htmlspecialchars()代替 JSON 编码来处理内联脚本中的 JSON。<script>内容采用不同的解析规则,HTML 实体可能不会按预期还原。 - 数据库连接应使用正确的 UTF-8 字符集。无效的 UTF-8 数据会导致
json_encode()失败,JSON_THROW_ON_ERROR可以及时暴露这个问题。 \/、\u2014等都是合法的 JSON 转义形式,解析后会分别还原为/和对应的 Unicode 字符。- 如果数据来自独立的 API 接口,接口应返回
Content-Type: application/json,前端通过response.json()读取,不需要把数据嵌入 HTML。
备注:内容仅供参考。
