PHP7.0字符串进阶技巧有哪些

发布时间:2026/10/18 15:03:19
PHP7.0字符串进阶技巧有哪些
前言PHP 7.0 发布于 2015 年 12 月它不是一个字符串版本但恰恰在字符串处理上带来了几个影响深远的变化一个是新增了 Unicode 码点转义\u{}另一个是把一大批古老的字符串函数ereg、split、mysql_*直接移除。前者常被忽略后者是老项目迁移时最痛的一刀。典型症状有三类升级到 7.0 后老代码大面积报Call to undefined function ereg()在 7.0 环境里照着新文章写str_contains()同样报未定义函数那是 PHP 8.0 才有的用strlen()统计中文长度得到的数字永远比实际字数大两倍。本文梳理 PHP 7.0 上真正可用、且值得用的字符串技巧码点转义、随机令牌、批量正则回调、多字节处理的正确姿势、??与字符串下标以及declare(strict_types1)对字符串参数的副作用。文中的示例最低版本 PHP 7.0可直接运行。一、\u{}码点转义7.0 新增的字符串能力PHP 7.0 之前想在字符串里写一个 Unicode 码点只能先算出 UTF-8 字节再用\x拼或者干脆把字符复制进去。7.0 加入了\u{十六进制}语法$hello \u{4F60}\u{597D}; // 你好$emoji \u{1F600};两条必须记住的规则只能用在双引号字符串和 heredoc 里单引号和 nowdoc 中会原样输出\u{4F60}这七个字符大括号是必须的写你不会被识别。它和json_decode处理的\uXXXX固定四位、不需要大括号是两套不同语法别混用。二、7.0 新增的几件趁手工具除了码点转义7.0 还给字符串相关任务补了几块短板函数 / 语法用途备注random_bytes()/random_int()生成密码学安全的随机字节 / 整数7.0 新增替代mt_rand()做令牌preg_replace_callback_array()一次配置多组正则 回调7.0 新增替代多个preg_replace_callback??空合并运算符$conf[k] ?? default7.0 新增对未定义下标不报 Notice太空船运算符排序比较7.0 新增常用于usortunserialize($s, [allowed_classes false])限制反序列化可实例化的类7.0 新增第二参数intdiv()整除7.0 新增与字符串无关但常一起用要特别提醒两个不属于7.0 的常见误传hash_equals()和password_hash()分别是 5.6 和 5.5 就有的不是 7.0 新特性而str_contains()/str_starts_with()/str_ends_with()要等到PHP 8.0在 7.0 上必须用strpos()/strncmp()/substr_compare()手工实现。三、多字节字符串7.0 上的正确写法PHP 的字符串是字节数组strlen()数的是字节数。你好是 6 字节strlen()返回 6 而不是 2。7.0 上处理 UTF-8 字符串的正确工具是mb_*系列与带/u修饰符的 PCRE取长度mb_strlen($s, UTF-8)截取mb_substr($s, 0, 10, UTF-8)拆成单字符数组不要用mb_str_split()它要 PHP 7.4 才有。7.0 上的写法是preg_split(//u, $s, -1, PREG_SPLIT_NO_EMPTY)大小写mb_strtolower()/mb_strtoupper()注意它们不做完整的区域化折叠如德语 ß正则给模式加/u否则.会按字节匹配中文会被拆成半个字符。四、完整可运行示例?php// 最低版本PHP 7.0declare(strict_types1);// 1) 码点转义只能写在双引号或 heredoc 中$greeting \u{4F60}\u{597D};$emoji \u{1F600};echo $greeting, $emoji, PHP_EOL; // 你好// 2) 生成令牌不要再自己拼 rand()$token bin2hex(random_bytes(32)); // 64 个十六进制字符echo strlen($token), PHP_EOL; // 64// 3) 一次配置多条替换规则$text 联系方式138-0000-0001邮箱 adaexample.com;$masked preg_replace_callback_array([/\b(\d{3})-(\d{4})-(\d{4})\b/ static function (array $m): string {return $m[1] . -****- . $m[3];},/\b([\w.])([\w.])\b/ static function (array $m): string {return substr($m[1], 0, 1) . *** . $m[2];},], $text);echo $masked, PHP_EOL; // 联系方式138-****-0001邮箱 a***example.com// 4) 多字节长度、截取、拆字符$cn 你好世界;echo strlen($cn), PHP_EOL; // 12字节echo mb_strlen($cn, UTF-8), PHP_EOL; // 4字符echo mb_substr($cn, 1, 2, UTF-8), PHP_EOL; // 好世// mb_str_split() 要 PHP 7.47.0 用 preg_split$chars preg_split(//u, $cn, -1, PREG_SPLIT_NO_EMPTY);echo count($chars), PHP_EOL; // 4echo implode(/, $chars), PHP_EOL; // 你/好/世/界// 5) ?? 让配置读取不再报 Notice$conf [];$env $conf[env] ?? production;$port (int) ($conf[port] ?? 8080);echo $env, :, $port, PHP_EOL; // production:8080// 6) 限制反序列化可实例化的类$payload serialize(new stdClass());$restored unserialize($payload, [allowed_classes false]);var_dump($restored instanceof __PHP_Incomplete_Class); // bool(true)// 7) 8.0 才有的函数在 7.0 上必须手工替代$haystack php-7.0-string-tips;$needle string;var_dump(strpos($haystack, $needle) ! false); // bool(true)var_dump(strncmp($haystack, php, 3) 0); // bool(true)这段代码覆盖了 7.0 上最实用的几个点。注意第 7 项str_contains()在 7.0 上会直接Fatal error而strpos()的返回值在匹配位置为 0时是0用if (strpos(...))判断会把开头就匹配误判为没找到——这是最经典的坑必须用! false。常见坑点1. 在 7.0 上调用 8.0 才有的字符串函数❌str_contains($h, $n)/str_starts_with($h, $n)——Call to undefined function整站 500。抄来的代码片段常常不标注版本。 ✅ 7.0 写法strpos($h, $n) ! false、strncmp($h, $n, strlen($n)) 0、substr_compare($h, $n, -strlen($n)) 0。2. 用strpos()的返回值直接做布尔判断❌if (strpos($h, $n)) { ... }——匹配位置是 0 时返回0判断为假于是以关键词开头的记录全部漏掉。 ✅ 一律! false。3. 在 7.0 上用mb_str_split()❌ 那是 PHP 7.4 才加入的函数7.0/7.1/7.2/7.3 都报未定义。 ✅preg_split(//u, $s, -1, PREG_SPLIT_NO_EMPTY)记得加/u空字符串会返回空数组。4. 还在用 7.0 已经移除的老函数❌ereg(^[0-9]$, $s)、split(,, $s)、mysql_query()——PHP 7.0 中这些已被删除不是弃用而是彻底不存在。 ✅preg_match(/^[0-9]$/D, $s)、explode(,, $s)、mysqli/PDO。5. 用mt_rand()生成密码重置令牌❌md5(mt_rand())——mt_rand是可预测的伪随机数令牌可被枚举。 ✅bin2hex(random_bytes(32))7.0 新增要用整型随机数则random_int(1, 100)。6. 用strlen()判断字符数❌if (strlen($nickname) 10)想限制十个字中文昵称三个字就被拒绝。 ✅mb_strlen($nickname, UTF-8)。反过来做存储长度校验如VARCHAR(255)时要用strlen()数字节。7. 在单引号里写\u{}❌\u{4F60}——单引号字符串不做转义解析页面上直接显示出这七个字符。 ✅ 用双引号或 heredoc同时注意双引号里的$需要转义。8.htmlspecialchars()不传编码❌htmlspecialchars($input)——依赖default_charset与默认 flags输出编码不确定另外要记住 PHP 8.1 起默认 flags 变成了ENT_QUOTES | ENT_SUBSTITUTE7.0 上默认是ENT_COMPAT不转义单引号。 ✅ 在 7.0 上显式写全htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, UTF-8)。总结技巧引入版本关键点\u{}码点转义PHP 7.0只能在双引号 / heredoc 中random_bytes()/random_int()PHP 7.0替代mt_rand生成令牌preg_replace_callback_array()PHP 7.0一组规则一次替换??空合并PHP 7.0读数组下标不再报 Noticepreg_split(//u, ...)拆字符一直可用7.4 之前没有mb_str_split()str_contains()/str_starts_with()PHP 8.07.0 上必须用strpos/strncmp替代ereg/split/mysql_*7.0 已移除迁移时最容易集中爆发在 PHP 7.0 上写字符串代码核心就两句话用mb_*和/u处理多字节用! false处理查找。把版本边界记清楚\u{}与random_bytes是 7.0 的、mb_str_split是 7.4 的、str_contains是 8.0 的就不会再被函数不存在和中文长度不对这两类问题反复绊住。