首选json_decode处理嵌套结构或需原生类型(如布尔、null、浮点)的配置,因其类型保真度高;parse_ini_file仅适用于扁平化简单配置,但默认全返回字符串易引发数值比较错误。

parse_ini_file 和 json_decode 的选择依据
INI 适合简单配置(如开关、单层键值),JSON 更适合嵌套结构或需要数组/布尔原生类型的地方。PHP 7.4 对两者都完全兼容,但 json_decode 在类型保真度上更可靠——比如 true、null、大整数不会被转成字符串,而 parse_ini_file 默认全返回字符串,即使加 INI_SCANNER_TYPED 也对浮点和科学计数法支持有限。
常见错误现象:用 parse_ini_file 解析含 timeout = 30.5 的配置,结果是字符串 "30.5",后续做数值比较会出错;而 JSON 中的 "timeout": 30.5 经 json_decode($json, true) 后就是 float 类型。
- 选 INI:仅用于环境标识、数据库连接串等扁平化配置,且团队习惯手写 ini 文件
- 选 JSON:涉及权限树、API 路由映射、多级 credential 列表等结构,或需与前端共享同一份配置 schema
- 别混用:同一项目中不要一部分用 INI、一部分用 JSON,维护成本陡增
json_decode 安全解析必须做的三件事
json_decode 看似一行调用,但跳过检查就等于把门敞给 malformed 数据。PHP 7.4 没改这个逻辑,错误仍静默返回 null,不抛异常。
- 必须用
file_get_contents读取后先校验是否失败:if (false === $raw) { throw new RuntimeException('Cannot read config.json'); } - 必须检查解码结果:
if (null === $cfg && JSON_ERROR_NONE !== json_last_error()) { throw new InvalidArgumentException('Invalid JSON: ' . json_last_error_msg()); } - 必须限定深度:尤其当配置来自用户上传或第三方 API 时,加
512参数防栈溢出(PHP 7.4 默认就是 512,但显式写出更稳妥)
示例片段:
立即学习“PHP免费学习笔记(深入)”;
$path = __DIR__ . '/config.json';
$raw = file_get_contents($path);
if (false === $raw) {
throw new RuntimeException("Failed to read $path");
}
$cfg = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
注意:JSON_THROW_ON_ERROR 是 PHP 7.3+ 才有,PHP 7.4 可用,但它会让错误直接抛出异常,省去手动查 json_last_error() ——前提是你的错误处理机制能接住它。
写入 JSON 配置文件时的权限与原子性陷阱
Nginx + PHP-FPM 环境下,file_put_contents('config.json', json_encode($data)) 表面没问题,实际极易出错:500 错误、空白页、配置被截断、并发写入损坏文件。
- 路径必须绝对:
__DIR__ . '/config.json',避免相对路径在 CLI / Web 下行为不一致 - 权限要提前设好:确保 PHP 进程用户(如
www-data)对目录有写权限,文件本身建议644,目录755;别用777 - 必须原子写入:用
file_put_contents($path, $content, LOCK_EX)加锁;更稳妥的是写临时文件再rename(),因为rename()在同一文件系统下是原子操作 - 编码要显式指定:
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),否则中文变 \uXXXX,格式混乱难调试
典型安全写法:
$temp = tempnam(sys_get_temp_dir(), 'cfg_');
if (false === file_put_contents($temp, json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX)) {
unlink($temp);
throw new RuntimeException('Failed to write temp config');
}
if (false === rename($temp, __DIR__ . '/config.json')) {
unlink($temp);
throw new RuntimeException('Failed to replace config.json');
}
PHP 7.4 特有坑:大整数精度丢失与 nullsafe 运算符误用
PHP 7.4 没修复 JSON 大整数问题——超过 PHP_INT_MAX(通常是 263−1)的数字会被转成 float,精度丢失。例如 ID 9223372036854775808 解码后变成 9.2233720368548E+18,再转回字符串就不是原值。
- 解决方案:始终传
JSON_BIGINT_AS_STRING给json_decode,确保大整数进数组后仍是字符串 - 别依赖
?->做配置访问:比如$cfg?->database?->host,但$cfg是数组而非对象——?->只对对象有效,数组要用??或isset() - 类型声明没帮你兜底:即使函数参数写了
array $cfg,json_decode返回null时也不会触发 TypeError,得靠前面的错误检查来拦截
真正安全的访问方式:
$host = $cfg['database']['host'] ?? 'localhost';
// 或更严谨
if (!isset($cfg['database']['host'])) {
throw new InvalidArgumentException('Missing database.host in config');
}
复杂点在于:JSON 配置的“正确性”无法靠 PHP 类型系统静态保证,必须靠运行时校验 + 显式默认值兜底。没人会为 config 写完整 schema 验证,但至少该 check 的 key 一个都不能少。



















