提供一组静态方法,覆盖数组清洗、列提取、哈希映射、分组、树形转换、多列排序等高频操作,代码复用率极高,适合作为项目基础库。
class ArrayHelper {
/**
* 递归移除数组中空白元素 (含纯空白字符)
* @param array $arr 引用传递,原地修改
* @param bool $trim 是否 trim 非空元素
*/
public static function removeEmpty(array &$arr, bool $trim = true): void {
foreach ($arr as $key => $value) {
if (is_array($value)) {
self::removeEmpty($arr[$key], $trim);
} else {
$value = trim($value);
if ($value === '') {
unset($arr[$key]);
} elseif ($trim) {
$arr[$key] = $value;
}
}
}
}
/**
* 从二维数组提取指定列的所有值
* @param array $arr 数据源
* @param string $col 列名
* @return array 值数组
*/
public static function getCols(array $arr, string $col): array {
$ret = [];
foreach ($arr as $row) {
if (isset($row[$col])) $ret[] = $row[$col];
}
return $ret;
}
/**
* 二维数组转哈希映射 (键值对)
* @param array $arr 数据源
* @param string $keyField 作为键的字段
* @param string|null $valueField 作为值的字段,null 则整行作值
* @return array 键值映射数组
*/
public static function toHashmap(array $arr, string $keyField, string $valueField = null): array {
$ret = [];
if ($valueField) {
foreach ($arr as $row) $ret[$row[$keyField]] = $row[$valueField];
} else {
foreach ($arr as $row) $ret[$row[$keyField]] = $row;
}
return $ret;
}
/**
* 二维数组按指定字段分组
* @param array $arr 数据源
* @param string $keyField 分组依据字段
* @return array 分组后数组 [key => [rows...]]
*/
public static function groupBy(array $arr, string $keyField): array {
$ret = [];
foreach ($arr as $row) {
$key = $row[$keyField];
$ret[$key][] = $row;
}
return $ret;
}
/**
* 扁平数组转树形结构 (引用赋值,O(N) 单遍历)
* @param array $arr 数据源 (含 id, parent_id)
* @param string $keyNodeId 节点ID字段
* @param string $keyParentId 父ID字段
* @param string $keyChildrens 子节点容器字段
* @param array|null $refs 输出节点引用表 [id => &node]
* @return array 树形数组
*/
public static function toTree(array $arr, string $keyNodeId, string $keyParentId = 'parent_id', string $keyChildrens = 'childrens', array &$refs = null): array {
$refs = [];
// 1. 初始化子节点容器 + 建立引用表
foreach ($arr as $offset => $row) {
$arr[$offset][$keyChildrens] = [];
$refs[$row[$keyNodeId]] = &$arr[$offset];
}
// 2. 组装树
$tree = [];
foreach ($arr as $offset => $row) {
$parentId = $row[$keyParentId];
if ($parentId) {
if (!isset($refs[$parentId])) { // 孤儿节点当根
$tree[] = &$arr[$offset];
continue;
}
$refs[$parentId][$keyChildrens][] = &$arr[$offset];
} else {
$tree[] = &$arr[$offset];
}
}
return $tree;
}
/**
* 树形数组展开为扁平数组 (逆向操作)
* @param array $tree 树形数组
* @param string $keyChildrens 子节点字段
* @return array 扁平数组
*/
public static function treeToArray(array $tree, string $keyChildrens = 'childrens'): array {
$ret = [];
if (isset($tree[$keyChildrens]) && is_array($tree[$keyChildrens])) {
foreach ($tree[$keyChildrens] as $child) {
$ret = array_merge($ret, self::treeToArray($child, $keyChildrens));
}
unset($tree[$keyChildrens]);
}
$ret[] = $tree;
return $ret;
}
/**
* 单列排序 (升序/降序)
* @param array $array 待排序数组
* @param string $keyname 排序键
* @param int $dir SORT_ASC/SORT_DESC
* @return array 排序后数组
*/
public static function sortByCol(array $array, string $keyname, int $dir = SORT_ASC): array {
return self::sortByMultiCols($array, [$keyname => $dir]);
}
/**
* 多列排序 (类比 SQL ORDER BY col1 ASC, col2 DESC)
* @param array $rowset 待排序二维数组
* @param array $args ['col1' => SORT_ASC, 'col2' => SORT_DESC]
* @return array 排序后数组
*/
public static function sortByMultiCols(array $rowset, array $args): array {
$sortArrays = [];
$sortRule = '';
foreach ($args as $field => $dir) {
foreach ($rowset as $offset => $row) {
$sortArrays[$field][$offset] = $row[$field];
}
$sortRule .= '$sortArrays[\'' . $field . '\'], ' . $dir . ', ';
}
if (!$sortArrays) return $rowset;
eval('array_multisort(' . $sortRule . '$rowset);'); // 动态构造调用
return $rowset;
}
}
$data = ['name' => ' John ', 'email' => '', 'tags' => ['php', ' ', 'java']]; ArrayHelper::removeEmpty($data); // 结果: ['name' => 'John', 'tags' => ['php', 'java']]
$orders = [
['id' => 1, 'amount' => 100],
['id' => 2, 'amount' => 200],
];
$ids = ArrayHelper::getCols($orders, 'id'); // [1, 2]
$sql = 'SELECT * FROM products WHERE id IN (' . implode(',', $ids) . ')';
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
];
$map = ArrayHelper::toHashmap($users, 'id', 'name'); // [1 => 'Alice', 2 => 'Bob']
echo $map[1]; // 直接命中,无需循环
$orders = [
['id' => 1, 'status' => 'paid'],
['id' => 2, 'status' => 'pending'],
['id' => 3, 'status' => 'paid'],
];
$grouped = ArrayHelper::groupBy($orders, 'status');
// ['paid' => [[id=>1], [id=>3]], 'pending' => [[id=>2]]]
$categories = [
['id' => 1, 'parent_id' => 0, 'name' => '电子产品'],
['id' => 2, 'parent_id' => 1, 'name' => '手机'],
['id' => 3, 'parent_id' => 2, 'name' => 'iPhone'],
['id' => 4, 'parent_id' => 0, 'name' => '图书'],
];
$tree = ArrayHelper::toTree($categories, 'id', 'parent_id', 'children', $refs);
// 结果: 电子产品 -> 手机 -> iPhone; 图书
// 任意节点子树: $refs[2] 即手机及其所有子分类
$items = [
['parent' => 2, 'name' => 'B'],
['parent' => 1, 'name' => 'A'],
['parent' => 1, 'name' => 'C'],
];
$sorted = ArrayHelper::sortByMultiCols($items, [
'parent' => SORT_ASC,
'name' => SORT_DESC,
]);
// 结果: parent=1 (C, A), parent=2 (B)
ArrayHelper::method() 调用keyExists()、pluck() (别名 getCols)、flatten() (别名 treeToArray)declare(strict_types=1) + 返回类型声明vendor/array-helper,按 PSR-4 自动加载