重头学PHP-5: 数组常用函数大全

784 阅读15分钟

PHP-5: 数组常用函数大全

1. 数组基础

1.1 概述与分类

  • 数组是典型的复合类型数据,它的值是由零个或多个键值对构成
  • 数组中的每一个"键值对", 称之为数组成员 或者 数组元素
  • 根据的类名,可以将数组分为二类:
序号 分类 描述
1 索引数组 键名默认是从 0 开始递增的正整数
2 关联数组 键名是由语义化的字符串组成

索引数组键名可使用数字字符串,所以,索引数组也可视为关联数组的一个子集

// 1. 数组分类

// 1.1 索引数组
$goods = [0=>'A1060', 1=>'华为笔记本电脑', 2=>'MateBook X Pro', 3=>9999];
printf('<pre>%s</pre>', print_r($goods,true));
// 如果键名是从0开始递增的正整数,可以省略键名
$goods = ['A1060', '华为笔记本电脑', 'MateBook X Pro', 9999];
printf('<pre>%s</pre>', print_r($goods,true));
// 键名可以不连续,可以是负数,甚至可以是小数
$goods = ['A1060', 5=>'华为笔记本电脑', 3.14=>'MateBook X Pro', -88=>9999];
printf('<pre>%s</pre>', print_r($goods,true));
// 打印键名时,只会显示键名的整数部分, 即小数键名会自动取整,访问时用原始键名或取整键名都可以
echo "{$goods[3.14]} --- {$goods[3]}<br>";
// 访问全部数组成员


// 1.2 关联数组
// 键名为非数字的字符串,例如将上面的索引数组,用以下方式定义,显然比纯数字的索引要直观得多
$goods = ['id'=>'A1060', 'name'=>'华为笔记本电脑', 'model'=>'MateBook X Pro', 'price'=>9999];
printf('<pre>%s</pre>', print_r($goods,true));

// 为什么特别强调是非数字字符串呢?因为索引数组的数字键名也可以这样表示
$goods = ['0'=>'A1060', '1'=>'华为笔记本电脑', '2'=>'MateBook X Pro', '3'=>9999];
printf('<pre>%s</pre>', print_r($goods,true));
// 访问的时候,可以使用数字键名,也可以使用字符串数字键名
echo "{$goods[1]} --- {$goods['1']}<br>";

// 所以, 索引数组,也可以理解为键名是数字字符串的关联数组
// 从这个角度看, 索引数组,可以视为"关联数组"的一个子集
// 因此, 数字键名与字符串键名在同一个数组中出现,其实也是合法的
$goods = [3=>'A1060', 'name'=>'华为笔记本电脑', 10=>'MateBook X Pro', 'price'=>9999];
printf('<pre>%s</pre>', print_r($goods,true));
// 如果省略数字键名部分, 默认使用从0开始递增的正整数为元素编号
$goods = ['A1060', 'name'=>'华为笔记本电脑', 'MateBook X Pro', 'price'=>9999];
printf('<pre>%s</pre>', print_r($goods,true));

1.2 定义与访问

序号 定义 描述
1 array()函数 传统定义方式,已淘汰或不再推荐
2 [...]结构 php5.4+支持, 语法简洁,推荐使用

访问遵循按键名访问的规则, 多维数组与不例外

<?php

# 2. 数组的定义与访问
// array()函数定义数组
$staff1 = array('1010', '八戒','bj@php.cn');
$staff2 = array('id'=>'1010', 'name'=>'八戒', 'email'=>'bj@php.cn');
printf('<pre>%s%s</pre>', print_r($staff1,true),print_r($staff2,true));

// 方括号[]简化定义: php 5.4+,与JavaScript类似, 推荐使用
$staff3 = ['1010', '八戒', 'bj@php.cn'];
$staff4 =['id'=>'1010', 'name'=>'八戒', 'email'=>'bj@php.cn'];
printf('<pre>%s%s</pre>', print_r($staff3,true),print_r($staff4,true));

// 使用方括号,还可以逐个定义数组成员
$staff5['id'] = '1020';
$staff5['name'] = '悟空';
$staff5['email'] = 'wk@php.cn';
printf('<pre>%s</pre>', print_r($staff5,true));

// 如果是逐个定义索引数组成员,如果省略键名,则键名默认从0开始递增
$staff6[] = '1030';
$staff6[] = '唐僧';
$staff6[] = 'ts@php.cn';
printf('<pre>%s</pre>', print_r($staff6,true));

// 数组成员是按键名访问的
// 访问索引数组成员
echo "$staff6[1] 的邮箱是: $staff6[2]<br>";
// 访问关联数组成员
// 双引号中的数组成员变量,键名部分使用了单引号, 所以一定要给数组变量加上大括号定界符
echo "{$staff5['name']} 的邮箱是: {$staff5['email']}<br>";

