切换菜单
用户头像
用户头像
未登录
wsf@example.com

👤 登录探索新世界

DataArray 类完整使用说明文档

类概述

DataArray 是一个强大的数组包装类,提供面向对象的数组操作方式,支持链式调用、点分隔符访问、通配符查找等高级功能。

主要特性

  • 链式操作:大部分方法支持链式调用

  • 智能查找:支持点分隔符和通配符查找

  • 只读模式:防止数据被意外修改

  • 多种构造:支持从JSON、对象、查询字符串创建

  • 丰富操作:包含排序、过滤、映射等完整数组操作

  • 强大搜索:支持递归搜索、通配符搜索、回调搜索

安装和实例化

基础实例化

use zxf\Util\Array\DataArray;

// 1. 基础实例化
$data = new DataArray(['name' => 'John', 'age' => 30]);

// 2. 从JSON创建
$jsonData = DataArray::fromJson('{"user": {"name": "John", "age": 30}}');

// 3. 从对象创建
$user = new stdClass();
$user->name = 'John';
$objectData = DataArray::fromObject($user);

// 4. 从查询字符串创建
$queryData = DataArray::fromQueryString('name=John&age=30&skills[]=php&skills[]=js');

// 5. 创建只读实例
$readOnlyData = DataArray::readOnly(['config' => 'value']);

空数组实例化

// 创建空实例
$emptyData = new DataArray();

// 批量添加数据
$emptyData->add([
    'user' => ['name' => 'John', 'age' => 30],
    'settings' => ['theme' => 'dark', 'notifications' => true]
]);

基础数据访问

基本访问方式

$data = new DataArray([
    'user' => [
        'name' => 'John',
        'profile' => [
            'age' => 30,
            'email' => 'john@example.com'
        ]
    ],
    'skills' => ['PHP', 'JavaScript', 'Python']
]);

// 1. 方法访问
echo $data->get('user.name'); // John
echo $data->get('user.profile.email'); // john@example.com

// 2. 数组式访问
echo $data['user.name']; // John
echo $data['user.profile.age']; // 30

// 3. 属性式访问(返回DataArray实例用于链式调用)
echo $data->user->name; // John

数据设置和修改

// 设置值
$data->set('user.location', 'New York');
$data['user.profile.phone'] = '123-456-7890';

// 批量设置
$data->add([
    'user.profile.company' => 'Tech Corp',
    'user.profile.title' => 'Developer'
]);

// 删除数据
$data->delete('user.profile.phone');
unset($data['user.profile.company']);

// 批量删除
$data->deleteMultiple(['user.location', 'user.profile.title']);

存在性检查

// 检查键是否存在
var_dump($data->has('user.name')); // true
var_dump($data->has('user.invalid')); // false
var_dump(isset($data->user->profile->age)); // true

// 点分隔符检查
var_dump($data->has('user.profile.email')); // true
var_dump($data->has('user.profile.invalid')); // false

高级数据访问

通配符查找

$data = new DataArray([
    'users' => [
        'user1' => ['name' => 'John', 'age' => 30],
        'user2' => ['name' => 'Jane', 'age' => 25],
        'group' => [
            'user3' => ['name' => 'Bob', 'age' => 35]
        ]
    ],
    'products' => [
        'product1' => ['name' => 'Phone', 'price' => 999],
        'product2' => ['name' => 'Laptop', 'price' => 1999]
    ]
]);

// 单级通配符 (*) - 下一级的所有匹配
$userNames = $data->get('users.*.name');
// 返回: ['John', 'Jane'] (不包含Bob)

// 多级通配符 (**) - 任意深度的所有匹配
$allNames = $data->get('users.**.name');
// 返回: ['John', 'Jane', 'Bob']

// 混合使用
$allPrices = $data->get('products.*.price');
// 返回: [999, 1999]

// 复杂通配符
$nestedData = $data->get('users.**.age');
// 返回: [30, 25, 35]

默认值处理

// 获取不存在的键时返回默认值
echo $data->get('nonexistent.key', 'default_value'); // default_value
echo $data->get('user.invalid', 'not_found'); // not_found

