PHP 字符串与数组

AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。

PHP 8.4

PHP 的数组是「有序映射」:既能当列表用,也能当字典用,函数库非常庞大。这一篇只讲真正高频的部分。

索引数组与关联数组

$colors = ["red", "green", "blue"];              // 索引:0, 1, 2
$user   = ["name" => "ann", "age" => 30];        // 关联:字符串键

追加元素:

$colors[] = "yellow";        // 追加到末尾,索引自动分配
$user["city"] = "Shenzhen";  // 关联数组指定键

PHP 数组保持插入顺序,这一点可以放心依赖:

$user["role"] = "admin";
foreach ($user as $key => $value) {
    echo "$key: $value\n";
}
// name: ann
// age: 30
// city: Shenzhen
// role: admin

遍历

$colors = ["red", "green", "blue"];

foreach ($colors as $color) {
    echo $color . "\n";
}

foreach ($colors as $index => $color) {
    echo "$index => $color\n";
}

foreach 遍历的是数组的副本:在循环里修改 $colors 不会影响正在遍历的序列。

$nums = [1, 2, 3];
foreach ($nums as $n) {
    $nums[] = $n * 10;   // 循环次数仍是 3,不会无限增长
}

需要修改元素值时用引用 &,用完务必 unset:

foreach ($nums as &$n) {
    $n *= 2;
}
unset($n);   // 必须:否则后续再用 $n 会意外改到数组最后一个元素

常用数组函数

$nums = [3, 1, 2];

count($nums);              // 3,元素个数
in_array(2, $nums);        // true,是否包含值(默认松散比较)
in_array(2, $nums, true);  // 严格比较,推荐
array_keys($nums);         // [0, 1, 2]
array_values($nums);       // [3, 1, 2]
sort($nums);               // 原地排序,返回 true,数组变成 [1, 2, 3]
rsort($nums);              // 降序原地排序

sort() 是原地修改并返回布尔值,不要写 $sorted = sort($nums)(会得到 true)。想保留原数组用 array_slice 或先复制。

array_map / array_filter / array_reduce

$nums = [1, 2, 3];

$doubled = array_map(fn($n) => $n * 2, $nums);   // [2, 4, 6]
$evens   = array_filter($nums, fn($n) => $n % 2 === 0);   // [1 => 2]
$total   = array_reduce($nums, fn($carry, $n) => $carry + $n, 0);   // 6

两个注意点:

  1. array_filter 会保留原键,结果可能不是连续索引。需要重排索引时套一层 array_values():
$evens = array_values(array_filter($nums, fn($n) => $n % 2 === 0));  // [2]
  1. 回调里访问外部变量要用 use(箭头函数 fn() 自动捕获,匿名函数 function() 不会):
$factor = 10;
array_map(function ($n) use ($factor) {
    return $n * $factor;
}, $nums);

数组合并:+ 与 array_merge

两者行为不同,选错会丢数据:

$a = ["name" => "ann", "age" => 30];
$b = ["age" => 31, "city" => "Shenzhen"];

array_merge($a, $b);
// ["name" => "ann", "age" => 31, "city" => "Shenzhen"]  后者覆盖前者

$a + $b;
// ["name" => "ann", "age" => 30, "city" => "Shenzhen"]  前者优先,忽略后者的同名键

对索引数组:array_merge 会追加并重新编号;+ 会保留左边、丢弃右边重叠下标。

[1, 2] + [3, 4];            // [1, 2],右边的 3、4 被丢弃
array_merge([1, 2], [3, 4]); // [1, 2, 3, 4]

合并索引数组用 array_merge,合并配置(想保留已有值)用 +。

字符串函数

$s = "hello world";

strlen($s);                  // 11,字节数
str_contains($s, "world");   // true(PHP 8+)
str_starts_with($s, "he");   // true
str_ends_with($s, "ld");     // true
strpos($s, "world");         // 6,首次出现位置,未找到返回 false
strtoupper($s);              // "HELLO WORLD"
strtolower($s);              // "hello world"
trim("  hi  ");              // "hi"
str_replace("world", "PHP", $s);   // "hello PHP"
substr($s, 0, 5);            // "hello"
explode(" ", $s);            // ["hello", "world"]
implode("-", ["a", "b"]);    // "a-b"

两个必须记住的点:

  1. strpos 未找到返回 false,找到位置 0 也返回 0。判断必须用 === / !==:
if (strpos($s, "hello") !== false) {
    echo "找到了";   // hello 在位置 0,用 == 会误判为"没找到"
}
  1. strlen 统计的是字节,中文在 UTF-8 下占 3 字节:
strlen("你好");                    // 6
mb_strlen("你好", "UTF-8");        // 2,用 mb_* 系列做多字节处理
mb_substr("你好世界", 0, 2, "UTF-8"); // "你好"

处理中文一律用 mb_* 函数(需安装 mbstring 扩展,主流发行版默认开启)。

字符串与数组的互转

$csv = "a,b,c";
$parts = explode(",", $csv);        // ["a", "b", "c"]
$back  = implode(",", $parts);      // "a,b,c"

// 去掉空项并清理空白
$tags = array_values(array_filter(
    array_map("trim", explode(",", "php, , js, "))
));
// ["php", "js"]

一个完整例子:统计与格式化

<?php
declare(strict_types=1);

$orders = [
    ["id" => 1, "amount" => 120, "paid" => true],
    ["id" => 2, "amount" => 80,  "paid" => false],
    ["id" => 3, "amount" => 200, "paid" => true],
];

$paid = array_filter($orders, fn($o) => $o["paid"]);
$total = array_reduce($paid, fn($carry, $o) => $carry + $o["amount"], 0);
$ids = implode(", ", array_map(fn($o) => "#" . $o["id"], $paid));

echo "已支付订单:{$ids}" . PHP_EOL;
echo "合计:{$total} 元" . PHP_EOL;
// 已支付订单:#1, #3
// 合计:320 元

常见错误与注意事项

  1. sort() 返回值当排序结果:它返回 true,数组被原地修改。
  2. strpos() 用 == false 判断:位置 0 会误判,必须用 !== false。
  3. 用 strlen() 处理中文长度:得到字节数,改用 mb_strlen()。
  4. array_filter 后下标不连续:套 array_values() 重排。
  5. 在 foreach 里修改数组期望影响遍历:遍历的是副本,需要改值用 & 并 unset。
  6. 用 + 合并关联数组期望后者覆盖:+ 保留左边,覆盖要用 array_merge。

小结

  • PHP 数组是有序映射,保序可用,foreach 遍历副本。
  • 转换用 array_map / array_filter / array_reduce;过滤后记得 array_values。
  • 合并:追加索引用 array_merge,保留已有键用 +。
  • 字符串查找用 str_contains(PHP 8+),定位必须 !== false。
  • 中文一律用 mb_* 系列函数。

下一步