|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace Hejunjie\Utils; |
| 4 | + |
| 5 | +/** |
| 6 | + * 数组处理类 |
| 7 | + * |
| 8 | + * @package Hejunjie\Utils |
| 9 | + */ |
| 10 | +class Arr |
| 11 | +{ |
| 12 | + /** |
| 13 | + * 获取两个数组的交集 |
| 14 | + * |
| 15 | + * @param array $array1 数组1 |
| 16 | + * @param array $array2 数组2 |
| 17 | + * |
| 18 | + * @return array |
| 19 | + * @throws Exception |
| 20 | + */ |
| 21 | + public static function arrayIntersect(array $array1, array $array2): array |
| 22 | + { |
| 23 | + // 检查输入的两个参数是否都是数组 |
| 24 | + if (!is_array($array1) || !is_array($array2)) { |
| 25 | + throw new \Exception('输入的参数必须是数组'); |
| 26 | + } |
| 27 | + return array_intersect($array1, $array2); |
| 28 | + } |
| 29 | + |
| 30 | + /** |
| 31 | + * 根据二维数组中的指定字段排序 |
| 32 | + * |
| 33 | + * @param array $array 二维数组 |
| 34 | + * @param string $field 排序字段 |
| 35 | + * @param bool $ascending 是否按升序排序(默认升序) |
| 36 | + * |
| 37 | + * @return array |
| 38 | + * @throws Exception |
| 39 | + */ |
| 40 | + public static function sortByField(array $array, string $field, bool $ascending = true): array |
| 41 | + { |
| 42 | + // 检查数组中的每个元素是否为数组,并且包含指定的字段 |
| 43 | + foreach ($array as $item) { |
| 44 | + if (!is_array($item)) { |
| 45 | + throw new \Exception('输入的数组中的每个元素必须是关联数组'); |
| 46 | + } |
| 47 | + if (!array_key_exists($field, $item)) { |
| 48 | + throw new \Exception("字段 '$field' 不存在于数组中的某些元素中"); |
| 49 | + } |
| 50 | + } |
| 51 | + // 使用 usort 对数组进行排序 |
| 52 | + usort($array, function ($a, $b) use ($field, $ascending) { |
| 53 | + return $ascending ? $a[$field] <=> $b[$field] : $b[$field] <=> $a[$field]; |
| 54 | + }); |
| 55 | + return $array; |
| 56 | + } |
| 57 | + |
| 58 | + /** |
| 59 | + * 根据二维数组中指定字段去重 |
| 60 | + * |
| 61 | + * @param array $array 二维数组 |
| 62 | + * @param string $field 指定的去重字段 |
| 63 | + * |
| 64 | + * @return array |
| 65 | + * @throws Exception |
| 66 | + */ |
| 67 | + public static function removeDuplicatesByField(array $array, string $field): array |
| 68 | + { |
| 69 | + // 用于记录字段值的数组 |
| 70 | + $unique = []; |
| 71 | + // 存储去重后的结果数组 |
| 72 | + $result = []; |
| 73 | + // 遍历数组,检查并去重 |
| 74 | + foreach ($array as $item) { |
| 75 | + // 确保每个项目是数组并且包含指定的字段 |
| 76 | + if (!is_array($item)) { |
| 77 | + throw new \Exception('输入的数组中的每个元素必须是关联数组'); |
| 78 | + } |
| 79 | + if (!array_key_exists($field, $item)) { |
| 80 | + throw new \Exception("字段 '$field' 不存在于数组中的某些元素中"); |
| 81 | + } |
| 82 | + // 如果该字段值不在unique数组中,则添加到结果中 |
| 83 | + if (!in_array($item[$field], $unique, true)) { |
| 84 | + $unique[] = $item[$field]; |
| 85 | + $result[] = $item; |
| 86 | + } |
| 87 | + } |
| 88 | + return $result; |
| 89 | + } |
| 90 | + |
| 91 | + /** |
| 92 | + * 根据二维数组中的指定字段进行分组 |
| 93 | + * |
| 94 | + * @param array $array 二维数组 |
| 95 | + * @param string $field 指定的分组字段 |
| 96 | + * |
| 97 | + * @return array |
| 98 | + * @throws Exception |
| 99 | + */ |
| 100 | + public static function groupByField(array $array, string $field): array |
| 101 | + { |
| 102 | + // 初始化分组数组 |
| 103 | + $grouped = []; |
| 104 | + // 遍历数组并根据字段进行分组 |
| 105 | + foreach ($array as $item) { |
| 106 | + // 确保每个项目是数组并且包含指定的字段 |
| 107 | + if (!is_array($item)) { |
| 108 | + throw new \Exception('输入的数组中的每个元素必须是关联数组'); |
| 109 | + } |
| 110 | + if (!array_key_exists($field, $item)) { |
| 111 | + throw new \Exception("字段 '$field' 不存在于数组中的某些元素中"); |
| 112 | + } |
| 113 | + // 按字段值进行分组 |
| 114 | + $grouped[$item[$field]][] = $item; |
| 115 | + } |
| 116 | + return $grouped; |
| 117 | + } |
| 118 | + |
| 119 | + /** |
| 120 | + * 数组转换为 CSV 格式的字符串 |
| 121 | + * |
| 122 | + * @param array $array 数组 |
| 123 | + * @param string $delimiter CSV 分隔符,默认为逗号 |
| 124 | + * @param string $enclosure CSV 包裹符号,默认为双引号 |
| 125 | + * @param string $escapeChar 转义符号,默认为反斜杠 |
| 126 | + * |
| 127 | + * @return string |
| 128 | + */ |
| 129 | + public static function arrayToCsv(array $array, string $delimiter = ',', string $enclosure = '"', string $escapeChar = '\\'): string |
| 130 | + { |
| 131 | + // 开启输出缓冲区 |
| 132 | + ob_start(); |
| 133 | + // 打开 PHP 输出流 |
| 134 | + $output = fopen('php://output', 'w'); |
| 135 | + // 检查文件句柄是否打开成功 |
| 136 | + if ($output === false) { |
| 137 | + throw new \Exception('无法打开输出流'); |
| 138 | + } |
| 139 | + // 遍历数组并写入 CSV 格式 |
| 140 | + foreach ($array as $row) { |
| 141 | + if (!is_array($row)) { |
| 142 | + throw new \Exception('输入的每一行都必须是一个数组'); |
| 143 | + } |
| 144 | + fputcsv($output, $row, $delimiter, $enclosure, $escapeChar); |
| 145 | + } |
| 146 | + // 关闭文件句柄 |
| 147 | + fclose($output); |
| 148 | + // 获取缓冲区内容 |
| 149 | + return ob_get_clean(); |
| 150 | + } |
| 151 | + |
| 152 | + /** |
| 153 | + * 解析 XML 数据并返回数组 |
| 154 | + * |
| 155 | + * @param string $xmlString XML 字符串 |
| 156 | + * |
| 157 | + * @return array 解析后的数组 |
| 158 | + * @throws \Exception |
| 159 | + */ |
| 160 | + public static function xmlParse(string $xmlString): array |
| 161 | + { |
| 162 | + // 禁用 libxml 错误和启用异常 |
| 163 | + libxml_use_internal_errors(true); |
| 164 | + // 加载 XML 字符串 |
| 165 | + $xml = simplexml_load_string($xmlString, "SimpleXMLElement", LIBXML_NOCDATA); |
| 166 | + // 检查 XML 是否加载成功 |
| 167 | + if ($xml === false) { |
| 168 | + $errors = libxml_get_errors(); |
| 169 | + libxml_clear_errors(); |
| 170 | + throw new \Exception("XML 解析错误: " . implode(", ", $errors)); |
| 171 | + } |
| 172 | + // 转换为数组 |
| 173 | + return self::xmlToArray($xml); |
| 174 | + } |
| 175 | + |
| 176 | + /** |
| 177 | + * 递归将 SimpleXMLElement 转换为数组 |
| 178 | + * |
| 179 | + * @param SimpleXMLElement $xml XML 元素 |
| 180 | + * @return array 转换后的数组 |
| 181 | + */ |
| 182 | + private static function xmlToArray($xml): array |
| 183 | + { |
| 184 | + $array = json_decode(json_encode($xml), true); |
| 185 | + // 处理每个元素 |
| 186 | + foreach ($array as $key => $value) { |
| 187 | + if (is_array($value)) { |
| 188 | + // 递归处理子元素 |
| 189 | + $array[$key] = self::xmlToArray($value); |
| 190 | + } |
| 191 | + } |
| 192 | + return $array; |
| 193 | + } |
| 194 | + |
| 195 | + /** |
| 196 | + * 将数组转换为 XML 字符串 |
| 197 | + * |
| 198 | + * @param array $data 要转换的数组 |
| 199 | + * @param string $rootElement 根元素名称 |
| 200 | + * @param SimpleXMLElement|null $xmlObject 用于递归的 SimpleXMLElement 对象 |
| 201 | + * |
| 202 | + * @return string 转换后的 XML 字符串 |
| 203 | + */ |
| 204 | + public static function arrayToXml(array $data, string $rootElement = 'root', \SimpleXMLElement $xmlObject = null): string |
| 205 | + { |
| 206 | + // 创建根元素 |
| 207 | + if ($xmlObject === null) { |
| 208 | + $xmlObject = new \SimpleXMLElement("<{$rootElement}/>"); |
| 209 | + } |
| 210 | + foreach ($data as $key => $value) { |
| 211 | + // 处理键名 |
| 212 | + $formattedKey = is_numeric($key) ? "item{$key}" : $key; |
| 213 | + // 如果值是数组,则递归调用 |
| 214 | + if (is_array($value)) { |
| 215 | + self::arrayToXml($value, $formattedKey, $xmlObject->addChild($formattedKey)); |
| 216 | + } else { |
| 217 | + // 添加值到 XML |
| 218 | + $xmlObject->addChild($formattedKey, htmlspecialchars($value)); |
| 219 | + } |
| 220 | + } |
| 221 | + return $xmlObject->asXML(); |
| 222 | + } |
| 223 | +} |
0 commit comments