哈希

class Cake\Utility\Hash

如果正确使用,数组管理可以成为构建更智能、更优化的代码的强大而有用的工具。CakePHP 在 Hash 类中提供了一组非常有用的静态实用程序,可以帮助您实现这一点。

CakePHP 的 Hash 类可以从任何模型或控制器中以与 Inflector 相同的方式调用。例如:Hash::combine().

哈希路径语法

下面描述的路径语法由 Hash 中的所有方法使用。并非所有路径语法部分都适用于所有方法。路径表达式由任意数量的标记组成。标记由两组组成。表达式用于遍历数组数据,而匹配器用于限定元素。您可以将匹配器应用于表达式元素。

表达式类型

表达式

定义

{n}

表示数字键。将匹配任何字符串或数字键。

{s}

表示字符串。将匹配任何字符串值,包括数字字符串值。

{*}

匹配任何值。

Foo

匹配具有完全相同值的键。

所有表达式元素都受所有方法支持。除了表达式元素之外,您还可以对某些方法使用属性匹配。它们是 extract()combine()format()check()map()reduce()apply()sort()insert()remove()nest()

属性匹配类型

匹配器

定义

[id]

匹配具有给定数组键的元素。

[id=2]

匹配 id 等于 2 的元素。

[id!=2]

匹配 id 不等于 2 的元素。

[id>2]

匹配 id 大于 2 的元素。

[id>=2]

匹配 id 大于或等于 2 的元素。

[id<2]

匹配 id 小于 2 的元素

[id<=2]

匹配 id 小于或等于 2 的元素。

[text=/.../]

匹配值与 ... 内的正则表达式匹配的元素。

static Cake\Utility\Hash::get(array|\ArrayAccess $data, $path, $default = null)

get()extract() 的简化版本,它只支持直接路径表达式。不支持带有 {n}{s}{*} 或匹配器的路径。当您想要从数组中获取一个值时,使用 get()。如果没有找到匹配的路径,将返回默认值。

static Cake\Utility\Hash::extract(array|\ArrayAccess $data, $path)

Hash::extract() 支持 哈希路径语法 的所有表达式和匹配器组件。您可以使用 extract 从实现 ArrayAccess 接口的数组或对象中快速检索数据,而无需遍历数据结构。相反,您可以使用路径表达式来限定要返回的元素。

// Common Usage:
$users = [
    ['id' => 1, 'name' => 'mark'],
    ['id' => 2, 'name' => 'jane'],
    ['id' => 3, 'name' => 'sally'],
    ['id' => 4, 'name' => 'jose'],
];
$results = Hash::extract($users, '{n}.id');
// $results equals:
// [1,2,3,4];
static Cake\Utility\Hash::insert(array $data, $path, $values = null)

$values 插入到由 $path 定义的数组中

$a = [
    'pages' => ['name' => 'page']
];
$result = Hash::insert($a, 'files', ['name' => 'files']);
// $result now looks like:
[
    [pages] => [
        [name] => page
    ]
    [files] => [
        [name] => files
    ]
]

您可以使用带有 {n}{s}{*} 的路径将数据插入到多个点

$users = Hash::insert($users, '{n}.new', 'value');

属性匹配器也适用于 insert()

$data = [
    0 => ['up' => true, 'Item' => ['id' => 1, 'title' => 'first']],
    1 => ['Item' => ['id' => 2, 'title' => 'second']],
    2 => ['Item' => ['id' => 3, 'title' => 'third']],
    3 => ['up' => true, 'Item' => ['id' => 4, 'title' => 'fourth']],
    4 => ['Item' => ['id' => 5, 'title' => 'fifth']],
];
$result = Hash::insert($data, '{n}[up].Item[id=4].new', 9);
/* $result now looks like:
    [
        ['up' => true, 'Item' => ['id' => 1, 'title' => 'first']],
        ['Item' => ['id' => 2, 'title' => 'second']],
        ['Item' => ['id' => 3, 'title' => 'third']],
        ['up' => true, 'Item' => ['id' => 4, 'title' => 'fourth', 'new' => 9]],
        ['Item' => ['id' => 5, 'title' => 'fifth']],
    ]
*/
static Cake\Utility\Hash::remove(array $data, $path)

