☰
Twig `is odd` 奇偶测试:语法、源码实现与沙箱安全用法详解
2026/9/26 7:58:59 网站建设 项目流程
  • 后端

【免费下载链接】Twig

Twig, the flexible, fast, and secure template language for PHP

项目地址:https://gitcode.com/gh_mirrors/tw/Twig
点击查看免费下载

导读

odd是 Twig 模板语言内置的一个数值测试(test),用于判断给定数字是否为奇数。本文以 doc/tests/odd.rst 为骨架,结合 Twig 源码中OddTest节点的编译实现、核心扩展注册逻辑与官方集成测试,完整讲解{{ var is odd }}的语法、底层求值原理、与even、divisible by的关系、负奇数等边界情况,以及它在沙箱(sandbox)模式下的可用性。读完本文,你将能在自己的 Twig 模板中准确、安全地使用奇偶判断。

odd测试的语法与基本语义

在 Twig 中,测试(tests)通过is操作符与变量结合使用。odd测试的语义非常直观:

当给定数字是奇数时,odd返回true。

官方文档 doc/tests/odd.rst 给出的最小示例为:

{{ var is odd }}

该表达式会输出true或false(Twig 中布尔值渲染为1或空字符串,实际显示效果取决于输出上下文)。同样地,odd也可以配合否定形式使用:

{% if var is not odd %} 数字是偶数 {% endif %}

完整可运行的模板示例

{% set var = 7 %} {{ var is odd ? '奇数' : '偶数' }} {# 输出:奇数 #} {% set var = 8 %} {{ var is odd ? '奇数' : '偶数' }} {# 输出:偶数 #}

该测试典型应用于列表分栏、隔行变色、栅格布局奇偶列渲染等需要按序数区分两组的场景:

{% for item in items %} <tr class="{{ loop.index is odd ? 'odd-row' : 'even-row' }}"> <td>{{ item }}</td> </tr> {% endfor %}

源码级原理:OddTest节点的编译实现

odd不是一个普通的回调式测试,而是 Twig 核心扩展中一个以专属节点类实现的测试。在 src/Extension/CoreExtension.php 中,它被注册为:

new TwigTest('even', null, ['node_class' => EvenTest::class, 'always_allowed_in_sandbox' => true]), new TwigTest('odd', null, ['node_class' => OddTest::class, 'always_allowed_in_sandbox' => true]),

关键点有两个:

  1. node_class指定专用节点:odd由 src/Node/Expression/Test/OddTest.php 处理,编译阶段直接生成内联的 PHP 求值代码;
  2. always_allowed_in_sandbox为true:即使开启沙箱模式,odd也始终被允许使用(详见下文沙箱章节)。

底层求值:取模运算

OddTest继承自TestExpression,其核心逻辑在compile()方法中(见 src/Node/Expression/Test/OddTest.php):

public function compile(Compiler $compiler): void { $compiler ->raw('(') ->subcompile($this->getNode('node')) ->raw(' % 2 != 0') ->raw(')') ; }

也就是说,模板中的{{ var is odd }}在编译后等价于 PHP 表达式:

($var % 2 != 0)

即“对 2 取模后不等于 0”。对比来看,src/Node/Expression/Test/EvenTest.php 中even的编译结果为(node % 2 == 0),两者互为镜像,odd恰好是even的补集。

类型强转约束

值得注意的一个细节是,OddTest还实现了getStringCoercedChildNames()并返回空数组(见 src/Node/Expression/Test/OddTest.php),注释明确说明:

PHP%rejects Stringable with a TypeError, no coercion

这意味着:由于底层直接使用 PHP 的取模运算符%,如果传入一个实现了Stringable(可转字符串)的对象,PHP 会抛出TypeError而不会进行字符串强转。因此odd的入参应当是真正的数值类型,模板中应避免把对象或非数值字符串传给该测试。

与even、divisible by的关系

odd在官方文档中与even测试互为“参见”关系:doc/tests/odd.rst 的seealso一节指向 doc/tests/even.rst,后者同样回指odd。

三者可归纳为:

测试语义等价表达式
odd数字为奇数num % 2 != 0
even数字为偶数num % 2 == 0
divisible by数字可被某数整除num % n == 0

因此可以推导出以下等价写法:

{{ var is odd }} {# 等价于 #} {{ var is not even }} {# 等价于 #} {{ var is not divisible by(2) }} {# 若数字为整数 #}

三者覆盖了奇偶判断与整除判断的全部常见需求,开发者可根据可读性选择最贴切的表达。

官方集成测试验证

Twig 仓库为odd提供了专门的集成测试用例 tests/Fixtures/tests/odd.test,覆盖了正奇数、偶数与负奇数三类输入:

{{ 1 is odd ? 'ok' : 'ko' }} {{ 2 is odd ? 'ko' : 'ok' }} {{ -1 is odd ? 'ok' : 'ko' }}

对应的期望输出为:

ok ok ok

该用例证实了两个事实:

  1. 1判定为奇数、2判定为偶数,基础语义正确;
  2. 负数同样参与奇偶判定:-1的-1 % 2在 PHP 中结果为-1(非 0),因此被正确判定为奇数——这也说明基于取模的实现对负数同样成立,无需额外的绝对值处理。

在 tests/Extension/CoreTest.php 中还可以看到odd被列为 Core 扩展提供的测试之一,确认其属于 Twig 核心内置能力,开箱即用,无需引入任何额外扩展。

沙箱模式下的安全性

由于odd被注册时显式声明了always_allowed_in_sandbox => true(见 src/Extension/CoreExtension.php),它在沙箱环境中属于白名单默认放行的测试。Twig 的沙箱测试用例 tests/Extension/SandboxTest.php 中即包含:

yield ['{{ 3 is odd ? "y" }}'];

这表示在启用沙箱的模板里,{{ 3 is odd ? "y" }}仍可正常求值,不会被安全策略拦截。这一点对在沙箱中渲染用户提交模板的场景很重要:奇偶判断属于纯数值运算,不涉及方法调用、属性访问或任何外部副作用,因此被设计为始终允许。

实用小结

  • {{ var is odd }}返回true当且仅当var是奇数,底层编译为 PHP 的(var % 2 != 0);
  • 与even互补,与divisible by(2)等价(对整数而言);
  • 支持负数判定;入参应为数值,向Stringable对象传入会触发TypeError;
  • 属于核心扩展内置测试(src/Extension/CoreExtension.php),并在沙箱中默认放行;
  • 官方集成测试见 tests/Fixtures/tests/odd.test,可作为行为基准。

至此,你已完整掌握 Twigodd测试的语法、实现原理与安全边界,可以在模板开发与沙箱配置中放心使用。

  • 后端

【免费下载链接】Twig

Twig, the flexible, fast, and secure template language for PHP

项目地址:https://gitcode.com/gh_mirrors/tw/Twig
点击查看免费下载
上一篇:3种场景解决方案:QMCDecode让加密音乐解锁成为可能
下一篇:深入浅出Per-CPU变量:一文看懂Linux内核的多核无锁加速术

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询