// 数组成员的类型不受限制,可以是字面量,可以是变量,可以是对象等
$age = 30;
$staff7 =['id'=>'1010', 'name'=>'八戒', 'age'=>$age, 'email'=>'bj@php.cn'];
printf('<pre>%s</pre>', print_r($staff7,true));
// 如果数组成员的类型仍是一个数组,则构成多维数组
// 多维数组中最常用的是二维数组,二维数组在php操作数据库中非常重要
$users = [
    0=>['id'=>'101', 'name'=>'玉帝', 'age'=>88],
    1=>['id'=>'102', 'name'=>'王母', 'age'=>78],
    2=>['id'=>'101', 'name'=>'如来', 'age'=>68],
];
printf('<pre>%s</pre>', print_r($users,true));
// 访问二维数组成员,与访问一维数组成员类似
// 先定位到某一个成员,再访问它的全部数据, 下例返回的是"如来"的数据
printf('<pre>%s</pre>', print_r($users[2],true));
// 查看如来的年龄
echo $users[2]['age'];

1.3 遍历

序号 方式 描述
1 逐个遍历 使用数组内部指针
2 循环遍历 使用foreach结构

数组内部指针函数:

序号 函数 描述
1 current 获取当前元素的值
2 key 获取当前元素的键名
3 next 将数组中的内部指针向前移动一位
4 prev 将数组的内部指针倒回一位
5 end 将数组的内部指针指向最后一个单元
6 reset 将数组的内部指针指向第一个单元

foreach遍历:

序号 语法 描述
1 foreach ($arr as $value) 遍历"值"
2 foreach ($arr as $key=>$value) 遍历"键与值"
3 foreach ($arr as list(...)) 解构遍历

foreach 不支持 @ 抑制错误

<?php
# 3. 数组遍历

// 数据遍历通常与数组元素的处理结合在一起的,与简单的打印输出不一样
// 数组元素的处理, 最常用的就是数据的格式化

// 3.1 逐个遍历: 数组内部指针
// 如果没有对数组进行过遍历操作,则数组内部指针默认停留头部,即指向第一个元素
$stu = ['id' => '1020', 'name' => '金莲', 'age' => 18, 'course' => 'php', 'grade' => 68];
// 获取当前数据成员的键名与值
// current(): 当前成员值, key(): 当前成员的键名
printf('[%s] => %s<br>', key($stu), current($stu));
// next():移动指针,指向下一个数组成员
next($stu);
printf('[%s] => %s<br>', key($stu), current($stu));
// 再次移动
next($stu);
printf('[%s] => %s<br>', key($stu), current($stu));
// 如果要访问最后一个成员,是否一直next()下去吗?当然不用,可以直接定位到数组末尾
end($stu);
printf('[%s] => %s<br>', key($stu), current($stu));

// prev(): 向前移动指针,指向当前成员的前一个前面
prev($stu);
printf('[%s] => %s<br>', key($stu), current($stu));
// 同样,如果要从当前位置直接跳转到第一个成员,也不用逐级返回,可以重置数组指针即可
// 数组指针重置后, 会自动指向第一个成员
reset($stu);
printf('[%s] => %s<br>', key($stu), current($stu));

echo '<hr>';

// 3.2 自动遍历: 循环实现
// 你可能会很自然的想到,使用while,配合数组内部指针来遍历,咱们试试看
reset($stu);
while (true) {
    printf('[%s] => %s<br>', key($stu), current($stu));
    if (next($stu)) {
        continue;
    } else {
        break;
    }
}
echo '<hr>';
// 看上去似乎正常,其实并非如此,这是假定数组所有元素都是true的前提下
// 如果有数组成员值为false,或者可转为false的值,如null,就会提前结束遍历
$stu = ['id' => '1020', 'name' => '金莲', 'age' => null, 'course' => 'php', 'grade' => 68];
reset($stu);
while (true) {
    printf('[%s] => %s<br>', key($stu), current($stu));
    if (next($stu)) {
        continue;
    } else {
        break;
    }
}
// age后面的二个成员将不会打印输出
echo '<hr>';


// 既然while循环不能遍历, 那么for循环是否可以呢?
// 看到for循环,首先会想到遍因索引数组,这是必然的
$arr = [100, 'a', 89, true, [1, 2, 3]];
for ($i = 0; $i < count($stu); $i++) {
    // 数组成员也可能仍然是数组,所以使用了is_array()判断一下,针对不同类型使用不同方式输出
    echo is_array($arr[$i]) ? print_r($arr[$i], true) : $arr[$i], '<br>';
}
echo '<hr>';
// 看上去,for循环工作得很好,那么for循环能否正确遍历关联数组呢?
reset($stu);
for ($i = 0; $i < count($stu); $i++) {
    printf('[%s] => %s<br>', key($stu), current($stu));
    next($stu);
}
// 可以看出, for循环可以正常输出关联数组,并且能正确识别出null/false元素
// 这是因为它是根据数组成员数量做为循环条件的, 并非根据当前数组指针是否指向空元素来判断