删除与 $path 匹配的数组中的所有元素。

$a = [
    'pages' => ['name' => 'page'],
    'files' => ['name' => 'files']
];
$result = Hash::remove($a, 'files');
/* $result now looks like:
    [
        [pages] => [
            [name] => page
        ]

    ]
*/

使用 {n}{s}{*} 将允许您一次删除多个值。您还可以对 remove() 使用属性匹配器

$data = [
    0 => ['clear' => true, 'Item' => ['id' => 1, 'title' => 'first']],
    1 => ['Item' => ['id' => 2, 'title' => 'second']],
    2 => ['Item' => ['id' => 3, 'title' => 'third']],
    3 => ['clear' => true, 'Item' => ['id' => 4, 'title' => 'fourth']],
    4 => ['Item' => ['id' => 5, 'title' => 'fifth']],
];
$result = Hash::remove($data, '{n}[clear].Item[id=4]');
/* $result now looks like:
    [
        ['clear' => true, 'Item' => ['id' => 1, 'title' => 'first']],
        ['Item' => ['id' => 2, 'title' => 'second']],
        ['Item' => ['id' => 3, 'title' => 'third']],
        ['clear' => true],
        ['Item' => ['id' => 5, 'title' => 'fifth']],
    ]
*/
static Cake\Utility\Hash::combine(array $data, $keyPath, $valuePath = null, $groupPath = null)

使用 $keyPath 作为构建其键的路径来创建关联数组,并可选地使用 $valuePath 作为获取值的路径。如果未指定 $valuePath 或与任何内容不匹配,则值将初始化为 null。您也可以根据 $groupPath 中指定的路径获取的值对值进行分组。

$a = [
    [
        'User' => [
            'id' => 2,
            'group_id' => 1,
            'Data' => [
                'user' => 'mariano.iglesias',
                'name' => 'Mariano Iglesias'
            ]
        ]
    ],
    [
        'User' => [
            'id' => 14,
            'group_id' => 2,
            'Data' => [
                'user' => 'phpnut',
                'name' => 'Larry E. Masters'
            ]
        ]
    ],
];

$result = Hash::combine($a, '{n}.User.id');
/* $result now looks like:
    [
        [2] =>
        [14] =>
    ]
*/

$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.user');
/* $result now looks like:
    [
        [2] => 'mariano.iglesias'
        [14] => 'phpnut'
    ]
*/

$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data');
/* $result now looks like:
    [
        [2] => [
                [user] => mariano.iglesias
                [name] => Mariano Iglesias
        ]
        [14] => [
                [user] => phpnut
                [name] => Larry E. Masters
        ]
    ]
*/

$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.name');
/* $result now looks like:
    [
        [2] => Mariano Iglesias
        [14] => Larry E. Masters
    ]
*/

$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
/* $result now looks like:
    [
        [1] => [
                [2] => [
                        [user] => mariano.iglesias
                        [name] => Mariano Iglesias
                ]
        ]
        [2] => [
                [14] => [
                        [user] => phpnut
                        [name] => Larry E. Masters
                ]
        ]
    ]
*/

$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.name', '{n}.User.group_id');
/* $result now looks like:
    [
        [1] => [
                [2] => Mariano Iglesias
        ]
        [2] => [
                [14] => Larry E. Masters
        ]
    ]
*/

// As of 3.9.0 $keyPath can be null
$result = Hash::combine($a, null, '{n}.User.Data.name');
/* $result now looks like:
    [
        [0] => Mariano Iglesias
        [1] => Larry E. Masters
    ]
*/

您可以为 $keyPath$valuePath 提供数组。如果您这样做,第一个值将用作格式字符串,用于其他路径提取的值。

