mblarsen / arrgh
Arrgh——一个合理的PHP数组库
Requires
- php: >=5.6
README
Arrgh的目标是提供一个更统一的PHP数组操作库。
- 数组作为第一个参数,且不可变。现有的数组API可能令人困惑。对于某些函数,输入数组是第一个参数,而对其他函数来说,输入数组是最后一个参数。此外,某些函数返回一个新数组,而其他函数则修改输入数组(通过引用传递)。
- Arrgh不是重写,而是将参数重新映射到原生函数。例如,
array_map($callable, $array)
变为arr_map($array, $callable)
。 - 提供三种版本
- 函数
arr_map($people, $callable)
- 静态
Arrgh::map($people, $callable)
- 对象/链式
$array->map($callable)
- 函数
- 添加了缺失的函数,如:
tail
、collapse
、sortBy
、mapAssoc
(关联映射函数)、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中,所有数组函数都将返回一个数组,除非当然是在计算值(例如sum
、pop
、min
、max
等)。
这些函数现在将返回结果
数组多排序,数组推入,数组切片,数组遍历,数组递归遍历,arsort,asort,krsort,ksort,natcasesort,natsort,rsort,shuffle,sort,uasort,uksort,usort
这意味着你可以这样做
// 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 预先构建了 arrgh
和 arr
前缀,因此对于这些不需要 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 实现了 ArrayAccessphp 和 Iteratorphp,因此你可以 将 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
以下函数不受支持
compact、extract、current、each、key、next、pos、prev、reset
附加函数
除了数组函数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实现了ArrayAccessphp和Iteratorphp,因此您可以将其用作数组。
以下是一个使用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