一、chr()做了什么
chr()接收一个整数,返回该整数对应ASCII码值的一个字符。返回值是一个单字节字符串。
语法:
string chr ( int $bytevalue )
| 参数 | 说明 | 是否必填 |
|---|---|---|
| bytevalue | ASCII码值,整数 | 必填 |
核心逻辑很直接:给一个数字,还一个字符。它是ord()的逆操作,ord()把字符转成ASCII码值,chr()把码值还原成字符。
这里有一个容易被忽略的点:chr()返回的是单字节字符串。ASCII范围是0到255,超出这个范围的值会被按256取模处理。也就是说,chr(300)等价于chr(300%256),结果是chr(44),即逗号。这一点在多字节字符场景下会带来困惑——你不能用chr()生成一个汉字,因为汉字在UTF-8下占3个字节。
关键词提示:PHPchr函数、ASCII转字符、ord逆操作、单字节字符串。
二、参数的三种进制写法
PHP的整数支持十进制、八进制、十六进制三种字面量写法,chr()的参数同样适用。不同写法传入的是同一个数值,结果一致。
十进制写法
<?php
$char = 52;
echo "原始数值:" . $char . "<br>";
echo "chr() 结果:" . chr($char);
?>
输出:
原始数值:52
chr() 结果:4
十进制52对应字符4。
八进制写法
八进制以0开头。
<?php
$char = 052;
echo "原始数值:" . $char . "<br>";
echo "chr() 结果:" . chr($char);
?>
输出:
原始数值:42
chr() 结果:*
注意这里的输出细节:$char=052是八进制写法,PHP在字符串拼接时会把它按十进制显示为42。八进制52等于十进制42,对应字符*。如果不了解进制前缀规则,看到输出42却得到*,会感到莫名其妙。
十六进制写法
十六进制以0x开头。
<?php
echo "原始数值:0x52<br>";
echo "chr() 结果:" . chr(0x52);
?>
输出:
原始数值:0x52
chr() 结果:R
十六进制0x52等于十进制82,对应字符R。
三种写法汇总:
| 写法 | 字面量 | 十进制值 | 对应字符 |
|---|---|---|---|
| 十进制 | 52 | 52 | 4 |
| 八进制 | 052 | 42 | * |
| 十六进制 | 0x52 | 82 | R |
踩坑经历:早期在解析一个协议文档时,文档里写的是0x0A,我顺手写成chr(0A),结果PHP把0A当成八进制解析,报语法错误。十六进制必须带0x前缀,八进制是前导0,十进制不带前缀,这个规则在chr()参数上同样适用,写的时候多看一眼。
三、用chr()拼接可读输出
chr()的一个实用场景是生成那些键盘上不好直接输入、或者需要动态计算的字符。
<?php
$plus = chr(43); // +
$equal = chr(61); // =
echo "2 $plus 2 $equal 4";
?>
输出:
2 + 2 = 4
ASCII43是加号,61是等号。这种写法在生成表达式、构造动态提示文本时可以用,但说实话,能用字面量'+'和'='直接写的地方,没必要绕一圈用chr()。chr()的价值在于数值是动态计算出来的时候,而不是写死一个已知字符。
更合理的用法是这样:
<?php
// 根据数值动态生成对应的字母
for ($i = 65; $i <= 70; $i++) {
echo chr($i) . " ";
}
?>
输出:
A B C D E F
ASCII65到90是大写字母A到Z,97到122是小写字母a到z。需要按序号生成字母时,chr()比维护一个字母表数组更省事。
四、chr()与ord()的互逆关系
ord()返回字符串第一个字节的ASCII码值,是chr()的反向操作。
<?php
$char = 'A';
$code = ord($char);
echo "字符 A 的 ASCII 码值:" . $code . "<br>";
echo "码值 65 还原为字符:" . chr($code);
?>
输出:
字符 A 的 ASCII 码值:65
码值 65 还原为字符:A
两者的对照关系:
| 函数 | 输入 | 输出 |
|---|---|---|
| ord() | 字符(取首字节) | ASCII码值 |
| chr() | ASCII码值 | 单字节字符 |
注意ord()只取第一个字节。对于UTF-8中文,ord("中")返回的是第一个字节的值,不是完整的码点。要处理多字节字符,需要用mb_ord()配合mb_chr(),这是另一组函数。
个人建议:单字节场景用chr()/ord(),多字节场景用mb_chr()/mb_ord()。混用会导致中文处理出问题,这个分界线要划清楚。
五、项目场景
场景一:生成控制字符
换行、制表符、回车这些控制字符,可以用chr()生成,也可以用转义序列\n、\t、\r。两者等价,但动态场景下chr()更灵活。
<?php
$lf = chr(10); // \n 换行
$tab = chr(9); // \t 制表符
echo "第一行" . $lf . "第二行" . $tab . "制表位";
?>
在拼接来自配置文件的控制字符码值时,chr()让代码保持数值驱动。
场景二:按码值表生成字符集
验证码字符集、测试数据生成器等场景,需要按ASCII区间批量产出字符。
<?php
$chars = '';
for ($i = 48; $i <= 57; $i++) {
$chars .= chr($i);
}
echo "数字字符集:" . $chars;
?>
输出:
数字字符集:0123456789
ASCII48到57是数字0到9。
场景三:协议数据构造
在拼接自定义二进制协议时,某些字段需要按字节值填充。
<?php
$header = chr(0x02) . chr(0x01) . chr(0x00);
echo "协议头 hex:" . bin2hex($header);
?>
输出:
协议头 hex:020100
用chr()生成字节,再用bin2hex()观察结果,是调试协议数据的常见组合。这里chr()配合bin2hex()比直接拼字符串更可控。
反思:曾经在一个串口通信项目里,同事直接把数值强转成字符串拼接,0x02变成了字符"2",协议解析全乱。字节值要用chr()生成,不能用数值的字符串形式,这个区别在处理二进制协议时必须分清。
六、本节课程知识要点
-
chr()由ASCII码值返回单字节字符,是ord()的逆操作。
-
参数支持十进制、八进制(前导0)、十六进制(0x前缀)三种写法。
-
超出0-255范围的值按256取模处理。
-
chr()只生成单字节,多字节字符需用mb_chr()。
-
动态生成字母、数字、控制字符时用chr()比维护字符表更简洁。
-
处理二进制协议字节时,用chr()生成而非数值强转字符串。
七、常见问题
Q:chr(0)返回什么?
A:返回NUL字节,是一个长度为1的字符串,不是空字符串。strlen(chr(0))等于1。这个区别在比较和拼接时要注意。
Q:为什么chr(300)不报错?
A:PHP对超出范围的值按256取模,chr(300)等价于chr(44),返回逗号。这是历史行为,不是错误。
Q:chr()能生成中文吗?
A:不能直接生成。UTF-8下一个汉字占3个字节,需要拼接3次chr()或者用mb_chr()。直接用chr()传一个汉字的Unicode码点,结果不会正确。
chr()是PHP中处理单字节字符与码值转换的基础函数,逻辑简单,但进制写法、取模行为、单字节限制这几个边界需要清楚。它适合动态生成字母、数字、控制字符以及协议字节,配合ord()可以完成字符与码值的双向转换。遇到多字节字符时,切换到mb_chr()/mb_ord()这一组函数。写代码时先判断场景是单字节还是多字节,再选函数,能避免不少隐蔽问题。