// 批量获取带默认值
$values = $data->getMultiple(['user.name', 'user.age', 'invalid.key'], 'default');
// 返回: ['user.name' => 'John', 'user.age' => 30, 'invalid.key' => 'default']

多层数据访问

$complexData = new DataArray([
    'company' => [
        'departments' => [
            'engineering' => [
                'teams' => [
                    'frontend' => ['members' => 5, 'tech' => 'React'],
                    'backend' => ['members' => 8, 'tech' => 'PHP']
                ]
            ],
            'marketing' => [
                'teams' => [
                    'social' => ['members' => 3, 'platform' => 'Twitter'],
                    'content' => ['members' => 4, 'platform' => 'Blog']
                ]
            ]
        ]
    ]
]);

// 深度访问
echo $complexData->get('company.departments.engineering.teams.backend.tech'); // PHP

// 通配符深度搜索
$allMembers = $complexData->get('company.departments.*.teams.*.members');
// 返回: [5, 8, 3, 4]

$allTech = $complexData->get('company.departments.**.tech');
// 返回: ['React', 'PHP']

数组操作

基本数组操作

$data = new DataArray(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 2]);

// 键值操作
$keys = $data->keys(); // ['a', 'b', 'c', 'd']
$values = $data->values(); // [1, 2, 3, 2]

// 栈操作
$data->unshift('first'); // 在开头添加元素
$first = $data->shift(); // 移除并返回第一个元素
$data->push('last'); // 在末尾添加元素
$last = $data->pop(); // 移除并返回最后一个元素

// 首尾元素
$first = $data->first(); // 第一个元素
$last = $data->last(); // 最后一个元素

// 随机元素
$random = $data->random(); // 随机一个元素
$randoms = $data->random(3); // 随机三个元素

数组合并

$data1 = new DataArray(['a' => 1, 'b' => ['c' => 2]]);
$data2 = new DataArray(['b' => ['d' => 3], 'e' => 4]);

// 普通合并(覆盖相同键)
$data1->merge($data2);
// 结果: ['a' => 1, 'b' => ['d' => 3], 'e' => 4]

// 递归合并(合并数组内容)
$data1->mergeRecursive(new DataArray(['b' => ['c' => 5, 'f' => 6]]));
// 结果: ['a' => 1, 'b' => ['d' => 3, 'c' => 5, 'f' => 6], 'e' => 4]

// 合并普通数组
$data1->merge(['g' => 7, 'h' => 8]);

数组转换操作

$data = new DataArray([
    ['id' => 1, 'name' => 'John', 'department' => 'Engineering'],
    ['id' => 2, 'name' => 'Jane', 'department' => 'Marketing'],
    ['id' => 3, 'name' => 'Bob', 'department' => 'Engineering']
]);

// 获取列
$names = $data->column('name'); // ['John', 'Jane', 'Bob']
$idNameMap = $data->column('name', 'id'); // [1 => 'John', 2 => 'Jane', 3 => 'Bob']

// 分组
$byDepartment = $data->groupBy(function($item) {
    return $item['department'];
});
/* 返回:
[
    'Engineering' => [
        ['id' => 1, 'name' => 'John', 'department' => 'Engineering'],
        ['id' => 3, 'name' => 'Bob', 'department' => 'Engineering']
    ],
    'Marketing' => [
        ['id' => 2, 'name' => 'Jane', 'department' => 'Marketing']
    ]
]
*/

// 分块
$chunks = $data->chunk(2); // 将数组分成每块2个元素

// 去重
$unique = $data->unique(); // 基于序列化去重

// 键值交换(仅支持字符串和整数)
$flipped = $data->flip();

搜索和查找

基础搜索

$data = new DataArray([
    'users' => [
        'john' => ['name' => 'John', 'age' => 30],
        'jane' => ['name' => 'Jane', 'age' => 25],
        'admin' => [
            'root' => ['name' => 'Root', 'age' => 40]
        ]
    ]
]);

// 基础值搜索(返回第一个匹配的键)
$key = $data->search('Jane'); // 'users.jane.name'

