从零开始学 PHP 系列(四):数组与字符串操作大全——数据处理的核心武器

摘要 :在前几篇中,我们已经掌握了变量、数据类型、流程控制和函数,但你是否发现,当需要处理一批数据时(如学生名单、购物车商品、表单提交的多个字段),单个变量就显得力不从心了。数组正是为了解决"批量数据"而生,它是 PHP 中最强大、最灵活的数据结构。与此同时,Web 开发中 80% 的工作都在处理字符串------从用户输入的清洗、URL 解析,到内容搜索替换。本篇将带你深入数组的创建、遍历、排序、合并与切片,掌握常用的回调函数(array_maparray_filter),并揭秘 $_GET$_POST$_SERVER 等超全局数组。在字符串部分,我们将进阶学习正则表达式入门、URL 与 HTML 处理、多字节字符串以及各种实用格式化函数。


一、引言:为什么数组和字符串如此重要?

设想你正在开发一个博客系统。文章列表、标签云、用户评论、配置项......几乎每一个功能都需要与"一组数据"打交道。把一组相关的数据放在一个变量中,这就是数组。而标题、正文、摘要、URL 的清洗、截断、替换,全离不开字符串函数。


二、数组进阶:从基本操作到数据处理

2.1 数组的创建方式

除了前面学过的 array()[],还可以通过 range()explode() 等函数快速生成数组。

php 复制代码
<?php
// 使用 range 生成连续数组
$numbers = range(1, 10);        // [1,2,...,10]
$letters = range('a', 'z');     // ['a','b',...,'z']
$even = range(0, 20, 2);        // 步长为 2
​
// 使用 explode 从字符串生成数组(回顾第二篇)
$tags = "php,mysql,html,css";
$tagArray = explode(",", $tags);
​
// 使用 array_combine 合并键和值数组
$keys = ['name', 'age', 'city'];
$values = ['张三', 25, '上海'];
$info = array_combine($keys, $values);  // ['name'=>'张三', 'age'=>25, ...]
?>

2.2 多维数组

数组中的元素也可以是数组,形成多维数组,常用于表示表格数据或嵌套结构。

php 复制代码
<?php
$students = [
    ["张三", 22, "计算机系"],
    ["李四", 23, "数学系"],
    ["王五", 21, "物理系"],
];
​
// 关联数组嵌套
$users = [
    "u01" => ["name" => "Alice", "email" => "alice@example.com"],
    "u02" => ["name" => "Bob",   "email" => "bob@example.com"],
];
​
echo $users["u01"]["name"]; // Alice
?>

多维数组的访问通过连续索引 [键1][键2]

2.3 数组的遍历与迭代器

foreach 遍历多维数组

php 复制代码
<?php
$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];
​
foreach ($matrix as $row) {
    foreach ($row as $cell) {
        echo $cell . " ";
    }
    echo "\n";
}
?>

使用 each() 和 list()(PHP 7.2+ each 已弃用,改用 foreach) : 老代码中常出现 while (list($k, $v) = each($arr)),现在直接用 foreach 即可。

数组内部指针current()next()prev()end()reset() 可手动移动数组内部指针,但在现代 PHP 中较少使用,了解即可。

2.4 数组元素增删改

php 复制代码
<?php
$arr = ['a', 'b', 'c'];
​
// 末尾添加
array_push($arr, 'd');         // 返回新长度,也相当于 $arr[] = 'd';
$arr[] = 'e';                  // 更简洁,推荐
​
// 开头添加
array_unshift($arr, 'x');      // 返回新长度
​
// 末尾删除
$last = array_pop($arr);       // 返回移除的元素
​
// 开头删除
$first = array_shift($arr);    // 返回移除的元素
​
// 指定位置插入(无直接函数,使用 array_splice)
array_splice($arr, 2, 0, 'inserted'); // 索引2位置插入,不删除任何元素
​
// 删除指定元素(根据值)
$arr = array_diff($arr, ['b']); // 删除所有值为 'b' 的元素
​
// 删除并替换(用 array_splice)
$removed = array_splice($arr, 1, 2, ['new1', 'new2']); // 从索引1开始删2个,插入新值
?>

