第七章-PHP字符串操作
PHP字符串操作
一,字符串定义语法
1. 单引号字符串(Single-Quoted Strings)
语法
$str = '这是一个单引号字符串';
特点
-
不解析变量
单引号内的内容会被原样输出,变量和转义字符(除\\
和\'
外)不会被处理。$name = "PHP"; echo 'Hello, $name!'; // 输出:Hello, $name!
-
支持的转义符
仅支持两种转义:\\
→ 反斜杠\'
→ 单引号
echo '路径:C:\\xampp\\htdocs'; // 输出:路径:C:\xampp\htdocs
-
性能优势
由于无需解析变量和复杂转义,单引号字符串在无变量时性能略优。
2. 双引号字符串(Double-Quoted Strings)
语法
$str = "这是一个双引号字符串";
特点
-
解析变量
直接嵌入变量名,变量值会被替换:$fruit = "apple"; echo "I like $fruit!"; // 输出:I like apple!
-
复杂变量语法
使用{}
明确变量边界,避免歧义:$type = "果汁"; echo "这是{$type}的瓶子"; // 输出:这是果汁的瓶子
-
支持丰富的转义字符
转义符包括:\n
→ 换行\t
→ 制表符\"
→ 双引号\$
→ 美元符号\x1A
→ 十六进制 ASCII 字符
echo "第一行\n第二行\t制表符";
3. Heredoc 结构(多行字符串)
语法
$str = <<<EOD
多行内容
可以包含变量和转义符
EOD;
规则
-
标识符命名
必须遵循变量命名规则(字母、数字、下划线,不能以数字开头),常用EOD
、EOF
等。 -
结束标记
必须单独一行、顶格书写,且以分号结束:// 正确 $html = <<<HTML <div> <p>$content</p> </div> HTML; // 错误!结束标记缩进 $html = <<<HTML <div></div> HTML;
-
行为类似双引号字符串
解析变量和转义符,适合嵌入 HTML 模板或长文本:$user = "Alice"; echo <<<MSG 欢迎,$user! 您的订单已确认。 MSG;
4. Nowdoc 结构(单引号多行字符串)
语法
$str = <<<'EOD'
内容不解析变量和转义符(除 \\ 和 \')
EOD;
规则
-
标识符需单引号包裹
<<<'EOD'
表示 Nowdoc 结构。 -
行为类似单引号字符串
变量和转义符(如\n
)不会被处理:$count = 10; echo <<<'TEXT' 当前计数:$count\n TEXT; // 输出:当前计数:$count\n
变量解析的详细规则
简单语法
直接写变量名,适用于变量后无歧义字符:
$drink = "coffee";
echo "I need $drink!"; // 输出:I need coffee!
复杂语法(花括号)
通过 {}
明确变量边界:
-
避免歧义
$var = "cat"; echo "这是${var}s"; // 输出:这是cats
-
解析数组或对象属性
$arr = ["key" => "value"]; echo "数组值:{$arr['key']}"; // 输出:数组值:value
-
动态变量名
$prop = "name"; echo "属性是:${$prop}"; // 等价于 $name
实际应用场景
-
单引号
-
静态文本(如配置键名)
-
无需转义的简单路径:
$path = 'C:\xampp\htdocs\file.txt';
-
-
双引号
-
含变量或转义符的动态文本:
$error = "404"; echo "错误代码:$error\n请检查输入。";
-
-
Heredoc
-
多行 HTML 模板:
$html = <<<HTML <table> <tr><td>$username</td></tr> </table> HTML;
-
-
Nowdoc
-
保留原始格式的文档(如 SQL 语句):
$sql = <<<'SQL' SELECT * FROM users WHERE id = 1; SQL;
-
注意事项
- 性能差异
单引号/Nowdoc 在无变量时略快,但差异可忽略不计,优先考虑代码可读性。 - 转义字符优先级
双引号中的\$
表示字面量$
,而单引号中的\'
表示单引号。 - 多行字符串缩进
Heredoc/Nowdoc 的内容可以缩进,但结束标记必须顶格。
错误示例与修正
错误:Heredoc 结束标记未顶格
// 错误!
$str = <<<EOD
内容...
EOD;
修正:
$str = <<<EOD
内容...
EOD;
二,字符串的转义符
1. 单引号字符串的转义
单引号字符串仅支持两种转义,其他字符前的反斜杠会被原样输出:
\\
→ 表示单个反斜杠\
\'
→ 表示单引号'
示例:
echo '路径:C:\\xampp\\htdocs'; // 输出:路径:C:\xampp\htdocs
echo '这是一个单引号:\''; // 输出:这是一个单引号:'
echo '换行符\n不会被转义'; // 输出:换行符\n不会被转义
2. 双引号字符串的转义
双引号字符串支持丰富的转义字符,包括:
转义符 | 含义 |
---|---|
\" | 双引号 " |
\\ | 反斜杠 \ |
\$ | 美元符号 $ (避免变量解析) |
\n | 换行符(ASCII 10) |
\r | 回车符(ASCII 13) |
\t | 水平制表符(Tab) |
\v | 垂直制表符 |
\e | Escape 键(ASCII 27) |
\f | 换页符(ASCII 12) |
\xHH | 十六进制 ASCII 字符(如 \x1A ) |
\u{XXXX} | Unicode 字符(如 \u{1F600} 表示😀) |
示例:
echo "双引号:\",换行符:\n,制表符:\t,美元符号:\$";
// 输出:
// 双引号:",换行符:
// ,制表符: ,美元符号:$
3. Heredoc 结构的转义
Heredoc 的行为与双引号字符串一致,支持双引号的所有转义规则,同时允许直接嵌入变量。
示例:
$var = "World";
echo <<<EOD
Hello, $var!\n转义符:\t、\x40(@)、\u{2665}(♥)
EOD;
// 输出:
// Hello, World!
// 转义符: 、@、♥
4. Nowdoc 结构的转义
Nowdoc 的行为与单引号字符串一致,仅支持两种转义:
\\
→ 反斜杠\
\'
→ 单引号'
(但 Nowdoc 本身用单引号包裹标识符,内部单引号无需转义)
示例:
echo <<<'EOT'
这是一个 Nowdoc 字符串:
反斜杠:\\,单引号:',换行符\n原样输出。
EOT;
// 输出:
// 这是一个 Nowdoc 字符串:
// 反斜杠:\,单引号:',换行符\n原样输出。
常见场景与注意事项
场景 1:输出字面量 $
或 "
在双引号字符串中,若需输出 $
或 "
,必须转义:
echo "价格:\$100"; // 输出:价格:$100
echo "引号:\""; // 输出:引号:"
场景 2:多行文本中的转义
Heredoc 适合编写多行文本并保留转义效果:
echo <<<XML
<root>
<node>\t内容</node> <!-- 转义为制表符 -->
</root>
XML;
场景 3:动态生成正则表达式
需转义正则符号(如 /
或 \
):
$pattern = "/^\\d+$/"; // 等价于 "/^\d+$/"
错误示例:
// 错误!未转义 $,导致解析变量
echo "价格:$100"; // 尝试解析变量 $100(未定义)
// 正确写法:
echo "价格:\$100"; // 输出:价格:$100
总结表
字符串类型 | 支持的转义符 |
---|---|
单引号 | \\ , \' |
双引号 | \" , \\ , \$ , \n , \r , \t , \xHH , \u{XXXX} 等 |
Heredoc | 同双引号 |
Nowdoc | 同单引号 |
最佳实践
- 优先单引号:当无需变量解析和复杂转义时,使用单引号提高可读性和性能。
- 明确变量边界:在双引号或 Heredoc 中,用
{}
包裹变量名(如"{$var}"
)。 - 避免过度转义:在单引号字符串中,除了
\\
和\'
,其他反斜杠无需转义。
三,字符串长度
在 PHP 中,字符串长度的处理与字符编码密切相关,尤其是在处理多字节字符(如中文、Emoji 等)时需要注意细节。以下是字符串长度相关知识的详细说明:
1. 获取字符串长度的函数
PHP 提供了两个常用函数来获取字符串长度:
strlen()
返回字符串的字节数(基于当前字符编码)。mb_strlen()
返回字符串的字符数(需指定字符编码,正确处理多字节字符)。
示例对比:
$str = "Hello, 世界!"; // 包含英文和中文
// 使用 strlen():按字节计算
echo strlen($str);
// 输出:13(英文占1字节/字符,中文UTF-8占3字节/字符)
// 计算方式:7 (Hello,) + 3*2 (世界) + 3 (!) = 7 + 6 + 3 = 16? 可能需要验证实际字节数
// 使用 mb_strlen():按字符计算
echo mb_strlen($str, 'UTF-8');
// 输出:9(H, e, l, l, o, ,, 空, 世, 界, !)
2. 字符编码对长度的影响
- 单字节编码(如 ASCII)
strlen()
和mb_strlen()
结果相同,因为每个字符占1字节。 - 多字节编码(如 UTF-8)
- 中文、日文等字符在 UTF-8 中通常占 3~4 字节。
- Emoji 字符(如 😊)可能占 4 字节。
- 使用
strlen()
会返回字节数,而mb_strlen()
返回实际字符数。
示例:
$emoji = "😊";
echo strlen($emoji); // 输出:4(UTF-8 编码)
echo mb_strlen($emoji, 'UTF-8'); // 输出:1
3. 处理多字节字符串的注意事项
(1) 截取子字符串
-
错误方式:直接使用
substr()
可能截断多字节字符,导致乱码。$str = "你好,世界!"; echo substr($str, 0, 5); // 输出乱码:你�(UTF-8 中每个中文占3字节)
-
正确方式:使用
mb_substr()
指定编码后安全截取。echo mb_substr($str, 0, 2, 'UTF-8'); // 输出:你好
(2) 遍历字符串字符
-
错误方式:直接按字节循环
使用strlen()
+ 下标访问可能拆分多字节字符。$str = "测试"; for ($i = 0; $i < strlen($str); $i++) { echo $str[$i]; // 输出乱码:拆分成3个字节 }
-
正确方式:使用
mb_strlen()
+mb_substr()
$length = mb_strlen($str, 'UTF-8'); for ($i = 0; $i < $length; $i++) { echo mb_substr($str, $i, 1, 'UTF-8'); // 输出:测 试 }
4. 字符串的最大长度
- 理论限制
PHP 字符串的长度受内存限制,由memory_limit
配置决定。 - 实际限制
通常单字符串可达几百 MB 甚至几 GB(取决于可用内存),但超大字符串会影响性能。
5. 性能优化
strlen()
是 O(1) 操作
PHP 内部记录字符串的字节长度,strlen()
直接返回预存值,速度极快。mb_strlen()
是 O(n) 操作
需要遍历字符串计算字符数,性能较低(尤其是大字符串)。
6. 常见问题与解决方案
问题 1:中文字符长度计算错误
$str = "你好";
echo strlen($str); // 输出:6(UTF-8 下每个中文占3字节)
// 期望字符数为2,需用 mb_strlen()
问题 2:字符串截断乱码
$str = "Hello, 世界!";
echo substr($str, 0, 7); // 输出:Hello, �(第7字节位于中文字符中间)
// 正确方式:mb_substr($str, 0, 7, 'UTF-8')
问题 3:未设置默认编码导致错误
// 需先设置默认编码(或在函数中显式指定)
mb_internal_encoding('UTF-8');
echo mb_strlen("测试"); // 正确输出:2
7. 最佳实践
-
统一使用 UTF-8 编码
在文件、数据库、HTTP 头中明确使用 UTF-8。 -
多字节操作使用
mb_\*
函数
如mb_strlen()
,mb_substr()
,mb_strpos()
。 -
始终指定编码参数
避免依赖服务器默认配置:mb_strlen($str, 'UTF-8');
7. 最佳实践
-
全局设置默认编码
在脚本开头设置:mb_internal_encoding('UTF-8'); mb_http_output('UTF-8');
-
优先使用
mb_\*
函数处理多字节文本
替代原生函数如strlen
、substr
。 -
验证输入数据的编码
使用mb_check_encoding()
确保数据符合预期编码:if (!mb_check_encoding($input, 'UTF-8')) { // 处理非法编码 }
总结表
场景 | 推荐函数/方法 | 说明 |
---|---|---|
获取字节数 | strlen() | 快速,但不处理多字节字符 |
获取字符数 | mb_strlen($str, 'UTF-8') | 需指定编码 |
截取子字符串 | mb_substr($str, $start, $length, 'UTF-8') | 安全处理多字节字符 |
遍历字符串 | mb_strlen() + mb_substr() | 避免拆分多字节字符 |
四,mbstring扩展
PHP 的 mbstring
扩展(Multibyte String Extension)是专门用于处理多字节字符(如中文、日文、韩文、Emoji 等)的核心扩展。它提供了一系列函数,用于安全操作多字节编码的字符串(如 UTF-8、GBK、Big5 等),避免因直接使用原生字符串函数导致的乱码或逻辑错误。
1. mbstring
扩展是什么
-
多字节字符问题
像 UTF-8 这样的编码中,一个字符可能占用多个字节(如中文占 3 字节,Emoji 占 4 字节)。
原生函数(如strlen
、substr
)按字节操作,可能拆分多字节字符,导致乱码。$str = "你好"; echo strlen($str); // 输出 6(字节数),而非字符数 2 echo substr($str, 0, 2); // 输出乱码(截断第一个中文字符的中间字节)
-
mbstring
的作用
提供mb_strlen
、mb_substr
等函数,按字符(而非字节)处理字符串,确保操作安全。
2. 安装与启用 mbstring
安装方式
-
Linux (Ubuntu/Debian)
通过包管理器安装:sudo apt-get install php-mbstring
-
Windows
在php.ini
中取消注释以下行:extension=mbstring
-
通用方法(源码编译)
编译 PHP 时添加--enable-mbstring
参数。
验证安装
运行 php -m | grep mbstring
或创建 PHP 文件:
<?php
var_dump(extension_loaded('mbstring')); // 输出 bool(true) 表示成功
3. 核心功能与常用函数
(1) 设置默认编码
-
mb_internal_encoding()
设置脚本内部默认编码(需与其他环节编码一致,如数据库、HTTP 头)。mb_internal_encoding('UTF-8'); // 推荐全局设置
(2) 字符串长度与截取
-
mb_strlen()
获取字符串的字符数(而非字节数):$str = "Hello, 世界!"; echo mb_strlen($str, 'UTF-8'); // 输出 9(字符数)
-
mb_substr()
安全截取子字符串:$str = "你好,世界!"; echo mb_substr($str, 0, 2, 'UTF-8'); // 输出 "你好"
(3) 字符串位置与替换
-
mb_strpos()
查找字符位置(按字符而非字节):$pos = mb_strpos("abcdef", "d", 0, 'UTF-8'); // 返回 3
-
mb_str_replace()
多字节安全的字符串替换:echo mb_str_replace("世界", "PHP", "你好,世界!", 'UTF-8'); // 输出 "你好,PHP!"
(4) 大小写转换
-
mb_strtolower()
/mb_strtoupper()
支持多字节字符的大小写转换:echo mb_strtoupper("abc Déjà", 'UTF-8'); // 输出 "ABC DÉJÀ"
(5) 编码转换
-
mb_convert_encoding()
转换字符串编码(如 UTF-8 → GBK):$str = "你好"; $gbk_str = mb_convert_encoding($str, 'GBK', 'UTF-8');
4. 常见应用场景
场景 1:处理表单输入
确保接收到的多字节数据(如中文用户名)正确处理:
// 设置接收编码为 UTF-8
mb_http_input('UTF-8');
mb_language('uni');
场景 2:数据库交互
统一数据库连接编码,避免乱码:
// PDO 示例
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", "user", "pass");
场景 3:文件读写
读取或写入多字节文本文件时指定编码:
$content = file_get_contents("data.txt");
$content = mb_convert_encoding($content, 'UTF-8', 'SJIS'); // 转换日文编码
5. 注意事项
(1) 编码一致性
- 始终明确指定编码参数(如
mb_substr($str, 0, 2, 'UTF-8')
),避免依赖默认配置。 - 确保文件存储、数据库、HTTP 头等环节使用统一编码(推荐 UTF-8)。
(2) 性能优化
mb_*
函数比原生函数略慢,但多数场景差异可忽略。- 超大字符串处理时,避免频繁调用
mb_*
函数。
(3) 错误处理
-
编码转换失败时,
mb_convert_encoding
可能返回false
或乱码:$str = mb_convert_encoding($invalidStr, 'UTF-8', 'GBK'); if ($str === false) { throw new Exception("编码转换失败"); }
6. 常见问题与解决
问题 1:未启用 mbstring
扩展
- 表现:调用
mb_strlen
时报错Call to undefined function
。 - 解决:安装并启用
mbstring
扩展。
问题 2:编码不一致导致乱码
-
表现:字符串显示为问号
�
或乱码。 -
解决:检查并统一各环节编码,使用
mb_detect_encoding
检测实际编码:$encoding = mb_detect_encoding($str, ['UTF-8', 'GBK', 'BIG5']);
问题 3:函数参数缺失编码
-
错误示例:
echo mb_strlen("你好"); // 未指定编码,可能返回错误值
-
解决:始终传递编码参数:
echo mb_strlen("你好", 'UTF-8');
五,字符串相关函数
一、字符串基础操作
1. 字符串长度
-
strlen(string $str): int
返回字符串的字节数(非字符数,不适用于多字节字符)。echo strlen("Hello"); // 输出:5
-
mb_strlen(string $str, string $encoding = null): int
返回字符串的字符数(需指定编码处理多字节字符)。echo mb_strlen("你好", "UTF-8"); // 输出:2
2. 字符串拼接
-
.
运算符
直接连接多个字符串。$str = "Hello" . " " . "World"; // "Hello World"
-
implode(string $glue, array $pieces): string
将数组元素拼接为字符串,用指定分隔符连接。echo implode(", ", ["Apple", "Banana"]); // "Apple, Banana"
3. 字符串分割
-
explode(string $separator, string $str, int $limit = PHP_INT_MAX): array
按分隔符拆分字符串为数组。$arr = explode(" ", "a b c"); // ["a", "b", "c"]
-
preg_split(string $pattern, string $str): array
使用正则表达式分割字符串。$arr = preg_split("/[\s,]+/", "a,b c"); // ["a", "b", "c"]
二、字符串搜索与替换
1. 查找子字符串
-
strpos(string $haystack, string $needle): int|false
返回子字符串首次出现的字节位置(区分大小写)。echo strpos("Hello World", "Wo"); // 6
-
str_contains(string $haystack, string $needle): bool
(PHP 8+)
判断字符串是否包含子字符串。echo str_contains("PHP", "H"); // true
2. 替换内容
-
str_replace(array|string $search, array|string $replace, string $str): string
替换字符串中的指定内容。echo str_replace("World", "PHP", "Hello World"); // "Hello PHP"
-
preg_replace(string $pattern, string $replacement, string $str): string
使用正则表达式替换。echo preg_replace("/\d+/", "X", "a1b2"); // "aXbX"
三、字符串格式化
1. 大小写转换
-
strtolower(string $str): string
转换为全小写。echo strtolower("HELLO"); // "hello"
-
strtoupper(string $str): string
转换为全大写。echo strtoupper("hello"); // "HELLO"
-
ucwords(string $str): string
每个单词首字母大写。echo ucwords("hello world"); // "Hello World"
2. 去除空白字符
-
trim(string $str, string $chars = " \t\n\r\0\x0B"): string
去除字符串两端的空白或指定字符。echo trim(" text "); // "text"
-
ltrim()
/rtrim()
分别去除左端或右端字符。
3. 格式化输出
-
sprintf(string $format, mixed ...$values): string
格式化字符串(类似 C 语言printf
)。echo sprintf("Name: %s, Age: %d", "Alice", 30); // "Name: Alice, Age: 30"
四、子字符串操作
1. 截取子字符串
-
substr(string $str, int $start, int $length = null): string
按字节截取子字符串(可能破坏多字节字符)。echo substr("Hello", 1, 3); // "ell"
-
mb_substr(string $str, int $start, int $length, string $encoding): string
安全截取多字节字符的子字符串。echo mb_substr("你好世界", 0, 2, "UTF-8"); // "你好"
2. 提取特定内容
-
strstr(string $haystack, string $needle, bool $before_needle = false): string|false
返回从子字符串首次出现到结尾的部分。echo strstr("user@example.com", "@"); // "@example.com"
五、编码与转义
1. URL 编码
-
urlencode(string $str): string
对字符串进行 URL 编码。echo urlencode("a b=c"); // "a%20b%3Dc"
-
urldecode(string $str): string
解码 URL 编码的字符串。
2. HTML 转义
-
htmlspecialchars(string $str, int $flags = ENT_QUOTES): string
将特殊字符转换为 HTML 实体。echo htmlspecialchars("<a>link</a>"); // "<a>link</a>"
3. 多字节编码转换
-
mb_convert_encoding(string $str, string $to_encoding, string $from_encoding): string
转换字符串编码(如 UTF-8 → GBK)。$gbk_str = mb_convert_encoding("你好", "GBK", "UTF-8");
六、哈希与加密
1. 哈希计算
-
md5(string $str, bool $raw_output = false): string
计算字符串的 MD5 哈希值。echo md5("password"); // "5f4dcc3b5aa765d61d8327deb882cf99"
-
sha1(string $str): string
计算 SHA1 哈希值。
2. 密码安全
-
password_hash(string $password, string $algorithm): string
生成密码的哈希值(推荐使用PASSWORD_DEFAULT
算法)。$hash = password_hash("123456", PASSWORD_DEFAULT);
七、正则表达式
1. 匹配与提取
-
preg_match(string $pattern, string $str, array &$matches): int
执行正则表达式匹配。preg_match("/\d+/", "ID: 123", $matches); echo $matches[0]; // "123"
2. 全局匹配
-
preg_match_all(string $pattern, string $str, array &$matches): int
匹配所有符合条件的结果。preg_match_all("/\d+/", "a1 b2", $matches); print_r($matches[0]); // ["1", "2"]
八、注意事项与最佳实践
- 多字节字符处理
涉及中文、Emoji 等时,优先使用mb_*
函数(如mb_substr
、mb_strlen
)。 - 避免 SQL 注入
使用预处理语句(如 PDO)而非手动拼接 SQL,或至少用mysqli_real_escape_string
转义。 - 性能优化
正则表达式(preg_*
)性能较低,简单操作优先用原生函数(如str_replace
)。 - 编码一致性
确保文件、数据库、HTTP 头的编码统一(推荐 UTF-8)。
总结示例
// 安全处理用户输入
$input = trim($_POST["username"]);
$input = htmlspecialchars($input, ENT_QUOTES, "UTF-8");
// 多字节字符串截取
$text = "你好,世界!";
$sub = mb_substr($text, 0, 2, "UTF-8"); // "你好"
// 正则提取邮箱
preg_match("/[\w\.-]+@[\w\.-]+/", "Contact: user@example.com", $matches);
echo $matches[0]; // "user@example.com"