$result = Hash::combine(
    $a,
    '{n}.User.id',
    ['%s: %s', '{n}.User.Data.user', '{n}.User.Data.name'],
    '{n}.User.group_id'
);
/* $result now looks like:
    [
        [1] => [
                [2] => mariano.iglesias: Mariano Iglesias
        ]
        [2] => [
                [14] => phpnut: Larry E. Masters
        ]
    ]
*/

$result = Hash::combine(
    $a,
    ['%s: %s', '{n}.User.Data.user', '{n}.User.Data.name'],
    '{n}.User.id'
);
/* $result now looks like:
    [
        [mariano.iglesias: Mariano Iglesias] => 2
        [phpnut: Larry E. Masters] => 14
    ]
*/
static Cake\Utility\Hash::format(array $data, array $paths, $format)

返回从数组中提取的一系列值,并使用格式字符串进行格式化。

$data = [
    [
        'Person' => [
            'first_name' => 'Nate',
            'last_name' => 'Abele',
            'city' => 'Boston',
            'state' => 'MA',
            'something' => '42'
        ]
    ],
    [
        'Person' => [
            'first_name' => 'Larry',
            'last_name' => 'Masters',
            'city' => 'Boondock',
            'state' => 'TN',
            'something' => '{0}'
        ]
    ],
    [
        'Person' => [
            'first_name' => 'Garrett',
            'last_name' => 'Woodworth',
            'city' => 'Venice Beach',
            'state' => 'CA',
            'something' => '{1}'
        ]
    ]
];

$res = Hash::format($data, ['{n}.Person.first_name', '{n}.Person.something'], '%2$d, %1$s');
/*
[
    [0] => 42, Nate
    [1] => 0, Larry
    [2] => 0, Garrett
]
*/

$res = Hash::format($data, ['{n}.Person.first_name', '{n}.Person.something'], '%1$s, %2$d');
/*
[
    [0] => Nate, 42
    [1] => Larry, 0
    [2] => Garrett, 0
]
*/
static Cake\Utility\Hash::contains(array $data, array $needle)

确定一个 Hash 或数组是否包含另一个的精确键值

$a = [
    0 => ['name' => 'main'],
    1 => ['name' => 'about']
];
$b = [
    0 => ['name' => 'main'],
    1 => ['name' => 'about'],
    2 => ['name' => 'contact'],
    'a' => 'b',
];

$result = Hash::contains($a, $a);
// true
$result = Hash::contains($a, $b);
// false
$result = Hash::contains($b, $a);
// true
static Cake\Utility\Hash::check(array $data, string $path = null)

检查数组中是否设置了特定路径

$set = [
    'My Index 1' => ['First' => 'The first item']
];
$result = Hash::check($set, 'My Index 1.First');
// $result == true

$result = Hash::check($set, 'My Index 1');
// $result == true

$set = [
    'My Index 1' => [
        'First' => [
            'Second' => [
                'Third' => [
                    'Fourth' => 'Heavy. Nesting.'
                ]
            ]
        ]
    ]
];
$result = Hash::check($set, 'My Index 1.First.Second');
// $result == true

$result = Hash::check($set, 'My Index 1.First.Second.Third');
// $result == true

$result = Hash::check($set, 'My Index 1.First.Second.Third.Fourth');
// $result == true

$result = Hash::check($set, 'My Index 1.First.Seconds.Third.Fourth');
// $result == false
static Cake\Utility\Hash::filter(array $data, $callback = ['Hash', 'filter'])

过滤数组中为空的元素,不包括 ‘0’。您也可以提供自定义的 $callback 来过滤数组元素。回调应该返回 false 来从结果数组中删除元素

$data = [
    '0',
    false,
    true,
    0,
    ['one thing', 'I can tell you', 'is you got to be', false]
];
$res = Hash::filter($data);

/* $res now looks like:
    [
        [0] => 0
        [2] => true
        [3] => 0
        [4] => [
                [0] => one thing
                [1] => I can tell you
                [2] => is you got to be
        ]
    ]
*/
static Cake\Utility\Hash::flatten(array $data, string $separator = '.')

将多维数组压缩成一维数组