2.5 数组的合并与切片

合并

php 复制代码
<?php
$a = [1, 2, 3];
$b = [4, 5, 6];
$c = array_merge($a, $b);    // [1,2,3,4,5,6]
​
// 关联数组合并,相同键后者覆盖前者
$x = ['name' => '张三', 'age' => 20];
$y = ['age' => 25, 'city' => '上海'];
$z = array_merge($x, $y);    // ['name'=>'张三', 'age'=>25, 'city'=>'上海']
​
// + 运算符也可以合并,但相同键保留前者
$z2 = $x + $y;               // ['name'=>'张三', 'age'=>20, 'city'=>'上海']
?>

切片array_slice() 不改变原数组,array_splice() 会修改原数组。

php 复制代码
<?php
$arr = [1, 2, 3, 4, 5];
​
// 切片:从索引 1 开始取 3 个
$slice = array_slice($arr, 1, 3);   // [2,3,4](原数组不变)
​
// 负数索引表示从末尾数
$tail = array_slice($arr, -2);      // [4,5]
?>

2.6 数组排序详解

函数 排序方式 是否保留键名 说明
sort() 升序(重置键名) 索引数组排序
rsort() 降序(重置键名)
asort() 按值升序 关联数组按值排序
arsort() 按值降序
ksort() 按键升序 按键名排序
krsort() 按键降序
usort() 用户自定义比较函数 自定义排序逻辑
uasort() 用户自定义比较函数 按值自定义排序
uksort() 用户自定义比较函数 按键自定义排序

示例

php 复制代码
<?php
$fruits = ['orange', 'apple', 'banana'];
sort($fruits);                // ['apple','banana','orange']
​
$scores = ['张三' => 85, '李四' => 92, '王五' => 78];
asort($scores);               // 按分数升序:王五、张三、李四
ksort($scores);               // 按键名升序:张三(张的拼音靠后,看字符编码)
​
// 自定义排序:按字符串长度
usort($fruits, function($a, $b) {
    return strlen($a) - strlen($b);
});
?>

usort 的比较函数应返回整数:<0 表示 $a 小于 $b,0 表示相等,>0 表示 $a 大于 $b。PHP 7 引入了"太空船运算符" <=>,让比较更简洁:

php 复制代码
usort($fruits, fn($a, $b) => strlen($a) <=> strlen($b));

2.7 数组的回调函数:数据处理的利器

array_map():对数组的每个元素应用回调函数,返回新数组。

php 复制代码
<?php
$numbers = [1, 2, 3, 4, 5];
$squared = array_map(function($n) { return $n * $n; }, $numbers);
// [1, 4, 9, 16, 25]
​
// 可传入多个数组
$a = [1, 2, 3];
$b = [4, 5, 6];
$sum = array_map(fn($x, $y) => $x + $y, $a, $b);  // [5, 7, 9]
?>

array_filter():使用回调过滤元素,返回满足条件的元素数组。

php 复制代码
<?php
$numbers = [1, 2, 3, 4, 5, 6];
$even = array_filter($numbers, fn($n) => $n % 2 == 0);
// [1=>2, 3=>4, 5=>6] (键名保留)
// 若想重置索引,用 array_values($even)
?>

array_reduce():将数组迭代归约为单一值(如求和、乘积、拼接字符串)。

php 复制代码
<?php
$numbers = [1, 2, 3, 4];
$sum = array_reduce($numbers, fn($carry, $item) => $carry + $item, 0); // 10
?>

array_walk():对数组每个元素应用回调,直接修改原数组(返回 bool,不返回数组)。

