mblarsen/arrgh

Arrgh——一个合理的PHP数组库

0.11.0 2016-02-19 04:04 UTC

This package is auto-updated.

Last update: 2024-09-21 20:20:45 UTC


README

Build Status Coverage Status Total Downloads Scrutinizer Code Quality Codacy Badge
Get help on Codementor Join the chat at https://gitter.im/mblarsen/arrgh

Arrgh的目标是提供一个更统一的PHP数组操作库。

  • 数组作为第一个参数,且不可变。现有的数组API可能令人困惑。对于某些函数,输入数组是第一个参数,而对其他函数来说,输入数组是最后一个参数。此外,某些函数返回一个新数组,而其他函数则修改输入数组(通过引用传递)。
  • Arrgh不是重写,而是将参数重新映射到原生函数。例如,array_map($callable, $array) 变为 arr_map($array, $callable)
  • 提供三种版本
    1. 函数 arr_map($people, $callable)
    2. 静态 Arrgh::map($people, $callable)
    3. 对象/链式 $array->map($callable)
  • 添加了缺失的函数,如:tailcollapsesortBymapAssoc(关联映射函数)、get(点路径获取器)等等。(见附加函数
  • 排序和比较在PHP5和PHP7中均有效,甚至对于您的自定义排序和比较函数。
  • 您可以使用您熟悉的名字或使用snake_case或camelCase的简短版本。例如,$array->array_map()$array->arrayMap()$array->map()

安装

composer require mblarsen/arrgh

示例

在每个情况下,函数都将数组作为第一个参数——不再需要在文档中查找

arr_map($input, $callable);
arr_join($input, ",");

链接函数

arr($input)->reverse()->slice(0, 5)->sum();

使用点路径的强大获取函数

// People and their children
$array = [
    [ "name" => "Jakob", "age" => 37, "children" => [
        [ "name" => "Mona", "sex" => "female" ],
        [ "name" => "Lisa", "sex" => "female" ],
    ] ],
    [ "name" => "Topher", "age" => 18, "children" => [
        [ "name" => "Joe", "sex" => "male" ],
    ] ],
    [ "name" => "Ginger", "age" => 43 ],
];

// Return all children's names
arr_get($array, "children.name");      // returns [ ["Mona", "Lisa"] , ["Joe"] ]
arr_get($array, "children.name", true) // returns [ "Mona", "Lisa", "Joe" ]

使用内置选择函数,按索引选择

arr_get($array, "children.0.name");    // returns [ ["Mona"], ["Joe"] ]
arr_get($array, "children.1.name");    // returns [ ["Lisa"] ]
arr_get($array, "children.-1.name");   // returns [ ["Lisa"], ["Joe"] ]

... 或者自己编写选择函数,返回所有女性孩子的名字

$children = arr($array)->get([ "children.!$.name",
    function ($item, $index) { return $item['sex'] === 'female'; }
])->toArray();

// returns [ Mona, Lisa ]

(语法:一个数组,其中路径后跟一个可调用的函数,用于路径中每个!$的出现)

使用链式API(这也非常简洁)实现相同的功能

$children = arr($array)
    ->map(function ($person) { return isset($person["children"]) ? $person["children"] : null; })
    ->filter()
    ->collapse()
    ->map(function ($child) {
        if ($child["sex"] === "female") { return $child["name"]; }
        return null;
    })
    ->filter()
    ->toArray();

数组作为第一个参数

Arrgh没有重写数组算法,而是将参数重新映射到原生函数。例如,arr_map$callable移动到最后一个参数。

array_map ( callable $callback , array $array1 [, array $... ] )

变为

arr_map ( array $array1 [, array $... ] , callable $callback )

示例用法

arr_map($products, function ($product) {
    return $product->code();
});

所有接受一个或多个数组的函数现在都接受它们作为其第一个参数

array_key_exists($key, $array)         => ($array, $key)
in_​array($key, $array)                 => ($array, $key)
array_search($search, $array)          => ($array, $search)
implode($glue, $array)                 => ($array, $glue);
join($glue, $array)                    => ($array, $glue);
array_map($callable, $array[, arrayN]) => ($array[, arrayN], $callable)

所有函数都是不可变的

大多数修改数组(如排序)的函数现在都通过引用传递输入数组,如

usort ( array &$array , callable $value_compare_func )

这使得在PHP中进行函数式编程变得困难且不够流畅。

在Arrgh中,所有数组函数都将返回一个数组,除非当然是在计算值(例如sumpopminmax等)。

这些函数现在将返回结果

数组多排序数组推入数组切片数组遍历数组递归遍历arsortasortkrsortksortnatcasesortnatsortrsortshufflesortuasortuksortusort

这意味着你可以这样做

// Top 5 most expensive products
array_usort($products, function ($p1, $p2) { ... };
return array_slice($products, 0, 5);

现在你可以这样做

// Top 5 most expensive products
return arr_slice(arr_usort($products, function ($p1, $p2) { ... }), 0, 5);

或者你可以使用这样的链 [见下文更多内容]

// Top 5 most expensive products
return arr($products)
    ->usort($products, function ($p1, $p2) { ... })
    ->slice(0, 5);

选择你的风格

Arrgh有三种风格来适应你的性格

函数风格

Arrgh函数库包含在全局作用域中,因此你可以在任何地方使用这些函数。就像原生数组函数一样

arr_replace($defaults, $params);

构造函数 aargh() 允许你开始一个链

arr($defaults)->replace($params);

使用函数风格

如果你想使用函数风格,你必须在自动加载之前定义以下内容。

define("ARRGH", true);
require __DIR__ . "/vendor/autoload.php";

你可以使用以下方式更改函数前缀

define("ARRGH_PREFIX", "arr");

现在 arr_reverse 变成了

arr_reverse([1, 2, 3]);

注意:更改函数前缀需要使用 eval()。如果 eval() 被禁用,Arrgh 将抛出异常。Arrgh 预先构建了 arrgharr 前缀,因此对于这些不需要 eval()

静态风格

你可以在 Arrgh 上使用静态函数

Arrgh::array_flip($music);
Arrgh::flip($music);

所有静态方法都接受一个数组作为第一个输入,并返回一个数组。甚至是排序

return Arrgh::sort($big_numbers);

你可以退出静态风格并像这样开始一个

Arrgh::arr($big_numbers)
    ->sort()
    ->reduce(function ($k, $v) { return $k += ln($v); });

arrgh 的同义词是 chain。两者都是通过在任意方法前添加 下划线 作为缩写

Arrgh::_sort($big_numbers)
    ->reduce(function ($k, $v) { return $k += $v });

_sort() 返回可链式 Arrgh 对象。

链式风格

链可以通过几种方式创建。

使用 arr() 函数

arr($array)->reverse();

使用静态方法 Arrgh::arr()Arrgh::chain()

Arrgh::chain($array)->reverse();

使用静态方法缩写 (_)

Arrgh::_reverse($array);

或者通过创建一个可链式对象

$videos = new Arrgh($videos);
$media = $videos->merge($music)->shuffle()->slice(0, 3);

当你处理对象时,所有方法都返回一个对象,而不是实际的数组。要获取原生 PHP 数组,调用 toArray() 方法

$media->toArray();

注意:Arrgh 实现了 ArrayAccessphpIteratorphp,因此你可以 将 Arrgh 对象用作数组

如果你想要保留数组而不是终止函数(如 pop())的结果,可以使用 keepChain()

arr([1, 2, 3])->pop(); // will return 3

使用 keepChain(),我们将得到数组而不是

arr([1, 2, 3])->keepChain()->pop(); // will return an Arrgh object with the array [1, 2]

如果您想再次中断链。例如,要获取剩余元素的总和,您可以

arr([1, 2, 3])->keepChain()->pop()->keepChain(false)->sum(); // returns 3
arr([1, 2, 3])->keepChain()->pop()->breakChain()->sum(); // breakChain() = keepChain(false)

如果省略了->keepChain(false),则sum()也会返回Arrgh对象。

可以使用keepOnce()编写相同的表达式。

arr([1, 2, 3])->keepOnce()->pop()->sum(); // returns 3

所有函数都在这里。

支持PHP手册数组函数php部分的全部函数。

如果您使用函数样式,则方法以arr_为前缀,除了以array_开头的函数(在这种情况下,它将被替换)。

array_map => arr_map
usort => arr_usort

以下函数不受支持

compactextractcurrenteachkeynextposprevreset

附加函数

除了数组函数php之外,Arrgh还提供了以下函数

  • map_assoc(array, function):在关联数组上工作的映射函数。映射函数为function ($key, $value)
  • sort_by(array, key|function):按键或函数对项目集合进行排序。排序函数为function ($item)
  • contains(array, [key]):在集合中查找特定值并返回true或false。可以限制为键。
  • collapse(array):将数组数组的数组折叠成一个。例如,[[1, 2], [3, 4]]变为[1, 2, 3, 4]
  • except(array, key|array):返回具有key|array中一些键的所有项目集合。
  • only(array, key|array):类似于except,但只返回具有key|array中键的项目。
  • get(array, path):多维数组的强大获取器。
  • isCollection(array):告诉数组是否为集合(与关联数组相对)。
  • depth(array):告诉数组数组的深度(不包括关联数组)。
  • head(array):与shift同义。
  • tail(array):返回除了头部之外的所有内容。例如,tail([1, 2, 3])输出[2, 3]。
  • first(array):与shift同义。
  • last(array):与pop同义。
  • partition(array, callable):根据可调用的函数将数组分成两个数组。
  • odd(array):给出数组中的所有奇数索引项。1, 3, 5等。
  • even(array):给出数组中的所有偶数索引项。0, 2, 4等。

与数组类似

Arrgh实现了ArrayAccessphpIteratorphp,因此您可以将其用作数组。

以下是一个使用foreach的示例

$arr = arr([1, 2, 3, 4, 5]);
foreach ($arr as $value) {
    echo $value . PHP_EOL;
}

您可以像原生的数组一样向数组中推送值

echo $arr->sum(); // 15
$arr[] = 6;
echo $arr->sum(); // 21

数组值作为Arrgh对象返回

$arr = arr([[3, 2, 1], [5, 4]]);
$content = arr([]);
foreach ($arr as $value) {
    $content = $content->merge($value->reverse());
}
$content->toArray(); // returns array [ 1, 2, 3, 4, 5 ];

注意:PHP的本地函数只能接受数组作为参数,因此这是一个限制。但您根本不使用它们,对吧?

如果您想使用函数样式,您必须在vendor/autoload require之前定义以下内容。

define("ARRGH", true);

现在您可以在代码的任何地方使用这些函数了

arr_reverse([1, 2, 3]);

你可以使用以下方式更改函数前缀

define("ARRGH_PREFIX", "arrgh");

现在 arr_reverse 变成了

arrgh_reverse([1, 2, 3]);

注意:更改函数前缀需要使用 eval()。如果禁用了 eval(),则 Arrgh 将引发异常。Arrgh 预先构建了 arr 前缀,因此对于这些 eval() 是不必要的。

PHP5 与 PHP7

在编写本文档时,PHP5 和 PHP7 对于可比较函数返回的相等值处理不同。

例如,以下 unittest 在 PHP 5.6.x 中将失败,但在 7 中不会失败

$original_input = [
    [ "name" => "Jakob", "age" => 42 ],
    [ "name" => "Topher", "age" => 18 ],
    [ "name" => "Ginger", "age" => 42 ],
];
$expected_result = [
    [ "name" => "Topher", "age" => 18 ],
    [ "name" => "Jakob", "age" => 42 ],
    [ "name" => "Ginger", "age" => 42 ],
];

$input = $original_input;
usort($input, function ($a, $b) {
    return $a["age"] - $b["age"];
});

// Actual ouput in PHP5 (Jakob and Ginger reversed):
// [
//     [ "name" => "Topher", "age" => 18 ],
//     [ "name" => "Ginger", "age" => 42 ],
//     [ "name" => "Jakob", "age" => 42 ],
// ]
//
// Actual ouput in PHP7 (Jakob and Ginger in the original order):
// [
//     [ "name" => "Topher", "age" => 18 ],
//     [ "name" => "Jakob", "age" => 42 ],
//     [ "name" => "Ginger", "age" => 42 ],
// ]

PHP5 和 PHP7 对比较结果中的数组项的处理不同。如果您为这两个版本编写代码,则需要考虑这一点。虽然 PHP5 改变顺序,但 PHP7 没有这种副作用。

Arrgh 通过提供根据运行版本正确签名的整数来提高此问题。因此,在运行自定义比较函数时,您可以这样做

usort($input, function ($a, $b) {
    return Arrgh::getSortDirection($a["age"] - $b["age"]);
});

或使用 Arrgh

arr_usort($input, function ($a, $b) {
    return Arrgh::getSortDirection($a["age"] - $b["age"]);
});

请参阅单元测试中的示例 ArrghGeneralTest::testPhpVersionFail*

从 v0.6 版本开始,Arrgh 内部处理此问题,因此您可以这样做

arr_usort($input, function ($a, $b) {
    return $a["age"] - $b["age"];
});

可调用函数被封装在具有 PHP 版本意识的可调用函数中,该函数检查结果并根据 PHP 版本返回值。

变更日志

请参阅 CHANGELOG.md

待办事项

请参阅 TODO.md