$arr = [
    [
        'Post' => ['id' => '1', 'title' => 'First Post'],
        'Author' => ['id' => '1', 'user' => 'Kyle'],
    ],
    [
        'Post' => ['id' => '2', 'title' => 'Second Post'],
        'Author' => ['id' => '3', 'user' => 'Crystal'],
    ],
];
$res = Hash::flatten($arr);
/* $res now looks like:
    [
        [0.Post.id] => 1
        [0.Post.title] => First Post
        [0.Author.id] => 1
        [0.Author.user] => Kyle
        [1.Post.id] => 2
        [1.Post.title] => Second Post
        [1.Author.id] => 3
        [1.Author.user] => Crystal
    ]
*/
static Cake\Utility\Hash::expand(array $data, string $separator = '.')

扩展之前使用 Hash::flatten() 扁平化的数组

$data = [
    '0.Post.id' => 1,
    '0.Post.title' => First Post,
    '0.Author.id' => 1,
    '0.Author.user' => Kyle,
    '1.Post.id' => 2,
    '1.Post.title' => Second Post,
    '1.Author.id' => 3,
    '1.Author.user' => Crystal,
];
$res = Hash::expand($data);
/* $res now looks like:
[
    [
        'Post' => ['id' => '1', 'title' => 'First Post'],
        'Author' => ['id' => '1', 'user' => 'Kyle'],
    ],
    [
        'Post' => ['id' => '2', 'title' => 'Second Post'],
        'Author' => ['id' => '3', 'user' => 'Crystal'],
    ],
];
*/
static Cake\Utility\Hash::merge(array $data, array $merge[, array $n])

此函数可以看作是 PHP 的 array_mergearray_merge_recursive 的混合体。与两者不同的是,如果数组键包含另一个数组,那么函数将递归地执行(不像 array_merge),但对于包含字符串的键不会执行(不像 array_merge_recursive)。

注意

此函数将处理无限数量的参数,并将非数组参数类型转换为数组。

$array = [
    [
        'id' => '48c2570e-dfa8-4c32-a35e-0d71cbdd56cb',
        'name' => 'mysql raleigh-workshop-08 < 2008-09-05.sql ',
        'description' => 'Importing an sql dump',
    ],
    [
        'id' => '48c257a8-cf7c-4af2-ac2f-114ecbdd56cb',
        'name' => 'pbpaste | grep -i Unpaid | pbcopy',
        'description' => 'Remove all lines that say "Unpaid".',
    ]
];
$arrayB = 4;
$arrayC = [0 => "test array", "cats" => "dogs", "people" => 1267];
$arrayD = ["cats" => "felines", "dog" => "angry"];
$res = Hash::merge($array, $arrayB, $arrayC, $arrayD);

/* $res now looks like:
[
    [0] => [
            [id] => 48c2570e-dfa8-4c32-a35e-0d71cbdd56cb
            [name] => mysql raleigh-workshop-08 < 2008-09-05.sql
            [description] => Importing an sql dump
    ]
    [1] => [
            [id] => 48c257a8-cf7c-4af2-ac2f-114ecbdd56cb
            [name] => pbpaste | grep -i Unpaid | pbcopy
            [description] => Remove all lines that say "Unpaid".
    ]
    [2] => 4
    [3] => test array
    [cats] => felines
    [people] => 1267
    [dog] => angry
]
*/
static Cake\Utility\Hash::numeric(array $data)

检查数组中所有值是否都是数字

$data = ['one'];
$res = Hash::numeric(array_keys($data));
// $res is true

$data = [1 => 'one'];
$res = Hash::numeric($data);
// $res is false
static Cake\Utility\Hash::dimensions(array $data)

计算数组的维度。此方法只考虑数组中第一个元素的维度

$data = ['one', '2', 'three'];
$result = Hash::dimensions($data);
// $result == 1

$data = ['1' => '1.1', '2', '3'];
$result = Hash::dimensions($data);
// $result == 1

$data = ['1' => ['1.1' => '1.1.1'], '2', '3' => ['3.1' => '3.1.1']];
$result = Hash::dimensions($data);
// $result == 2