php 复制代码
<?php
$fruits = ['apple', 'banana'];
array_walk($fruits, function(&$value, $key) {
    $value = strtoupper($value);
});
// $fruits 变为 ['APPLE', 'BANANA']
?>

2.8 其他实用数组函数速览

  • in_array($value, $array):检查值是否存在。

  • array_key_exists($key, $array):检查键是否存在。

  • array_search($value, $array):搜索值,返回对应键名。

  • array_keys($array):返回所有键名。

  • array_values($array):返回所有值,重建索引。

  • array_unique($array):移除重复值。

  • array_reverse($array):反转数组顺序。

  • array_rand($array, $num):随机取出一个或多个键。

  • shuffle($array):打乱数组(键名丢失)。

  • array_sum($array):计算数组所有值的和。

  • array_count_values($array):统计每个值出现的次数。

2.9 超全局数组:Web 开发的接口

PHP 预定义了几个在任何作用域都可访问的"超全局"数组,它们是脚本与外部交互的通道。

php 复制代码
<?php
// $_GET:URL 查询字符串参数
// URL:page.php?id=123&name=test
echo $_GET['id'];    // 123
​
// $_POST:HTTP POST 方法提交的数据
echo $_POST['username'];
​
// $_REQUEST:合并了 $_GET、$_POST、$_COOKIE(不推荐使用,来源不清)
// $_SERVER:服务器和执行环境信息
echo $_SERVER['HTTP_HOST'];    // 当前请求的主机名
echo $_SERVER['REQUEST_URI'];  // 请求的 URI(不含主机)
echo $_SERVER['REQUEST_METHOD'];// GET 或 POST
echo $_SERVER['REMOTE_ADDR'];  // 客户端 IP
echo $_SERVER['HTTP_USER_AGENT'];
​
// $_FILES:上传文件信息(下一篇详细讲)
// $_SESSION:会话变量(需 session_start())
// $_COOKIE:HTTP Cookie
// $_ENV:环境变量
?>

安全性提示 :永远不要信任 $_GET$_POST 中的数据,使用前务必进行过滤和验证(后续篇章会详细展开)。


三、字符串操作进阶:正则与多字节

3.1 正则表达式入门

正则表达式是字符串匹配和替换的"瑞士军刀"。PHP 使用 PCRE(Perl 兼容正则)函数族,以 preg_ 开头。

① 基础模式

  • /pattern/ 定界符,常用 /

  • ^ 开头,$ 结尾。

  • . 任意字符,* 零次或多次,+ 一次或多次,? 零次或一次。

  • \d 数字,\w 单词字符,\s 空白。

  • [abc] 字符集,[a-z] 范围,[^abc] 非字符集。

  • {n,m} 出现 n 到 m 次。

  • 修饰符:i(不区分大小写),m(多行模式),u(UTF-8 模式)。

② preg_match():匹配一次,返回 0/1,并将匹配结果存入第三个参数。

php 复制代码
<?php
$email = "user@example.com";
$pattern = "/^[\w\.-]+@[\w\.-]+\.\w{2,}$/";
if (preg_match($pattern, $email, $matches)) {
    echo "邮箱合法: " . $matches[0];
} else {
    echo "邮箱非法";
}
?>

③ preg_match_all():全局匹配,返回匹配次数。

php 复制代码
<?php
$text = "电话: 13800138000, 还有 15912345678";
preg_match_all("/\d{11}/", $text, $matches);
print_r($matches[0]); // [13800138000, 15912345678]
?>

④ preg_replace():查找并替换。

php 复制代码
<?php
$str = "Hello, 2026!";
$cleaned = preg_replace("/\d+/", "XXXX", $str);
echo $cleaned; // "Hello, XXXX!"
?>

⑤ preg_split():按模式分割字符串。

php 复制代码
<?php
$data = "apple, banana; orange | pineapple";
$fruits = preg_split("/[,;|]\s*/", $data);
// ["apple", "banana", "orange", "pineapple"]
?>