// 尽管for循环可以遍历数组, 但仍然不方便,特别是遍历关联数组时,循环变量只是摆设,并且必须手工移到数组指针
// 针对数组类型,PHP预定义了foreach语法结构,专用于遍历数组类型的数据
echo '<hr>';
foreach ($stu as $key => $value) {
    printf('[%s] => %s<br>', $key, $value);
}
// 对于索引数组,我们通常只关注值,可以省略循环变量的键名$key
echo '<hr>';
foreach ($arr as $value) {
    echo is_array($value) ? print_r($value, true) : $value, '<br>';
}
echo '<hr>';

// foreach()在遍历二维数组时特别方便,以下用二维数组模拟数据表查询结构
$users = [
    0 => ['id' => '101', 'name' => '玉帝', 'age' => 88],
    1 => ['id' => '102', 'name' => '王母', 'age' => 78],
    2 => ['id' => '101', 'name' => '如来', 'age' => 68],
];
// 索引是默认值,可以省略
$users = [
    ['id' => '101', 'name' => '玉帝', 'age' => 88],
    ['id' => '102', 'name' => '王母', 'age' => 78],
    ['id' => '101', 'name' => '如来', 'age' => 68],
];
// 也可将多维数组写在一行定义
// 前面可能定义过$users数组,为防止后面数据被追加,所以先清空
// 第一行必须加上$users = []; 清空该数组
$users = [];
$users[] = ['id' => '101', 'name' => '玉帝', 'age' => 88];
$users[] = ['id' => '102', 'name' => '王母', 'age' => 78];
$users[] = ['id' => '101', 'name' => '如来', 'age' => 68];

print_r($users);

foreach ($users as $user) {
    foreach ($user as $key => $value) {
        echo "$key => $value <br>";
    }
    echo '<hr>';
}

// 更多场景下, 我们并不会使用双重循环来输出二维数组
foreach ($users as $user) {
    printf('id=%s, name=%s, age=%s<br>', $user['id'], $user['name'], $user['age']);
}
echo '<hr>';

// 如果二维数组中字段并不多,可以使用list()进行数组解包,类似于ES6中的解构赋值
// 提示: 在foreach中使用list()解构数组, 要求 PHP5.5+
foreach ($users as list('id' => $id, 'name' => $name, 'age' => $age)) {
    printf('id=%s, name=%s, age=%s<br>', $id, $name, $age);
}
echo '<hr>';
// 对于索引数组, list()解构更加方便
$staffs = null;
$staffs[] = ['2020', '八戒', 29];
$staffs[] = ['2021', '悟空', 39];
$staffs[] = ['2022', '唐僧', 49];
foreach ($staffs as list($id, $name, $age)) {
    printf('id=%s, name=%s, age=%s<br>', $id, $name, $age);
}
echo '<hr>';

// list()中的参数数量可以少于数组元素数量,但不能多于
foreach ($staffs as list($id, $name)) {
    printf('id=%s, name=%s<br>', $id, $name);
}
// list()参数过多,会报Notice消息级警告错误
foreach ($staffs as list($id, $name, $age, $email)) {
    printf('id=%s, name=%s, email=%s<br>', $id, $name,$age, $email);
}
echo '<hr>';
// list()中允许嵌套list, 用于解析多维数组
// $staffs中添加一个字段, 表示js和php的成绩
$staffs = null;
$staffs[] = ['2020', '八戒', 29, [67, 88]];
$staffs[] = ['2021', '悟空', 39, [99, 31]];
$staffs[] = ['2022', '唐僧', 49, [56, 63]];
foreach ($staffs as list($id, $name, $age, list($js, $php))) {
    printf('id=%s, name=%s, age=%s, js=%s, php=%s<br>', $id, $name,$age, $js, $php);
}
echo '<hr>';

// foreach()不仅仅可以遍历数组,还可以遍历对象属性
$obj = new stdClass();
$obj->name = 'admin';
$obj->email = 'admin@php.cn';
$obj->role = 'custom';
foreach ($obj as $prop=>$value) {
    printf('%s => %s<br>',$prop, $value);
}

2. 数组函数

2.1. 键名相关

序号 函数 描述
1 array_keys 获取所有键名组成的数组
2 array_key_exists 是否存在指定键名
3 array_key_last 获取最后一个键名 php7.3+
4 array_key_first 获取第一个键名 php7.3+
// ## 键名相关函数
// array_keys: 获取所有键名组成的数组
$arr = ['id' => 1, 'username' => 'admin', 'email' => 'admin@php.cn'];
print_r(array_keys($arr));
echo '<hr>';

// array_key_exists: 是否存在指定键名
echo (array_key_exists('email', $arr) ? '存在' : '不存在') . '<hr>';

// array_key_last: 获取最后一个键名php7.3+
echo array_key_last($arr) . '<hr>';

// array_key_first: 获取第一个键名php7.3+
echo array_key_first($arr) . '<hr>';

2.2 与值相关

