Hyperf3.x函数合集

<?php

namespace App;

use Hyperf\Collection\Arr;

final class CustomUtil
{
    /**
     * 从原始数据中提取指定字段的值,并可进行键名映射、设置默认值和字符串裁剪
     *
     * @param array $originalData 原始数据数组
     * @param array $fields 字段配置数组,每个元素为一个字段的配置,格式如下:
     *                      [原键名, 默认值, 新键名, 是否裁剪(可选,默认true)]
     *                      - 原键名: 在原始数据中的键名
     *                      - 默认值: 如果原始数据中不存在该键,则使用此默认值
     *                      - 新键名: 提取后的新键名(可选,如果不填则使用原键名)
     *                      - 是否裁剪: 是否对字符串值进行trim操作(可选,默认true)
     * @return array 提取处理后的数据数组
     *
     * 示例:
     * $originalData = ['name' => ' test ', 'age' => 25, 'email' => 'test@example.com'];
     * $fields = [
     *     ['name', '', 'new_name'],           // 从'name'提取到'new_name',并裁剪空格
     *     ['age', 0],                        // 从'age'提取,保持原键名
     *     ['nonexistent', 'default_value'],   // 键不存在,使用默认值
     *     ['email', '', 'mail', false]       // 从'email'提取到'mail',但不裁剪
     * ];
     */
    public static function getParams(array $originalData, array $fields)
    {
        $data = Arr::mapWithKeys($fields, static function ($field) use ($originalData) {
            if (!is_array($field)) {
                return [];
            }

            $originalKey = Arr::get($field, 0); // 获取原始键名
            if (!$originalKey) {
                return [];
            }

            $value = Arr::get($originalData, $originalKey, Arr::get($field, 1)); // 获取原始数据中的值,如果不存在则使用默认值
            if (is_string($value) && Arr::get($field, 3, true)) { // 检查是否需要裁剪字符串
                $value = trim($value);
            }

            $newKey = Arr::get($field, 2) ?: $originalKey; // 获取新键名,如果未指定则使用原始键名
            return [$newKey => $value]; // 返回新键值对
        });

        return $data;
    }

    /**
     * 获取数组最大嵌套深度(标准定义)
     *
     * @param mixed $arr 待检测的变量
     * @return int 深度值(空数组为 1,非数组为 0)
     */
    public static function getArrayDepth($arr): int
    {
        if (!is_array($arr)) {
            return 0;
        }

        if (empty($arr)) {
            return 1;
        }

        $stack = [[$arr, 1]]; // [当前数组, 当前层级]
        $maxDepth = 1;

        while (!empty($stack)) {
            [$currentArray, $level] = array_pop($stack);
            $maxDepth = max($maxDepth, $level);

            foreach ($currentArray as $value) {
                if (is_array($value)) {
                    $stack[] = [$value, $level + 1];
                }
            }
        }

        return $maxDepth;
    }

    /**
     * 将扁平化的数组结构转换为树形结构
     * 
     * 此方法通过指定的ID字段和父级ID字段,将一维数组转换为具有父子关系的多维树形结构
     * 支持自动生成子节点列表,如果根节点无法直接识别(没有id为0的项),则会尝试找出最顶层的节点作为根节点
     *
     * @param array $data 包含扁平化数据的数组,每个元素应包含id和parent_id字段
     * @param string $idKey 用于标识唯一性的字段名称,通常是主键字段名
     * @param string $parentIdKey 用于表示父级关系的字段名称,通常是外键字段名
     * @return array 转换后的树形结构数组
     *
     * 示例:
     * $data = [
     *     ['id' => 1, 'name' => 'Parent 1', 'pid' => 0],
     *     ['id' => 2, 'name' => 'Child 1', 'pid' => 1],
     *     ['id' => 3, 'name' => 'Child 2', 'pid' => 1],
     *     ['id' => 4, 'name' => 'Grandchild 1', 'pid' => 2]
     * ];
     * $tree = CustomUtil::generateTree($data, 'id', 'pid');
     * 
     * 结果将是:
     * [
     *     [
     *         'id' => 1,
     *         'name' => 'Parent 1',
     *         'pid' => 0,
     *         'child' => [
     *             [
     *                 'id' => 2,
     *                 'name' => 'Child 1',
     *                 'pid' => 1,
     *                 'child' => [
     *                     // ...
     *                 ]
     *             ],
     *             // ...
     *         ]
     *     ]
     * ]
     */
    public static function generateTree(array $data, string $idKey, string $parentIdKey)
    {
        // 创建一个以父级ID为键的映射表,用于快速查找子节点
        $map = [];
        foreach ($data as &$item) {
            $map[$item[$parentIdKey]][] = &$item;
        }

        // 遍历所有数据项,将子节点添加到父节点的child属性中
        foreach ($data as &$item) {
            if (isset($map[$item[$idKey]])) {
                $item['child'] = $map[$item[$idKey]];
            }
        }
        // 解除引用,避免潜在的内存泄漏或意外修改
        unset($item);

        // 如果存在以0为键的项(通常代表顶级节点),则直接返回
        if (isset($map[0])) {
            return $map[0];
        } else {
            // 否则,寻找最深层级的节点作为根节点返回
            $depths = Arr::mapWithKeys($map, function ($item, $id) {
                return [$id => self::getArrayDepth($item)];
            });
            $maxDepth = max($depths);
            $parentIds = [];
            foreach ($depths as $parentId => $depth) {
                if ($depth === $maxDepth) {
                    $parentIds[] = $parentId;
                }
            }
            return array_column(Arr::only($map, $parentIds), 0);
        }
    }
}

 

posted @ 2026-01-14 10:47  tros  阅读(3)  评论(0)    收藏  举报