Skip to content

Commit c10b467

Browse files
author
nix
committed
added phpstan; fixed some docs issues; reworked phpunit configuration
1 parent 7b04b4c commit c10b467

File tree

13 files changed

+152
-27
lines changed

13 files changed

+152
-27
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
/vendor/
2+
/tests-output/
3+
/phpunit.xml
4+
/phpstan.neon

composer.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"php": ">=8.2"
1616
},
1717
"require-dev": {
18-
"phpunit/phpunit": "^11.5.42"
18+
"phpstan/phpstan": "^2.1",
19+
"phpunit/phpunit": "~11.5"
1920
},
2021
"autoload": {
2122
"psr-4": {
@@ -27,9 +28,21 @@
2728
"Test\\": "tests/"
2829
}
2930
},
31+
"config": {
32+
"sort-packages": true
33+
},
3034
"extra": {
3135
"branch-alias": {
3236
"dev-main": "1.2.x-dev"
3337
}
38+
},
39+
"scripts": {
40+
"test": "phpunit --no-coverage",
41+
"test+coverage": [
42+
"@putenv XDEBUG_MODE=coverage",
43+
"phpunit"
44+
],
45+
"stan": "phpstan",
46+
"stan-tests": "phpstan analyse -c phpstan-tests.neon"
3447
}
3548
}

composer.lock

Lines changed: 54 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

phpstan-tests.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
parameters:
2+
level: 9
3+
paths: [tests]
4+
ignoreErrors:
5+
- identifier: missingType.iterableValue

phpstan.dist.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
parameters:
2+
level: 10
3+
paths: [src]

phpunit.dist.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php"
3+
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" cacheDirectory="tests-output/phpunit-cache">
4+
<coverage>
5+
<report>
6+
<clover outputFile="tests-output/coverage/clover.xml"/>
7+
<cobertura outputFile="tests-output/coverage/cobertura.xml"/>
8+
<crap4j outputFile="tests-output/coverage/crap4j.xml"/>
9+
<html outputDirectory="tests-output/coverage/html"/>
10+
<php outputFile="tests-output/coverage/coverage.php"/>
11+
<text outputFile="tests-output/coverage/coverage.txt"/>
12+
<xml outputDirectory="tests-output/coverage/xml"/>
13+
</report>
14+
</coverage>
15+
<testsuites>
16+
<testsuite name="php-util test suite">
17+
<directory>tests</directory>
18+
</testsuite>
19+
</testsuites>
20+
<logging>
21+
<junit outputFile="tests-output/junit-report.xml"/>
22+
</logging>
23+
<source>
24+
<include>
25+
<directory>src/</directory>
26+
</include>
27+
</source>
28+
</phpunit>