$data = ['1' => '1.1', '2', '3' => ['3.1' => '3.1.1']];
$result = Hash::dimensions($data);
// $result == 1

$data = ['1' => ['1.1' => '1.1.1'], '2', '3' => ['3.1' => ['3.1.1' => '3.1.1.1']]];
$result = Hash::dimensions($data);
// $result == 2
static Cake\Utility\Hash::maxDimensions(array $data)

类似于 dimensions(),但此方法返回数组中任何元素的维度深度

$data = ['1' => '1.1', '2', '3' => ['3.1' => '3.1.1']];
$result = Hash::maxDimensions($data);
// $result == 2

$data = ['1' => ['1.1' => '1.1.1'], '2', '3' => ['3.1' => ['3.1.1' => '3.1.1.1']]];
$result = Hash::maxDimensions($data);
// $result == 3
static Cake\Utility\Hash::map(array $data, $path, $function)

通过提取 $path 并对结果应用 $function,创建一个新数组。您可以在此方法中使用表达式和匹配元素

// Call the noop function $this->noop() on every element of $data
$result = Hash::map($data, "{n}", [$this, 'noop']);

public function noop(array $array)
{
    // Do stuff to array and return the result
    return $array;
}
static Cake\Utility\Hash::reduce(array $data, $path, $function)

通过提取 $path 并使用 $function 减少提取的结果,创建一个单一的值。您可以在此方法中使用表达式和匹配元素。

static Cake\Utility\Hash::apply(array $data, $path, $function)

使用 $function 将回调应用于一组提取的值。函数将获取提取的值作为第一个参数

$data = [
    ['date' => '01-01-2016', 'booked' => true],
    ['date' => '01-01-2016', 'booked' => false],
    ['date' => '02-01-2016', 'booked' => true]
];
$result = Hash::apply($data, '{n}[booked=true].date', 'array_count_values');
/* $result now looks like:
    [
        '01-01-2016' => 1,
        '02-01-2016' => 1,
    ]
*/
static Cake\Utility\Hash::sort(array $data, $path, $dir, $type = 'regular')

根据 Hash 路径语法 确定的任何值对数组进行排序。此方法只支持表达式元素

$a = [
    0 => ['Person' => ['name' => 'Jeff']],
    1 => ['Shirt' => ['color' => 'black']]
];
$result = Hash::sort($a, '{n}.Person.name', 'asc');
/* $result now looks like:
    [
        [0] => [
                [Shirt] => [
                        [color] => black
                ]
        ]
        [1] => [
                [Person] => [
                        [name] => Jeff
                ]
        ]
    ]
*/

$dir 可以是 ascdesc$type 可以是以下值之一

  • regular 用于常规排序。

  • numeric 用于按数字等效值对值进行排序。

  • string 用于按字符串值对值进行排序。

  • natural 用于以人类友好的方式对值进行排序。例如,将 foo10 排列在 foo2 之前。

static Cake\Utility\Hash::diff(array $data, array $compare)

计算两个数组之间的差值

$a = [
    0 => ['name' => 'main'],
    1 => ['name' => 'about']
];
$b = [
    0 => ['name' => 'main'],
    1 => ['name' => 'about'],
    2 => ['name' => 'contact']
];

$result = Hash::diff($a, $b);
/* $result now looks like:
    [
        [2] => [
                [name] => contact
        ]
    ]
*/
static Cake\Utility\Hash::mergeDiff(array $data, array $compare)

此函数合并两个数组,并将数据中的差异推送到结果数组的底部。

示例 1

$array1 = ['ModelOne' => ['id' => 1001, 'field_one' => 'a1.m1.f1', 'field_two' => 'a1.m1.f2']];
$array2 = ['ModelOne' => ['id' => 1003, 'field_one' => 'a3.m1.f1', 'field_two' => 'a3.m1.f2', 'field_three' => 'a3.m1.f3']];
$res = Hash::mergeDiff($array1, $array2);

/* $res now looks like:
    [
        [ModelOne] => [
                [id] => 1001
                [field_one] => a1.m1.f1
                [field_two] => a1.m1.f2
                [field_three] => a3.m1.f3
            ]
    ]
*/

