← PHP number_format() 函数 PHP parse_str() 函数 →

PHP ord()函数指南:ASCII字节转换、版本差异、常见陷阱与mb_ord对比

著
原创 2026-10-11 PHP 已有人查阅

ord()是什么,又不是什么

ord()的定义十分简洁:返回字符串第一个字节的无符号整数值,范围0到255。它接受的参数是字符串类型,返回整数。

<?php
echo ord("A");   // 65
echo ord("ABC"); // 65,只取第一个字节
echo ord("");    // 0(PHP 8 中空字符串返回 0)

ord()不感知任何字符编码。它在字节层面工作,与ASCII、UTF-8、GBK等编码概念无关。PHP文档在2009年前后将其描述从“ReturnASCIIvalueofcharacter”修正为“Cortthefirstbyteofastringtoavaluebetween0and255”,这一改动反映了社区对该函数真实行为的认知纠偏。

与chr()的互补关系

ord()的反函数是chr():给定0-255的整数,返回对应的单字节字符串。

<?php
// 验证往返一致性(参考 PHP 官方测试用例[citation:6])
for ($i = 0; $i < 256; $i++) {
    if (ord(chr($i)) !== $i) {
        throw new RuntimeException("Round-trip failed at byte {$i}");
    }
}

PHP源码中的ord_basic.phpt测试文件正是采用这种遍历方式验证函数的可靠性。实际业务中,这个往返特性可用于字节级数据校验,比如检测二进制协议中的魔数。

多字节字符的现实

这是使用ord()时最需要警惕的地方。UTF-8编码下,一个汉字通常占3个字节,Emoji可能占4个字节。ord()只返回第一个字节的值,而非字符的Unicode码点。

<?php
// 代码号学习PHP:理解 ord() 的字节行为
$str = "中";
var_dump(ord($str)); // int(228) —— UTF-8 首字节

$emoji = "X";
// PHP 官方测试用例展示了逐字节分析方式[citation:2]
for ($pos = 0; $pos < strlen($emoji); $pos++) {
    $byte = substr($emoji, $pos, 1);
    echo "Byte {$pos}: " . ord($byte) . "\n";
}
// Byte 0: 240
// Byte 1: 159
// Byte 2: 144
// Byte 3: 152

如果你需要获取一个UTF-8字符的完整码点,应使用mb_ord():

<?php
var_dump(mb_ord("X", "UTF-8")); // int(128024)

PHP版本差异

版本 行为变化
PHP4 函数已存在,文档描述为“返回ASCII值”
PHP5 行为无变化,文档逐步修正措辞
PHP7.2 mb_ord()引入,提供Unicode码点获取能力
PHP8.0 内部实现细节优化,空字符串返回0保持一致

ord()本身从PHP4到PHP8没有破坏性变更,参数类型始终为string。PHP8引入的严格类型模式对ord()影响有限,因为传入非字符串会被自动转换或触发TypeError。

单元测试与边界测试

基础功能测试:

<?php
// 代码号学习PHP:ord() 边界测试用例
$testCases = [
    ["A", 65],   // 大写字母
    ["z", 122],  // 小写字母
    ["0", 48],   // 数字
    ["!", 33],   // 标点
    ["\n", 10],  // 换行符
    ["\xFF", 255], // 最大字节
    ["", 0],     // 空字符串
];

foreach ($testCases as [$input, $expected]) {
    $actual = ord($input);
    assert($actual === $expected, 
        "ord('{$input}') expected {$expected}, got {$actual}");
}

边界测试:ord("\x00")返回0,ord("\xFF")返回255。PHP字符串可以包含空字节,ord()对此处理正常。

常见错误与异常处理

ord()本身几乎不抛出异常。它接受的参数会被强制转换为字符串,传入null在PHP8.1后会触发弃用警告。实践中常见错误是误以为它能处理多字节字符的完整码点:

<?php
// 错误用法:试图获取中文字符的 Unicode 码点
$code = ord("中"); // 228,不是 20013

// 正确方式
$code = mb_ord("中", "UTF-8"); // 20013

另一个易错点是空字符串的返回值。虽然PHP8中ord("")返回0,但这不应作为业务逻辑的判断依据,应当使用$str===""明确判断。

与相邻函数的职责对比

函数 职责 编码感知 适用范围
ord() 返回首字节值(0-255) 否 单字节编码、字节级操作
mb_ord() 返回首字符Unicode码点 是 多字节编码(UTF-8等)
IntlChar::ord() 返回Unicode码点 是 intl扩展可用时
bin2hex() 返回十六进制字节表示 否 字节级调试