src/Arr.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ private function __construct() {}
1313
* @param string|int ...$keys the keys for the values to retain
1414
* @return array the resulting array
1515
* @since 1.0
16+
* @phpstan-ignore missingType.iterableValue, missingType.iterableValue
1617
*/
1718
public static function pick(array $array, string|int ...$keys): array
1819
{
@@ -26,6 +27,7 @@ public static function pick(array $array, string|int ...$keys): array
2627
* @param bool $return_key whether to return the key instead of the value
2728
* @return mixed the value or the key for a found item, null otherwise
2829
* @since 1.0
30+
* @phpstan-ignore missingType.iterableValue
2931
*/
3032
public static function find_by(array $array, callable $predicate, bool $return_key = false): mixed
3133
{
@@ -40,10 +42,11 @@ public static function find_by(array $array, callable $predicate, bool $return_k
4042
* @param iterable $iterable the elements to reduce
4143
* @param callable(mixed $carry, mixed $value, string|int $key): mixed $callback
4244
* @param mixed $initial an optional initial value. if not passed, the first element is taken as the initial value and the `$callback` is not called for it
43-
* @param mixed $on_empty (since 1.2) whether to return the initial value iff the iterable is empty
45+
* @param bool $on_empty (since 1.2) whether to return the initial value iff the iterable is empty
4446
* @return mixed the reduced value, the initial value or the on_empty value (if passed)
4547
* @throws \RuntimeException when the iterable is empty, no initial value was passed and no_empty was not given
4648
* @since 1.0
49+
* @phpstan-ignore missingType.iterableValue
4750
*/
4851
public static function reduce(iterable $iterable, callable $callback, mixed $initial = new self(), bool $on_empty = false): mixed
4952
{
@@ -58,7 +61,7 @@ public static function reduce(iterable $iterable, callable $callback, mixed $ini
5861
continue;
5962
}
6063
}
61-
$initial = $callback($initial, $v, $k);
64+
$initial = $callback($initial, $v, $k); // @phpstan-ignore argument.type ($k is definitely of type string|int)
6265
}
6366
if ($first && !$has_initial) {
6467
if ($initial_set)
@@ -70,9 +73,11 @@ public static function reduce(iterable $iterable, callable $callback, mixed $ini
7073

7174
/**
7275
* Like implode()/join() in legacy syntax, but outputs the keys too and takes an additional parameter `$kv_sep`.
76+
* @param iterable $data the elements to join
7377
* @param string $sep the separator of elements
7478
* @param string $kv_sep the separator for key and value
7579
* @since 1.0
80+
* @phpstan-ignore missingType.iterableValue
7681
*/
7782
public static function kvjoin(iterable $data, string $sep = ', ', string $kv_sep = '='): string
7883
{
@@ -81,7 +86,7 @@ public static function kvjoin(iterable $data, string $sep = ', ', string $kv_sep
8186
foreach ($data as $k => $v) {
8287
if ($first) $first = false;
8388
else $str .= $sep;
84-
$str .= $k . $kv_sep . $v;
89+
$str .= "$k$kv_sep$v"; // @phpstan-ignore encapsedStringPart.nonString, encapsedStringPart.nonString
8590
}
8691
return $str;
8792
}
@@ -90,13 +95,14 @@ public static function kvjoin(iterable $data, string $sep = ', ', string $kv_sep
9095
* Returns the first mapping (element) of an array as key and value in an array, or null/null if the array is empty.
9196
* Array destructuring is a very convenient way to handle the result: `['k' => $key, 'v' => $value] = Arr::first($array)`
9297
* @param iterable $iterable the source iterable
93-
* @return array ['k' => <key>/null, 'v' => <value>/null]
98+
* @return array{k: string|int|null, v: mixed} ['k' => <key>/null, 'v' => <value>/null]
9499
* @since 1.0
100+
* @phpstan-ignore missingType.iterableValue
95101
*/
96102
public static function first(iterable $iterable): array
97103
{
98104
foreach ($iterable as $k => $v)
99-
return compact('k', 'v');
105+
return compact('k', 'v'); // @phpstan-ignore return.type
100106
return ['k' => null, 'v' => null];
101107
}
102108

@@ -105,8 +111,9 @@ public static function first(iterable $iterable): array
105111
* Array destructuring is a very convenient way to handle the result: `['k' => $key, 'v' => $value] = Arr::find($array, 'key1', 'key2')`
106112
* @param array $array the source array
107113
* @param string|int ...$ks the keys
108-
* @return array ['k' => <key>/null, 'v' => <value>/null]
114+
* @return array{k: string|int|null, v: mixed} ['k' => <key>/null, 'v' => <value>/null]
109115
* @since 1.0
116+
* @phpstan-ignore missingType.iterableValue
110117
*/
111118
public static function find(array $array, string|int ...$ks): array
112119
{
@@ -115,4 +122,4 @@ public static function find(array $array, string|int ...$ks): array
115122
return compact('k', 'v');
116123
return ['k' => null, 'v' => null];
117124
}
118-
}
125+
}

src/Pipe.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function __construct(
2929
)
3030
{}
3131

32-
public function __call(string $method, array $args): self
32+
public function __call(string $method, array $args): self // @phpstan-ignore missingType.iterableValue
3333
{
3434
$this->value = $this->value->{$method}(...$args);
3535
return $this;
@@ -69,7 +69,7 @@ public function new(string $class, mixed ... $args): self
6969
*/
7070
public function get(string|int $key, bool $array_access = false): self
7171
{
72-
$this->value = $array_access || is_int($key) ? $this->value[$key] : $this->value->{$key};
72+
$this->value = $array_access || is_int($key) ? $this->value[$key] : $this->value->{$key}; // @phpstan-ignore offsetAccess.nonOffsetAccessible
7373
return $this;
7474
}
7575

@@ -83,14 +83,14 @@ public function get(string|int $key, bool $array_access = false): self
8383
public function set(string|int $key, mixed $value, bool $array_access = false): self
8484
{
8585
if ($array_access || is_int($key))
86-
$this->value[$key] = $value;
86+
$this->value[$key] = $value; // @phpstan-ignore offsetAccess.nonOffsetAccessible
8787
else
8888
$this->value->{$key} = $value;
8989
return $this;
9090
}
9191

9292
public function __toString(): string
9393
{
94-
return "$this->value";
94+
return "$this->value"; // @phpstan-ignore encapsedStringPart.nonString
9595
}
9696
}

src/Str.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ private function __construct() {}
1616
*/
1717
public static function trim_prefix(string $string, string $prefix): string
1818
{
19-
return $prefix === '' ? $string : preg_replace('#^' . preg_quote($prefix, '#') . '#', '', $string);
19+
return $prefix === '' ? $string : preg_replace('#^' . preg_quote($prefix, '#') . '#', '', $string); // @phpstan-ignore return.type
2020
}
2121

2222
/**
@@ -28,6 +28,6 @@ public static function trim_prefix(string $string, string $prefix): string
2828
*/
2929
public static function trim_suffix(string $string, string $suffix): string
3030
{
31-
return $suffix === '' ? $string : preg_replace('#' . preg_quote($suffix, '#') . '$#', '', $string);
31+
return $suffix === '' ? $string : preg_replace('#' . preg_quote($suffix, '#') . '$#', '', $string); // @phpstan-ignore return.type
3232
}
3333
}

src/Util.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public static function identity(mixed $v): mixed
1818
return $v;
1919
}
2020

21-
private static function nots(bool $null, bool $false, bool $empty, bool $zero): array
21+
private static function nots(bool $null, bool $false, bool $empty, bool $zero): array // @phpstan-ignore missingType.iterableValue
2222
{
2323
$nots = [];
2424
if ($null) $nots[] = null;
@@ -34,7 +34,7 @@ private static function nots(bool $null, bool $false, bool $empty, bool $zero):
3434
* @template T type of the input value
3535
* @template U type of the mapped value
3636
* @param ?T $v the input value to be mapped
37-
* @param ?callable(T): U $fn the mapping function. `null` means {@link identity()} (return $v as-is)
37+
* @param ?callable(?T): U $fn the mapping function. `null` means {@link identity()} (return $v as-is)
3838
* @param bool $null_on_not whether to return null iff the input value matches one of the $nots
3939
* @param bool $func whether to test $fn on null as a 'not' value, too.
4040
* if true, $fn === null means return $v unmapped (only useful with $null_on_not === true, which returns null then);
@@ -56,7 +56,7 @@ public static function map_nots(mixed $v, ?callable $fn = null, bool $null_on_no
5656
* @template T type of the input value
5757
* @template U type of the mapped value
5858
* @param ?T $v
59-
* @param ?callable(T): ?U $fn the mapping function. `null` means {@link identity()} (return $v as-is)
59+
* @param ?callable(?T): ?U $fn the mapping function. `null` means {@link identity()} (return $v as-is)
6060
* @param bool $null_on_not return null on falsy (as selected by $func, $null, $false, $empty and $zero)
6161
* @param bool $func whether $fn === null means falsy too
6262
* @param bool $null whether null is a falsy value
@@ -109,7 +109,7 @@ public static function when(mixed $test, mixed $v, ?callable $fn = null, bool $n
109109
* For any node in a tree structure, get all parents (possibly up to a specific one) and return them from top to bottom
110110
* as an iterable (Generator): `foreach (tree_path($node) as $parent_node) {...}`
111111
* @template T the node type
112-
* @param T $element the starting node
112+
* @param ?T $element the starting node
113113
* @param callable(T): ?T $get_parent the function to get the parent node of a child node
114114
* @param ?callable(T): bool $while an optional check when to stop (`$while` must return false to not rise further in the tree)
115115
* @return \Generator<T> the iterable, directly usable in `foreach(...)`
@@ -134,6 +134,6 @@ public static function tree_path(mixed $element, callable $get_parent, ?callable
134134
*/
135135
public static function new(string $class): \Closure
136136
{
137-
return fn(...$args) => new $class(...$args);
137+
return static fn(...$args) => new $class(...$args);
138138
}
139139
}

0 commit comments

Comments
 (0)