序号 函数 描述
1 array_values 返回数组中所有值组成的数组
2 in_array 检查数组中是否存在某个值
3 array_search 搜索指定的值,返回键名
4 array_unique 删除重复的值
// ## 与值相关的数组函数
// array_values: 返回数组中所有值组成的数组
$arr = [3 => 10, 9 => 20, 0 => 'html', 'id' => 'css', 20 => 20, 30];
print_r($arr);
echo '<hr>';
print_r(array_values($arr));
echo '<hr>'; // 键名被打乱的数组进行重置

// in_array: 检查数组中是否存在某个值
echo (in_array('html', $arr) ? '存在' : '不存在') . '<br>';

// array_search: 搜索指定的值,返回键名
echo array_search('css', $arr);
echo '<br>';
echo $arr[array_search('css', $arr)] . '<br>';

// array_unique: 删除重复的值
$newArr = array_unique($arr);
print_r($newArr);

2.3 与统计相关

序号 函数 描述
1 count 统计元素数量或对象属性数量
2 array_count_values 统计所有值的出现频率
// 与统计相关
$arr = [10, 3, 5, 3, 10, 5, 7, 3, 10, 7, 7];
printf('<pre>%s</pre>', print_r($arr, true));
// count: 统计元素数量或对象属性数量
echo '数组元素数量: ' . count($arr);

// array_count_values: 统计所有值的出现频率
$res = array_count_values($arr);
printf('<pre>%s</pre>', print_r($res, true));

2.4 与计算相关

序号 函数 描述
1 array_sum 对数组中所有值求和
2 array_product 计算数组中所有值的乘积
// 与计算相关
$arr = [10, 20, 30];

// array_sum: 对数组中所有值求和
echo array_sum($arr) . '<hr>';

// array_product: 计算数组中所有值的乘积
echo array_product($arr);

2.5 栈与队列

序号 函数 描述
1 array_push 从尾部添加一个或多个元素
2 array_pop 从尾部删除最后一个元素
3 array_unshift 从头部添加一个或多个元素
4 array_shift 从头部删除一个元素
// 栈与队列

// 栈: 后进先出(LIFO): 最后进入的元素最先出来
// 队列: 先进先出(FIFO): 最先插入的数据最先出来

// 1. 栈操作: 尾部进行
$stack = [];
// 1.1.  array_push: 进栈, 返回数量
echo array_push($stack, 10) . '<br>';
echo array_push($stack, 20, 30) . '<br>';
print_r($stack);
echo '<hr>';
// 1.2. array_pop: 出栈, 返回元素
echo array_pop($stack) . '<br>';
echo array_pop($stack) . '<br>';
echo array_pop($stack) . '<br>';
var_dump(array_pop($stack));
echo  '<hr>';

// 2. array_unshift: 栈操作: 头部进行, 返回数量
$stack = [];
// 2.1 入栈
echo array_unshift($stack, 'one') . '<br>';
echo array_unshift($stack, 'two', 'three') . '<br>';
print_r($stack);
echo '<hr>';
// 2.2 array_shift: 出栈, 返回元素
echo array_shift($stack) . '<br>';
echo array_shift($stack) . '<br>';
echo array_shift($stack) . '<br>';
var_dump(array_pop($stack));
echo  '<hr>';

// 3. 队列:
// 尾部添加, 头部出队 array_push()+array_shift()
// 进队
$queue = [];
echo array_push($queue, 10, 20, 30) . '<br>';
print_r($queue);
echo '<hr>';
//出队
echo array_shift($queue) . '<br>';
echo array_shift($queue) . '<br>';
echo array_shift($queue) . '<br>';

// 头部添加入队, 尾部出队 array_unshift() + array_pop()
$queue = [];
echo array_unshift($queue, 'one', 'two', 'three');
print_r($queue);
echo '<hr>';
echo array_pop($queue) . '<br>';
echo array_pop($queue) . '<br>';
echo array_pop($queue) . '<br>';
var_dump(array_pop($queue));
echo  '<hr>';

2.6 排序

2.6.1 对值排序

序号 函数 描述
1 sort 按值升序排序, 索引重排
2 asort 按值升序排序, 索引保持不变
3 rsort 按值降序排序, 索引重排
4 arsort 按值降序排序, 索引保持不变

2.6.2 对键排序

序号 函数 描述
1 ksort 按键名升序排序
2 krsort 按键名降序排序

2.6.3 自定义排序

序号 函数 描述
1 usort 自定义函数对值进行排序
2 uasort 自定义函数对值排序并保持索引不变
3 uksort 自定义函数对键名进行排序

2.6.4 自然排序

序号 函数 描述
1 natsort 支持数字型字符串排序
2 natcasesort 不区分大小写

2.6.5 乱序反转

序号 函数 描述
1 shuffle 随机打乱一个数组的顺序
2 array_flip 交换数组中的键和值
3 array_reverse 反转一个数组

示例:

// 排序: 参数是引用传值, 直接更新原始数组
// 1. 对值排序
$arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46];
printf('原始数组:<pre>%s</pre><hr>', print_r($arr, true));
// 1.1升序
// 升序: 索引重置
sort($arr);
printf('升序索引重置:<pre>%s</pre>', print_r($arr, true));