IntlChar::ord()提供了另一种获取Unicode码点的方式,但依赖于intl扩展,在部分部署环境中可能不可用。

性能对比:ord() vs preg_replace

在字符串处理场景中,ord()常被与正则表达式对比。StackOverflow上有一个经典基准测试:将驼峰命名转换为下划线命名。

<?php
// 方案一:ord() 手动循环
function camelToSnakeOrd($str) {
    $result = '';
    $len = strlen($str);
    $ordA = ord('A');
    $ordZ = ord('Z');
    for ($i = 0; $i < $len; $i++) {
        $c = ord($str[$i]);
        if ($c >= $ordA && $c <= $ordZ) {
            $result .= '_' . strtolower($str[$i]);
        } else {
            $result .= $str[$i];
        }
    }
    return $result;
}

// 方案二:preg_replace
function camelToSnakePreg($str) {
    return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $str));
}

基准测试结果显示,preg_replace方案在100,000次调用中耗时约0.42秒,而ord()手动循环耗时约2.49秒。PCRE引擎的底层C实现比PHP层面的逐字节循环高效得多。

经验分享:在PHP项目中使用ord()做逐字节分析,通常出现在解析二进制协议、处理图像数据、实现自定义编码转换等场景。日常字符串格式化任务应优先考虑内置字符串函数或正则。ord()的价值在于字节级精确控制,而非通用字符处理。

现在框架中的惯用写法

现在PHP框架中直接调用ord()的场景并不多见。Laravel的Str类、Symfony的String组件都封装了更高层的字符操作方法。但在底层库中,ord()仍然活跃:

场景一:检测字符串是否为UTF-8BOM开头

<?php
// 代码号学习PHP:BOM 检测
function hasUtf8Bom(string $content): bool {
    return ord($content[0]) === 0xEF 
        && ord($content[1]) === 0xBB 
        && ord($content[2]) === 0xBF;
}

场景二:二进制协议帧头校验

<?php
// 检查协议帧是否以 0x7E 开始
function isValidFrameStart(string $frame): bool {
    return strlen($frame) > 0 && ord($frame[0]) === 0x7E;
}

常见误区速查

误区 实际行为
ord("中")返回中文字的Unicode码点 返回UTF-8首字节228
ord()能识别编码 基于字节,不感知编码
ord("")返回false或抛出错误 PHP8返回0
ord()与intval()等价 intval("ABC")返回0,ord("ABC")返回65
UTF-8下ord()的结果代表字符本身 仅代表首个字节的数值

延伸练习

练习一:编写一个函数,使用ord()判断字符串是否全部由可打印ASCII字符组成(字节值32-126)。

练习二:实现一个简化版UTF-8解码器,使用ord()逐字节解析并还原Unicode码点。提示:UTF-8首字节的高位比特模式决定了后续字节数。

练习三:对比ord()逐字节循环与unpack()在解析二进制数据时的性能差异。

参考文献

PHP官方手册:ord()
https://www.php.net/manual/en/function.ord.php
官方函数文档,包含函数原型、参数说明、返回值以及社区贡献的多字节处理替代方案。

PHP官方手册:mb_ord()
https://www.php.net/manual/en/function.mb-ord.php
多字节版本的ord函数,用于获取Unicode码点,PHP7.2+可用。

PHP源码测试:ord_basic.phpt
https://svn.php.net/viewvc/php/php-src/trunk/ext/standard/tests/strings/ord_basic.phpt
官方单元测试文件,展示了ord()的基本功能验证方法和往返一致性测试。

PHP文档修正记录
https://svn.php.net/viewvc/phpdoc/en/trunk/reference/strings/functions/ord.xml?r1=297028&r2=345229
文档描述从“ReturnASCIIvalueofcharacter”修正为“Cortthefirstbyteofastringtoavaluebetween0and255”的变更记录,反映了对函数本质的澄清。

StackOverflow:preg_replace与ord性能对比
https://stackoverflow.com/questions/3995338/preg-replace-versus-ord
实际基准测试数据,展示了逐字节PHP循环与PCRE正则引擎在字符串处理中的性能差距。

← PHP number_format()函数:数字格式化与舍入机制深度教程 PHP parse_str()函数指南:查询字符串解析、版本差异与安全边界 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号