PHP 字符串与数组
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
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
两个注意点:
array_filter会保留原键,结果可能不是连续索引。需要重排索引时套一层array_values():
$evens = array_values(array_filter($nums, fn($n) => $n % 2 === 0)); // [2]
- 回调里访问外部变量要用
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"
两个必须记住的点:
strpos未找到返回false,找到位置 0 也返回0。判断必须用===/!==:
if (strpos($s, "hello") !== false) {
echo "找到了"; // hello 在位置 0,用 == 会误判为"没找到"
}
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 元
常见错误与注意事项
sort()返回值当排序结果:它返回true,数组被原地修改。strpos()用== false判断:位置 0 会误判,必须用!== false。- 用
strlen()处理中文长度:得到字节数,改用mb_strlen()。 array_filter后下标不连续:套array_values()重排。- 在
foreach里修改数组期望影响遍历:遍历的是副本,需要改值用&并unset。 - 用
+合并关联数组期望后者覆盖:+保留左边,覆盖要用array_merge。
小结
- PHP 数组是有序映射,保序可用,
foreach遍历副本。 - 转换用
array_map/array_filter/array_reduce;过滤后记得array_values。 - 合并:追加索引用
array_merge,保留已有键用+。 - 字符串查找用
str_contains(PHP 8+),定位必须!== false。 - 中文一律用
mb_*系列函数。