// 升序: 索引保持不变
// 数组还原, 便于观察排序结果
$arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46];
asort($arr);
printf('升序索引不变:<pre>%s</pre>', print_r($arr, true));

// 1.2 降序
// 降序: 索引重置
$arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46];
rsort($arr);
printf('降序索引重置:<pre>%s</pre>', print_r($arr, true));

// 降序: 索引保持不变
$arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46];
arsort($arr);
printf('降序索引不变:<pre>%s</pre>', print_r($arr, true));

echo '<hr>';

// 2. 对键排序
$arr = ['e' => 10, 'a' => 30, 'p' => 50];
// 2.1 按键名升序
ksort($arr);
printf('按键名升序:<pre>%s</pre>', print_r($arr, true));

// 2.2 按键名降序
$arr = ['e' => 10, 'a' => 30, 'p' => 50];
krsort($arr); // 降序
printf('按键名降序:<pre>%s</pre>', print_r($arr, true));

echo '<hr>';

// 3. 自定义排序
$arr = [90, 33, 4, 10, 2, 12];
// 3.1 自定义升序
usort($arr, function ($a, $b) {
    return $a - $b;
});
printf('自定义升序:<pre>%s</pre>', print_r($arr, true));
// 3.2 自定义降序
$arr = [90, 33, 4, 10, 2, 12];
uasort($arr, function ($a, $b) {
    return $a - $b;
});
printf('自定义升序且索引不变:<pre>%s</pre>', print_r($arr, true));

echo '<hr>';

// 4. 自然排序
$arr = ['img1.jpg', 'img5.jpg', 'img10.jpg', 'img8.jpg'];
sort($arr);
// 不能正确识别出字母数字字符串 "1" 和 "10" 之间的区别
printf('普通升序:<pre>%s</pre>', print_r($arr, true));
$arr = ['img1.jpg', 'img5.jpg', 'img10.jpg', 'img8.jpg'];
// 自然排序可以正确识别出字母数字字符串中的数值
natsort($arr);
printf('自然升序:<pre>%s</pre>', print_r($arr, true));

echo '<hr>';

// 5. 乱序反转
$arr = ['id' => 109, 'username' => 'peter', 'age' => 27, 'salary' => 99999];
// 随机打乱一个数组,引用传参, 会改变原数组
shuffle($arr);
printf('随机扰乱:<pre>%s</pre>', print_r($arr, true));
// 翻转一个数组,返回一个新数组,翻转是指第一个变成最后一个,依次类推
$arr = array_reverse($arr);
printf('翻转数组:<pre>%s</pre>', print_r($arr, true));

$arr = ['name' => 'admin', 'age' => 30, 'salary' => 8888];
// 注意键名的合法性,如果不是"integer"或"string"会有警告,且不会出现在结果中
$arr = ['name' => 'admin', 'age' => 30, 'salary' => false];
// 交换键值
$arr  = array_flip($arr);
printf('交换键值:<pre>%s</pre>', print_r($arr, true));

2.7 查询与替换

序号 函数 描述
1 array_slice 从数组中取出一部分
2 array_splice 去掉数组中一部分并用其它值代替
3 array_rand 从数组中随机取出一个或多个元素的键名
4 array_column 获取多维数组中一列组成的新数组
5 array_replace 使用后面数组的值替换第一个数组的值
6 array_replace_recursive 使用传递的数组递归替换第一个数组的元素
7 array_intersect 计算数组的交集
8 array_intersect_assoc 返回数组交集,键名也做比较
9 array_diff 返回数组的差集
10 array_diff_assoc 返回数组差集,键名也做比较

示例:

## 查询与替换

// 1. array_slice($arr,$offset,$length,$flag): 从数组中取出一部分
$stu = ['id' => 101, 'name' => '无忌', 'age' => 20, 'course' => 'php', 'grade' => 80];
// offset=0: 获取从索引0开始直到结束,即获取全部元素,这不是这个函数的主要使用场景
$res = array_slice($stu, 0);
// 获取前2个
$res = array_slice($stu, 0, 2);
// 从第2个开始获取3个
$res = array_slice($stu, 1, 3);
// 第2个参数支持负数,数组索引反序从-1开始,-3表示从倒数第3个
// 从倒数第3个开始,获取2个
$res = array_slice($stu, -3, 2);
// 第3个参数也支持负数,表示元素区间的结束索引(返回结果不包括结束索引对应的元素)
// 注意结果中并不包括索引-1对应元素'grade'
$res = array_slice($stu, 1, -1);
// 第4个参数是布尔值,默认为false,针对索引数组才有意义
// 将$stu转为索引数组, false表示, 获取到的部分元素,索引重置,即从0开始重排
$res = array_slice(array_values($stu), 1, -1, false);
// true: 表示保持元素在原始数组中的索引不变
$res = array_slice(array_values($stu), 1, -1, true);
printf('<pre>%s</pre>', print_r($res, true));

echo '<hr>';