⑥ 常见正则示例

  • 手机号(中国大陆):/^1[3-9]\d{9}$/

  • URL:/https?:\/\/[\w\-]+(\.[\w\-]+)+([\w\-\.,@?^=%&:/~+#]*)?/

  • 日期格式 YYYY-MM-DD:/^\d{4}-\d{2}-\d{2}$/

正则表达式需要多加练习才能熟练,但掌握基本语法就足以应对多数场景。

3.2 多字节字符串处理

在处理中文等非英文字符时,必须使用 mb_ 开头的多字节字符串函数,否则会得到错误结果。

php 复制代码
<?php
$cn = "你好世界";
​
echo strlen($cn);       // 12(UTF-8 下每个汉字 3 字节)
echo mb_strlen($cn);    // 4  (正确字符数)
​
echo substr($cn, 0, 3);       // 可能输出乱码
echo mb_substr($cn, 0, 2);    // "你好"
​
echo mb_strpos($cn, "世界");   // 2(从 0 开始)
?>

常用 mb_ 函数:mb_strlenmb_substrmb_strposmb_strtolowermb_strtouppermb_convert_encodingmb_convert_case 等。

设置内部编码 (在脚本开头或 php.ini 中):mb_internal_encoding("UTF-8");

3.3 URL 与 HTML 相关函数

php 复制代码
<?php
// URL 编码与解码
$query = "name=张三&age=25";
$encoded = urlencode($query);    // name=%E5%BC%A0%E4%B8%89...
echo urldecode($encoded);        // 还原
​
// HTTP 构建查询字符串
$data = ['name' => '张三', 'age' => 25];
echo http_build_query($data);    // name=%E5%BC%A0%E4%B8%89&age=25
​
// 解析 URL
$url = "https://user:pass@example.com:8080/path?id=1#frag";
$parts = parse_url($url);
print_r($parts);
/*
Array (
    [scheme] => https
    [host]   => example.com
    [user]   => user
    [pass]   => pass
    [path]   => /path
    [query]  => id=1
    [fragment] => frag
)
*/
?>

3.4 字符串与数组的深度互转

除了 explodeimplode,还有更灵活的 str_splitpreg_split

php 复制代码
<?php
// 按字符分割(包括多字节慎用,最好用 mb_str_split PHP 7.4+)
$chars = str_split("Hello", 2);  // ['He','ll','o'] 
​
// 利用正则分割,保留分隔符
$str = "apple, banana, orange";
$parts = preg_split("/(,\s*)/", $str, -1, PREG_SPLIT_DELIM_CAPTURE);
// ["apple", ", ", "banana", ", ", "orange"]
?>

3.5 字符串搜索与高级替换

php 复制代码
<?php
$text = "Hello World, Hello PHP";

// str_replace(基本替换)
$replaced = str_replace("Hello", "你好", $text);

// str_ireplace(不区分大小写)
$replaced = str_ireplace("hello", "你好", $text);

// strtr() 按字符映射替换
echo strtr("abc", "a", "x");        // "xbc"
echo strtr("abc", ["a"=>"x"]);      // "xbc"

// strpos/stripos 查找位置,stripos 不区分大小写
$pos = strpos($text, "World");      // 6

// strstr/stristr 查找子串并返回从该位置到结尾的字符串
$rest = strstr($text, "World");     // "World, Hello PHP"

// strrchr 从最后出现的位置开始返回
echo strrchr("file.txt.zip", ".");  // ".zip"
?>

3.6 格式化输出函数

php 复制代码
<?php
// printf 系列:格式化字符串并输出/返回
$price = 9.99;
printf("价格:%.2f 元", $price);    // 直接输出
$formatted = sprintf("价格:%.2f 元", $price); // 返回字符串
​
// number_format() 千位分隔与小数
echo number_format(1234567.89, 2, '.', ','); // 1,234,567.89
​
// str_pad 填充
echo str_pad("5", 3, "0", STR_PAD_LEFT); // 005
​
// nl2br 换行符转 <br>
echo nl2br("第一行\n第二行");
?>

四、综合实战:编写一个简单的文本数据处理工具

让我们结合数组和字符串函数,制作一个命令行下的"词频统计器"。读取一段文本,统计每个单词出现的次数并排序输出。

php 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>英文词频统计工具</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft YaHei", sans-serif;
        }
        body {
            background-color: #f4f7fc;
            padding: 40px;
        }
        .container {
            max-width: 700px;
            margin: 0 auto;
            background: #fff;
            padding: 30px;
            border-radius: 12px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
            color: #2c3e50;
            margin-bottom: 25px;
            font-size: 24px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            padding: 12px 15px;
            text-align: left;
            border-bottom: 1px solid #e2e8f0;
        }
        th {
            background-color: #3498db;
            color: white;
        }
        tr:nth-child(even) {
            background-color: #f8fafc;
        }
        .count-high {
            color: #e74c3c;
            font-weight: bold;
        }
    </style>
</head>
<body>
<div class="container">
    <h1>📖 英文文本词频统计 TOP10</h1>
    <?php
    /**
     * 简易英文词频统计器
     * 输入一段英文文本,返回按单词出现频次降序的数组
     * @param string $text 原始英文文本
     * @param int $minLength 单词最小长度,默认2
     * @return array [单词 => 出现次数]
     */
    function wordFrequency(string $text, int $minLength = 2): array {
        // 全部转为小写
        $text = mb_strtolower($text);

        // 替换所有标点、特殊符号为空格,保留字母与连字符(复合单词)
        $text = preg_replace("/[^a-z\s\-]/", " ", $text);
        // 多个连续空格统一替换为单个空格
        $text = preg_replace("/\s+/", " ", trim($text));

        // 按空格分割单词,过滤空元素
        $words = explode(" ", $text);

        // 过滤长度不足的单词
        $words = array_filter($words, function ($word) use ($minLength) {
            return mb_strlen($word) >= $minLength;
        });

        // 统计每个单词出现次数
        $frequency = array_count_values($words);

        // 按频次降序排序
        arsort($frequency);

        return $frequency;
    }

    // 测试示例文本
    $sample = "PHP is a popular general-purpose scripting language that is especially suited to web development. Fast, flexible and pragmatic, PHP powers everything from your blog to the most popular websites in the world.";

    // 获取词频结果
    $result = wordFrequency($sample);
    ?>

    <table>
        <tr>
            <th width="12%">排名</th>
            <th width="60%">单词</th>
            <th width="28%">出现次数</th>
        </tr>
        <?php
        $rank = 1;
        foreach ($result as $word => $count) {
            // 出现2次及以上标红加粗
            $countClass = $count >= 2 ? 'count-high' : '';
            echo <<<TR
            <tr>
                <td>{$rank}</td>
                <td>{$word}</td>
                <td class="{$countClass}">{$count}</td>
            </tr>
            TR;
            if ($rank >= 10) break;
            $rank++;
        }
        ?>
    </table>
</div>
</body>
</html>

这个程序用到了正则替换和分割、数组过滤、array_count_valuesarsortprintf 等,正是本系列知识的集中运用。


五、总结

  • 数组高级操作:创建(range/explode)、多维数组、增删改(push/pop/shift/unshift/splice)、合并与切片(merge/slice)、各种排序及自定义排序(usort)、回调函数(map/filter/reduce/walk)。

  • 超全局数组$_GET$_POST$_SERVER 等是 Web 与 PHP 的核心交互接口。

  • 字符串进阶:正则表达式入门(preg_match/match_all/replace/split)、多字节字符串(mb_* 系列)、URL 与 HTML 函数、格式化输出。


如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。动手练习是掌握编程最快的方法,请务必亲手敲一遍本文的所有示例代码,并截图保存你的成果。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。