// 递归值搜索(返回所有匹配路径)
$paths = $data->searchValueRecursive('John');
// 返回: ['users.john.name']

// 包含详细信息的递归搜索
$detailedResults = $data->searchValueRecursive('John', true, true);
/* 返回:
[
    [
        'path' => 'users.john.name',
        'value' => 'John',
        'key' => 'name'
    ]
]
*/

通配符键搜索

$data = new DataArray([
    'user_name' => 'John',
    'user_age' => 30,
    'admin_name' => 'Jane',
    'admin_role' => 'super',
    'config' => [
        'db_host' => 'localhost',
        'db_port' => 3306,
        'cache_ttl' => 3600
    ]
]);

// 搜索所有 user_ 开头的键
$userKeys = $data->searchKey('user_*');
// 返回: ['user_name', 'user_age']

// 搜索所有包含 'name' 的键
$nameKeys = $data->searchKey('*name*');
// 返回: ['user_name', 'admin_name']

// 搜索特定模式的键
$dbKeys = $data->searchKey('*.db_*');
// 返回: ['config.db_host', 'config.db_port']

回调函数搜索

$data = new DataArray([
    'products' => [
        'p1' => ['name' => 'iPhone', 'price' => 999, 'category' => 'electronics'],
        'p2' => ['name' => 'MacBook', 'price' => 1999, 'category' => 'electronics'],
        'p3' => ['name' => 'T-Shirt', 'price' => 29, 'category' => 'clothing'],
        'p4' => ['name' => 'Shoes', 'price' => 89, 'category' => 'clothing']
    ]
]);

// 搜索价格大于100的产品
$expensiveProducts = $data->searchByCallback(function($value, $key, $path) {
    return is_array($value) && isset($value['price']) && $value['price'] > 100;
});
/* 返回:
[
    ['name' => 'iPhone', 'price' => 999, 'category' => 'electronics'],
    ['name' => 'MacBook', 'price' => 1999, 'category' => 'electronics']
]
*/

// 搜索包含路径信息
$expensiveWithPaths = $data->searchByCallback(
    function($value, $key, $path) {
        return is_array($value) && isset($value['price']) && $value['price'] > 100;
    },
    true
);
/* 返回:
[
    [
        'path' => 'products.p1',
        'key' => 'p1',
        'value' => ['name' => 'iPhone', 'price' => 999, 'category' => 'electronics']
    ],
    // ...
]
*/

高级搜索功能

// 搜索第一个匹配项
$firstMatch = $data->searchFirst('John');
// 返回第一个匹配的路径或元素

// 统计匹配数量
$count = $data->searchCount('electronics');
// 返回匹配的数量

// 递归获取所有键
$allKeys = $data->keysRecursive();
// 返回所有层级的键名

排序方法

基础排序

$data = new DataArray(['c' => 3, 'a' => 1, 'b' => 2]);

// 按值排序
$data->sort(); // ['a' => 1, 'b' => 2, 'c' => 3]
$data->rsort(); // ['c' => 3, 'b' => 2, 'a' => 1]

// 按键排序
$data->ksort(); // ['a' => 1, 'b' => 2, 'c' => 3]
$data->krsort(); // ['c' => 3, 'b' => 2, 'a' => 1]

自定义排序

$data = new DataArray([
    'user1' => ['name' => 'John', 'age' => 30],
    'user2' => ['name' => 'Jane', 'age' => 25],
    'user3' => ['name' => 'Bob', 'age' => 35]
]);

// 自定义值排序
$data->usort(function($a, $b) {
    return $a['age'] <=> $b['age'];
});

// 自定义键排序
$data->uksort(function($a, $b) {
    return strcmp($a, $b);
});

// 保持索引关联的自定义排序
$data->uasort(function($a, $b) {
    return $a['name'] <=> $b['name'];
});

转换方法

数据格式转换

$data = new DataArray([
    'user' => new DataArray(['name' => 'John']),
    'skills' => ['PHP', 'JS'],
    'config' => [
        'nested' => new DataArray(['value' => 'test'])
    ]
]);