// 2. array_splice(&$arr...): 去掉数组中一部分并用其它值代替,引用传参,会更新原数组,键名自动重置
// 该函数功能非常强大,具有数组元素的: 删除, 替换, 增加功能
$arr = [10, 28, 9, 33, 56, 21, 82, 47];
printf('原始数组元素: <pre>%s</pre>', print_r($arr, true));
// 2.1 删除: 指定起始索引和元素数量即可,从第2个元素开始删除2个,返回被删除的元素
// $res = array_splice($arr, 1,2);
// 2.2 替换: 传入第3个数组参数, 替换掉被删除的元素,如果数组元素数量与被删除元素数量相等,则可视为更新操作
// 为了便于观察结果,请将上一条array_splice()语句注释掉
// $res = array_splice($arr, 1,2, [888, 999]);
// 如果只替换一个元素,则第四个参数不需要以数组形式出现,单值即可
// $res = array_splice($arr, 1,2, 888);
// 2.3 增加: 如果第3个参数length的值为0,而又提供了第4个参数,表示不会有元素被删除,新元素会被插入到数组中
// $res = array_splice($arr, 1,0, [888, 999]);
// 第2与第3个参数也支持负数,含义与array_slice()一样
// 将从倒数第3个元素开始的2个元素,替换成888,999
// $res = array_splice($arr, -3,2, [888, 999]);
// 将从倒数第4个位置到倒数第2个位置之间的元素替换成888,999 (注意不包括-2位置的元素)
$res = array_splice($arr, -4, -2, [888, 999]);
printf('被删除的元素:<pre>%s</pre>', print_r($res, true));
printf('当前数组元素: <pre>%s</pre>', print_r($arr, true));

echo '<hr>';

// 3. array_rand: 从数组中随机取出一个或多个元素的键名,支持索引与关联数组
$arr = ['一等奖', '二等奖', '三等奖', '谢谢参与'];
// 如果只传入一个参数,即数组,则只返回一个随机的键名
$res = array_rand($arr);
printf('%s<br>', $res);
// 当然这个键名对用户来说意义不大,用户真正感兴趣的是键名对应的值
printf('[%s] => %s<br>', $res, $arr[$res]);
// 第二个参数是一个正整数,表示要取出的元素数量,返回一个键名组成的一维数组
// 例如,一次性随机取出三个,提高中奖率
$res = array_rand($arr, 3);
printf('<pre>%s</pre>', print_r($res, true));
// 遍历键名数组,查看对应的中奖情况
foreach ($res as $key) {
    printf('%s<br>', $arr[$key]);
}

echo '<hr>';

// 4. array_column: 获取多维数组中一列组成的新数组
$arr = null;
$arr[] = ['id' => 101, 'name' => 'jack', 'age' => 20];
$arr[] = ['id' => 102, 'name' => 'mike', 'age' => 30];
$arr[] = ['id' => 103, 'name' => 'pony', 'age' => 40];

// 只指定返回数组的列名称, 默认返回列值组成的一维索引数组,键名为默认值
$res = array_column($arr, 'name');
// 为了更加精准描述结果,允许自定义返回数组的键名,键名须是原数组中除第2个参数之外键名
$res = array_column($arr, 'name', 'id');
printf('<pre>%s</pre>', print_r($res,true));
// 这个参数是数据表查询, 获取单个字符的值时非常有用

echo '<hr>';

// 5. array_replace: 使用后面数组的值替换第一个数组的值, 同名的键名会彼此覆盖,适合自定义配置参数
$arr = ['type'=>'mysql', 'host'=>'localhost', 'username'=>'root', 'password'=>'root'];
$arr1 = ['host'=>'127.0.0.1', 'username'=>'admin'];
$arr2 = ['username'=>'peter', 'password'=>'123456'];
$res =array_replace($arr, $arr1, $arr2);
printf('<pre>%s</pre>', print_r($res,true));

echo '<hr>';

// 6. array_intersect: 计算数组的交集
$arr1 = [10, 20, 30, 40, 'php'];
$arr2 = [1,'php', 20, 30, 5];
$arr3 = ['a','c', 'php', 30, 10, 20];
// 交集,即返回多个数组中, 都存在的元素
$res = array_intersect($arr1, $arr2, $arr3); // 20, 30, 'php'
printf('<pre>%s</pre>', print_r($res,true));
// array_intersect_assoc: 返回数组交集,键名也做比较,

echo '<hr>';

// 7. array_diff:返回数组的差集
// 从第一个参数$arr数组中, 去掉在$arr2, $arr3中存在的元素
// 可理解为减法: $arr1 - $arr2 - $arr3 ,最终剩下的是只存在于$arr1中的元素
$res = array_diff($arr1, $arr2, $arr3);
printf('<pre>%s</pre>', print_r($res,true)); // 只剩下40
// array_diff_assoc: 返回数组差集,键名也做比较,请同学位自行测试

2.8 分割与合并

序号 函数 描述
1 array_combine 通过合并两个数组来创建一个新数组
2 array_merge 把一个或多个数组合并为一个数组
3 array_chunk 将一个数组分割成多个子数组