示例 2

$array1 = ["a" => "b", 1 => 20938, "c" => "string"];
$array2 = ["b" => "b", 3 => 238, "c" => "string", ["extra_field"]];
$res = Hash::mergeDiff($array1, $array2);
/* $res now looks like:
    [
        [a] => b
        [1] => 20938
        [c] => string
        [b] => b
        [3] => 238
        [4] => [
                [0] => extra_field
        ]
    ]
*/
static Cake\Utility\Hash::normalize(array $data, $assoc = true, $default = null)

规范化数组。如果 $assoctrue,则结果数组将被规范化为关联数组。具有值的数字键将被转换为具有 $default 值的字符串键。规范化数组,使使用 Hash::merge() 的结果更容易

$a = ['Tree', 'CounterCache',
    'Upload' => [
        'folder' => 'products',
        'fields' => ['image_1_id', 'image_2_id']
    ]
];
$result = Hash::normalize($a);
/* $result now looks like:
    [
        [Tree] => null
        [CounterCache] => null
        [Upload] => [
                [folder] => products
                [fields] => [
                        [0] => image_1_id
                        [1] => image_2_id
                ]
        ]
    ]
*/

$b = [
    'Cacheable' => ['enabled' => false],
    'Limit',
    'Bindable',
    'Validator',
    'Transactional',
];
$result = Hash::normalize($b);
/* $result now looks like:
    [
        [Cacheable] => [
                [enabled] => false
        ]

        [Limit] => null
        [Bindable] => null
        [Validator] => null
        [Transactional] => null
    ]
*/

在版本 4.5.0 中更改: 添加了 $default 参数。

static Cake\Utility\Hash::nest(array $data, array $options = [])

接受一个扁平化的数组集,并创建一个嵌套的或线程化的数据结构。

选项

  • children 在结果集中用于子节点的键名。默认值为 ‘children’。

  • idPath 用于标识每个条目的键的路径。应该与 Hash::extract() 兼容。默认值为 {n}.$alias.id

  • parentPath 用于标识每个条目父节点的键的路径。应该与 Hash::extract() 兼容。默认值为 {n}.$alias.parent_id

  • root 所需最顶层结果的 ID。

例如,如果您有以下数组数据

$data = [
    ['ThreadPost' => ['id' => 1, 'parent_id' => null]],
    ['ThreadPost' => ['id' => 2, 'parent_id' => 1]],
    ['ThreadPost' => ['id' => 3, 'parent_id' => 1]],
    ['ThreadPost' => ['id' => 4, 'parent_id' => 1]],
    ['ThreadPost' => ['id' => 5, 'parent_id' => 1]],
    ['ThreadPost' => ['id' => 6, 'parent_id' => null]],
    ['ThreadPost' => ['id' => 7, 'parent_id' => 6]],
    ['ThreadPost' => ['id' => 8, 'parent_id' => 6]],
    ['ThreadPost' => ['id' => 9, 'parent_id' => 6]],
    ['ThreadPost' => ['id' => 10, 'parent_id' => 6]]
];

$result = Hash::nest($data, ['root' => 6]);
/* $result now looks like:
    [
        (int) 0 => [
            'ThreadPost' => [
                'id' => (int) 6,
                'parent_id' => null
            ],
            'children' => [
                (int) 0 => [
                    'ThreadPost' => [
                        'id' => (int) 7,
                        'parent_id' => (int) 6
                    ],
                    'children' => []
                ],
                (int) 1 => [
                    'ThreadPost' => [
                        'id' => (int) 8,
                        'parent_id' => (int) 6
                    ],
                    'children' => []
                ],
                (int) 2 => [
                    'ThreadPost' => [
                        'id' => (int) 9,
                        'parent_id' => (int) 6
                    ],
                    'children' => []
                ],
                (int) 3 => [
                    'ThreadPost' => [
                        'id' => (int) 10,
                        'parent_id' => (int) 6
                    ],
                    'children' => []
                ]
            ]
        ]
    ]
    */