// 转换为普通数组(保持DataArray对象)
$array = $data->toArray();
// user 键对应的仍然是 DataArray 对象

// 递归转换为数组(所有DataArray对象都转换)
$recursiveArray = $data->toArrayRecursive();
// 所有层级的 DataArray 对象都转换为普通数组

// 转换为JSON
$json = $data->toJson();
$prettyJson = $data->toJson(JSON_PRETTY_PRINT);

// 转换为查询字符串
$queryString = $data->toQueryString();

// 清空数组
$data->clear(); // 清空所有数据

序列化方法

// JSON序列化(自动调用 toArrayRecursive)
$jsonData = json_encode($data);

// 字符串表示(JSON格式)
echo (string)$data; // 输出JSON字符串

// 计数
$count = count($data); // 元素数量
$recursiveCount = $data->countRecursive(); // 递归计数

函数式编程

Map/Filter/Reduce

$data = new DataArray([1, 2, 3, 4, 5, 6]);

// Map - 对每个元素应用函数(返回新实例)
$doubled = $data->map(fn($n) => $n * 2); // [2, 4, 6, 8, 10, 12]

// Filter - 过滤元素(返回新实例)
$even = $data->filter(fn($n) => $n % 2 === 0); // [2, 4, 6]

// Reduce - 缩减为单一值
$sum = $data->reduce(fn($carry, $n) => $carry + $n, 0); // 21

// Each - 遍历执行(链式操作)
$data->each(function($value, $key) {
    echo "Key: $key, Value: $value\n";
})->filter(fn($n) => $n > 3); // 链式调用

切片和遍历

// 数组切片(返回新实例)
$slice = $data->slice(1, 3); // 从索引1开始取3个元素

// 反向遍历
foreach ($data->reverse() as $key => $value) {
    // 反向遍历数组
}

// 使用迭代器
$iterator = $data->getIterator();
foreach ($iterator as $key => $value) {
    // 遍历数组
}

条件操作

$data = new DataArray([1, 2, 3, 4, 5]);

// When - 条件满足时执行
$result = $data->when(
    count($data) > 3,
    fn($d) => $d->filter(fn($n) => $n > 2),
    fn($d) => $d->map(fn($n) => $n * 10)
);

// Unless - 条件不满足时执行
$result = $data->unless(
    empty($data),
    fn($d) => $d->sort(),
    fn($d) => $d->add(['default' => 'value'])
);

// Pipe - 管道操作
$processed = $data->pipe(function($d) {
    return $d->filter(fn($n) => $n > 2)
             ->map(fn($n) => $n * 10)
             ->toArray();
});

高级功能

只读模式

// 创建只读实例
$readOnly = DataArray::readOnly(['config' => 'value']);

try {
    $readOnly->set('new_key', 'value'); // 抛出RuntimeException
} catch (RuntimeException $e) {
    echo $e->getMessage(); // 不能修改只读的DataArray
}

// 创建可变副本
$mutable = $readOnly->mutable();
$mutable->set('new_key', 'value'); // 成功

// 创建副本
$copy = $readOnly->copy(); // 保持只读状态

// 检查只读状态
$isReadOnly = $readOnly->isReadOnly(); // true

链式操作

// 复杂的链式操作
$result = (new DataArray([5, 2, 8, 1, 9, 3, 2, 7]))
    ->filter(fn($n) => $n > 3)           // [5, 8, 9, 7]
    ->unique()                           // [5, 8, 9, 7] 
    ->map(fn($n) => $n * 2)              // [10, 16, 18, 14]
    ->sort()                             // [10, 14, 16, 18]
    ->when(
        count($data) > 2,
        fn($d) => $d->slice(0, 2)        // [10, 14]
    )
    ->toArray();

调试方法

$data = new DataArray(['user' => ['name' => 'John', 'age' => 30]]);

// 调试输出(不终止)
$data->dump();
// 输出: array(1) { ['user'] => array(2) { ... } }

// 调试输出并终止
// $data->dd(); // 输出并终止脚本

// 链式调试
$data->filter(fn($v) => is_array($v))
     ->dump()
     ->map(fn($v) => array_keys($v))
     ->dd();