示例:

// 分割与合并
// 1. array_combine: 通过合并两个数组(一个是"键数组",一个是"值数组")来创建一个新数组
$keys = ['type', 'host', 'dbname', 'username', 'password'];
$values = ['mysql', 'localhost', 'phpedu', 'root', 'root'];
$res = array_combine($keys, $values);
printf('<pre>%s</pre>', print_r($res,true));

echo '<hr>';

// 2. array_merge($arr1, $arr2,...): 把一个或多个数组合并为一个数组
// 这个功能经常被用在项目配置上, 使用用户自定义配置项覆盖项目默认配置顶
$default= ['host'=>'localhost', 'username'=>'root', 'password'=>'root'];
$custom = ['username'=>'admin', 'password'=>'123456'];
$res = array_merge($default, $custom);
printf('<pre>%s</pre>', print_r($res,true));

echo '<hr>';

// 3. array_chunk`: 将一个数组分割成多个子数组,在海量数据查询时非常实用
// 注意, 这是数据分块, 不是分页, 也不能代替分页查询
$arr = range(1,20);
$res = array_chunk($arr, 6);
printf('<pre>%s</pre>', print_r($res,true));

2.9 自动生成

序号 函数 描述
1 array_fill 用给定的值填充数组
2 array_fill_keys 使用指定的键和值填充数组
3 array_pad 以指定长度将一个值填充进数组

示例:

// 自动生成

// 1.array_fill: 用给定的值填充数组
$res = array_fill(2, 5, 'demo');
printf('<pre>%s</pre>', print_r($res, true));

echo '<hr>';

// 2. array_fill_keys: 使用指定的键和值填充数组,注意键名各不相同, 但值是一样的
// 先创建一个键名数组
$keys = ['id', 'name', 'age', 'email'];
$res = array_fill_keys($keys, 'demo');
printf('<pre>%s</pre>', print_r($res, true));

echo '<hr>';

// 3. array_pad`:  以指定长度将一个值填充进数组
$arr = ['apple', 'dell', 'thinkpad'];
$res = array_pad($arr, 6, 'computer');
printf('<pre>%s</pre>', print_r($res, true));

2.10 类型转换

序号 函数 描述
1 list 将数组中的值赋予一组变量(类似解构赋值)
2 implode 将数组元素按指定字符拼装成字符串
3 explode 将字符串分割为数组
4 extract 将关联数组拆分成变量名值对
5 compact 将一组变量名值对拼装成一个关联数组键值对

示例:

<?php
// 类型转换

// 1.list: 将数组中的值赋予一组变量(类似解构赋值)
// 索引数组转变量
list($id, $name) = [10, 'admin'];
printf('$id = %s, $name = %s <br>', $id, $name);
// php7+, 支持关联数组元素转变量
list('id'=>$id, 'name'=>$name) = ['id'=>20, 'name'=>'peter'];
printf('$id = %s, $name = %s <br>', $id, $name);
// 取一部分值
list(,,$email) = [10, 'admin', 'admin@php.cn'];
echo $email . '<br>';

echo '<hr>';

// 2. implode: 将数组元素按指定字符拼装成字符串
$arr = ['huawei', 'xiaome', 'apple', 'oppo', 'vivo'];
echo implode(', ', $arr);

echo '<hr>';

// 3. explode`: 将字符串分割为数组
$str = 'blue, green, yellow, red, coral';
// 注意, 逗号后面要有一个空格, 这样才能与原始字符串对应上
$res = explode(', ', $str);
printf('<pre>%s</pre>', print_r($res, true));

echo '<hr>';

// 4. extract: 将关联数组拆分成变量名值对
// 以pdo连接参数为例进行演示
$config = ['type'=>'mysql','host'=>'localhost', 'dbname'=>'phpedu', 'charset'=>'utf8'];
extract($config);
// 拼装dsn字符串
$dsn = sprintf('%s:host=%s; dbname=%s; charset=%s',$type,$host, $dbname, $charset);
echo $dsn , '<br>';
// 连接数据库,先创建数据库phpedu,防止连接失败, 用户名密码采用默认值:root
$pdo = new PDO($dsn, 'root', 'root');
var_dump($pdo);

echo '<hr>';

// 5. compact: 将一组变量名值对拼装成一个关联数组键值对
$id = 99;
$name = 'Peter Zhu';
$job = 'Lecture';

// 传统方式, 手工创建关联数组,将变量值做为元素值填充
$res = ['id'=>$id, 'name'=>$name, 'job'=>$job];
printf('<pre>%s</pre>', print_r($res, true));

// 使用compace()可一步到位
$res = compact('id', 'name', 'job');
printf('<pre>%s</pre>', print_r($res, true));

2.11 回调处理

序号 函数 描述
1 array_filter 用回调函数过滤数组中的单元
2 array_map 为数组的每个元素应用回调函数
3 array_reduce 用回调函数迭代地将数组简化为单一的值
4 array_walk 使用用户自定义函数对数组中的每个元素做回调处理

