PHP 解析 YAML 1.2:一个小“y”,引发的大困惑

PHP 解析 YAML 1.2:一个小“y”,引发的大困惑

image

本文编写于 2023 年,2025 年重构。

问题初现:当“y”不再是“y”,我真的懵了

故事的开端,源于 FastAdmin 的 QQ 高级群,有一位小伙伴焦急的提问:“我的YAML文件解析出错了,y 怎么变成了 1 呢?” 看着他发来的代码,我心头一紧,这可不是小问题啊!

size:
  x: 100
  y: 200

本以为能得到期待中的结果:

size:
  x: 100
  y: 200

结果却变成了:

size:
  x: 100
  1: 200  // 注意这里的键变化

那一刻,我感觉像是被一道闪电击中,一个简单的 y 键,怎么就变成了 1 呢? 这简直颠覆了我的认知,难道是解析器“喝醉”了?


深入分析:规范的“善意”,却成了埋藏的“坑”

我立刻着手排查。初步判断,很可能是解析器把 y自动转换成了布尔值。这个猜测让我立刻联想到YAML的官方规范。

当我翻开 YAML 1.1 的规范时,我发现了一个惊人的事实:

y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF

原来如此,YAML 1.1 对布尔值的定义是如此的宽泛yyeson 甚至都被认为是布尔值!那一刻,我真有点哭笑不得,这规范的“善意”——为了方便,却无形中埋下了一个大大的“坑”。怪不得会出现这种匪夷所思的转换,因为在某些解析器看来,y 确实可以被理解为 true,而 true 在某些语境下又可能被转换为 1

但紧接着,我发现了一个转机,在 GitHub 上,有人也曾为此“愤愤不平”,并提到 YAML 1.2 规范已经对布尔值进行了更严格的定义。(见附录 [1]

Since 1.0.0 we have removed support of automagic y => true conversion in the spirit of YAML 1.2 after some talks with YAML core developers.

我赶紧查阅了 YAML 1.2 的最新规范[2],果不其然,布尔值的范围被大大缩小了,只明确认可 trueTrueTRUEfalseFalseFALSE。这让我长舒一口气,这才是符合直觉的定义嘛。


寻找出路:PECL 的“执着”,Symfony 的“救赎”

既然规范升级了,那我们的 PHP 解析器呢?我满怀希望地去查看了 PHP PECL 扩展库的 php-yaml。然而,一个冰冷的事实摆在我面前:php-yaml 目前只支持 YAML 1.1 的解析! 原来我一直以为它的版本号代表着支持 YAML 规范的版本,这是一个巨大的误解。 它仅仅是 php-yaml 这个软件自身发布的版本号而已,目前(2025-05-30)这个组件的版本号为v2.2.4 [3],其内部的核心仍然停留在 YAML 1.1 时代。那一刻,我感觉自己像个“老古董”,用着过时的工具却不自知。

那如果想让 PHP 支持 YAML 1.2 怎么办?我陷入了沉思。幸运的是,柳暗花明又一村!通过不断的搜索,我找到了 symfony/yaml 这个 PHP Composer 组件。当我看到它的官方说明时,心中的石头终于落了地:[4]

Booleans
Booleans in YAML are expressed with true and false.

它明确说明支持 YAML 1.2,并且对布尔值的处理严格遵循新规范!这意味着,它不会再把小伙伴的 YAML 的 y 替换成 1 了。


尘埃落定:问题解决,心情豁然开朗!

最终,小伙伴在项目中引入了 symfony/yaml,替换掉原有的解析方式后,困扰他多时的问题迎刃而解!看着正确的解析结果,我们都感到无比的欣慰和轻松。

这次经历让我深刻体会到,即使是看似简单的字符,背后也可能隐藏着深层的规范差异和技术陷阱。 在开发中,多一份对规范的了解,多一份对工具的甄别,就能少踩很多不必要的“坑”。希望我的这次“探险”经历,也能帮助到同样遇到困惑的你。


后记:对 PECL php-yaml 扩展的一点思考

在解决了 y 键解析的“乌龙”之后,我开始思考一个更深层次的问题:为什么 PHP 的 PECL yaml 扩展至今仍未直接支持 YAML v1.2 规范呢?

我有一个猜想:这可能与 **YAML 自身版本迭代的“历史遗留问题”**有关。现在我们谈论软件版本,习惯了“语义化版本规范”(Semantic Versioning)[5],即通过版本号(主版本号、次版本号、修订号)来明确表示兼容性:主版本号的提升通常意味着不兼容的重大变更。

然而,YAML 1.1 到 YAML 1.2 的升级,似乎并没有完全遵循我们今天所理解的语义化版本规范。仔细分析 YAML 1.2 的变更,我们确实能发现一些不兼容的更新,比如文中提到的 y 被从布尔值列表中移除,就是一个典型的例子。这让我不禁猜测,在 YAML 1.1 和 YAML 1.2 发布之时,可能并没有一个严格的语义化版本共识。

因此,从某种程度上说,YAML v1.1 和 YAML v1.2 更像是两个独立但共用一个名字的规范,而非简单的兼容性升级。面对这种“断裂式”的规范演进,PECL php-yaml 扩展的维护者表现出了极大的谨慎。

我注意到,关于 PECL php-yaml 扩展支持 YAML 1.2 的 Issue[6] 至今仍然是开放状态,并且不时有人回复和关注。这说明维护者们并非不作为,而是在权衡支持新规范可能带来的兼容性风险。他们可能需要考虑如何优雅地处理这两个“不兼容”的 YAML 版本,既要满足用户对新特性的需求,又要避免引入新的混乱。这种维护者的审慎和责任感,其实是开源社区非常宝贵的品质。

附录


  1. 《Removed y to true》 https://github.com/nodeca/js-yaml/issues/42 ↩︎

  2. 《YAML 1.2 Spec》 https://yaml.org/spec/1.2.2/ ↩︎

  3. 《PECL PHP YAML》https://pecl.php.net/package/yaml ↩︎

  4. 《Booleans》 https://symfony.com/doc/current/reference/formats/yaml.html ↩︎

  5. 《语义化版本规范》 https://semver.org/lang/zh-CN/ ↩︎

  6. 《php PECL YAML v1.2 issue》 https://github.com/php/pecl-file_formats-yaml/issues/64 ↩︎

posted on 2025-05-30 09:32  建伟F4nniu  阅读(28)  评论(0)    收藏  举报

导航