示例:

<?php
// 数组元素的回调处理

// 1. array_filter: 用回调函数过滤数组中的单元,返回回调执行为true的元素组成的新数组
$arr = [150,'php', true,[4,5,6], (new class {}), [], null, false,'', 0, '0'];
// 利用回调只返回运算结果为true元素特征, 可以过滤掉数组中的可转为false的值
// 自动转换为false的值包括但不限于: null, false, 空数组, 空字符串, 0, '0'
// 提示: 空对象不能转为false, 空数组可以
// 省略回调参数, 则自动过滤掉数组中可转为false的值,实现过滤空值的效果
$res = array_filter($arr);
printf('<pre>%s</pre>', print_r($res,true));
// 自定义回调函数参数, 返回运算结果为true的值组成的数组
$res = array_filter($arr, function($value) {
    // 只返回标量类型的元素: interger, float, string, boolean
    // 所以, 被过滤掉的元素类型是array, object, 包括空数组,空对象
    return is_scalar($value);
});
printf('<pre>%s</pre>', print_r($res,true));

echo '<hr>';

// 2 array_map: 为数组的每个元素应用回调函数,返回回调处理后的所有元素组成的 "新数组"
$arr = ['php',[3,4,5], (new class {public $name='电脑';public $price=8888;}), 15, 20];

$res = array_map(function ($item){
    switch (gettype($item)) {
        case 'object':
            $item = get_object_vars($item);
        case 'array':
            $item = implode(', ', $item);
    }
    return $item;
}, $arr);
printf('<pre>%s</pre>', print_r($res,true));

// 同时处理多个数组,例如将一个键名与值的二个数组进行组装
$keys = ['host', 'username', 'password'];
$values = ['localhost', 'root', '123456'];
// 当然,使用前面学过的: array_combine()可以轻松实现
$res = array_combine($keys, $values);
printf('<pre>%s</pre>', print_r($res,true));
// 其实,使用array_map()也可以实现同样功能
$res = array_map(function ($value1, $value2) {
    return [$value1 => $value2];
}, $keys, $values);
printf('<pre>%s</pre>', print_r($res,true));
// 不过, 返回的是一个二维数组, 如果要获取用户名,需要这样做,比较麻烦
echo '用户名: ' . $res[1]['username'];
// 下面我们用数组迭代函数实现同样功能来拉平这个数组,模拟array_combine()函数的功能
echo '<hr>';


// 自定义数组迭代处理函数: my_array_reduce($array, $callback, $init=null)
// $callback回调中的二个参数
// $prev: 上一次迭代处理的结果,如果是第一次迭代,它的值是第三个参数$init提供的初始值
// $current: 本次需要迭代处理的值
// $init: 可选, 在迭代处理前,或者处理结束后,数组为空时的最后一个结果
function my_array_reduce($array, $callback, $init=null)
{
    // $prev的初始值
    $prev = $init;
    foreach($array as $current){
        // 为数组中每一个元素调用迭代回调函数进行处理
        $prev = $callback($prev, $current);
    }
    // 将最终结果通过前一次迭代变量返回
    return $prev;
}

$result = my_array_reduce($res, function ($prev, $current) {
    // 获取当前元素的键值
    $key = key($current);
    $value = current($current);
    // 将键值对拼装成一个元素, 利用$prev,将结果返回
    $prev[$key] = $value;
    return $prev;
});
printf('自定义数组迭代函数返回值:<pre>%s</pre>', print_r($result,true));

echo '<hr>';

// 幸运的是, 我们不用自定义数组迭代处理函数, 系统已经为我们预置了
// 3. array_reduce($arr, $callback($prev, $current), $init): 用回调函数迭代地将数组简化为单一的值
// $res: 它是前面array_map()的返回值,是一个二维数组
$res = array_reduce($res, function ($prev, $current) {
    // 获取当前元素的键值
    $key = key($current);
    $value = current($current);
    // 将键值对拼装成一个元素, 利用$prev,将结果返回
    $prev[$key] = $value;
    return $prev;
});
printf('内置数组迭代函数返回值:<pre>%s</pre>', print_r($res,true));

echo '<hr>';

// 4. array_walk: 使用用户自定义函数对数组中的每个元素做回调处理, 返回布尔值
// array_walk($arr, callback($value, $key), $userdata)
// 回调的第一个参数$value,如果设置为引用(&$value),则所做的修改直接作用到原始数组本身
// 如果提供了第三个参数$userdata,则做为回调的第三个参数传入
// 这个函数不受数组内部指针约束, 不论当前指针在哪,都会遍历整个数组
// 该函数主要用于在遍历数组的时候进行一些自定义操作, 例如元素的格式化等, 所以常在回调中使用输出语句
// 例如,将数组元素的值,描红输出
$res = ['id'=>123, 'name'=>'peter', 'email'=>'peter@php.cn'];
array_walk($res, function ($value, $key, $color){
    printf('[ %s ] => <span style="color:%s">%s</span><br>', $key, $color, $value);
}, 'red');