• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ICanBoogie / Common / 4509235923

pending completion
4509235923

push

github

Olivier Laviale
Deprecate stable_sort()

5 of 5 new or added lines in 1 file covered. (100.0%)

105 of 269 relevant lines covered (39.03%)

2.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/lib/array.php
1
<?php
2

3
namespace ICanBoogie;
4

5
use LogicException;
6

7
use function array_filter;
8
use function array_key_exists;
9
use function array_keys;
10
use function array_merge;
11
use function array_search;
12
use function array_shift;
13
use function array_splice;
14
use function array_unshift;
15
use function array_walk;
16
use function asort;
17
use function count;
18
use function is_array;
19
use function is_numeric;
20
use function is_scalar;
21
use function max;
22
use function min;
23
use function reset;
24
use function substr;
25
use function trigger_error;
26

27
use const E_USER_DEPRECATED;
28

29
/**
30
 * Sorts an array using a stable sorting algorithm while preserving its keys.
31
 *
32
 * A stable sorting algorithm maintains the relative order of values with equal keys.
33
 *
34
 * The array is always sorted in ascending order but one can use the array_reverse() function to
35
 * reverse the array. Also, keys are preserved, even numeric ones, use the array_values() function
36
 * to create an array with an ascending index.
37
 *
38
 * @param array<int|string, mixed> $array
39
 *
40
 * @deprecated Since PHP 8.0, asort() is stable https://wiki.php.net/rfc/stable_sorting
41
 */
42
function stable_sort(array &$array, callable $picker = null): void
43
{
44
    @trigger_error('icanboogie/common: stable_sort() is deprecated, use asort() or uasort()', E_USER_DEPRECATED);
×
45

46
    if ($picker) {
×
47
        uasort($array, $picker);
×
48
    } else {
49
        asort($array);
×
50
    }
51
}
52

53
/**
54
 * Sort an array according to the weight of its items.
55
 *
56
 * The weight of the items is defined as an integer; a position relative to another member of the
57
 * array `before:<key>` or `after:<key>`; the special words `top` and `bottom`.
58
 *
59
 * @param array<int|string, mixed> $array
60
 * @param callable $weight_picker The callback function used to pick the weight of the item. The
61
 * function is called with the following arguments: `$value`, `$key`.
62
 *
63
 * @return array<int|string, mixed> A sorted copy of the array.
64
 */
65
function sort_by_weight(array $array, callable $weight_picker): array
66
{
67
    if (!$array) {
3✔
68
        return $array;
×
69
    }
70

71
    $order = [];
3✔
72

73
    foreach ($array as $k => $v) {
3✔
74
        $order[$k] = $weight_picker($v, $k);
3✔
75
    }
76

77
    $n = count($order);
3✔
78

79
    $numeric_order = array_filter($order, fn($weight) => is_scalar($weight) && is_numeric($weight));
3✔
80

81
    if ($numeric_order) {
3✔
82
        $top = min($numeric_order) - $n;
3✔
83
        $bottom = max($numeric_order) + $n;
3✔
84
    } else {
85
        $top = -$n;
×
86
        $bottom = $n;
×
87
    }
88

89
    foreach ($order as &$weight) {
3✔
90
        if ($weight === 'top') {
3✔
91
            $weight = --$top;
2✔
92
        } else {
93
            if ($weight === 'bottom') {
3✔
94
                $weight = ++$bottom;
2✔
95
            }
96
        }
97
    }
98

99
    foreach ($order as $k => &$weight) {
3✔
100
        if (str_starts_with($weight, 'before:')) {
3✔
101
            $target = substr($weight, 7);
1✔
102

103
            if (isset($order[$target])) {
1✔
104
                $order = array_insert($order, $target, $order[$target], $k);
1✔
105
            } else {
106
                $weight = 0;
1✔
107
            }
108
        } else {
109
            if (str_starts_with($weight, 'after:')) {
3✔
110
                $target = substr($weight, 6);
2✔
111

112
                if (isset($order[$target])) {
2✔
113
                    $order = array_insert($order, $target, $order[$target], $k, true);
1✔
114
                } else {
115
                    $weight = 0;
1✔
116
                }
117
            }
118
        }
119
    }
120

121
    asort($order);
3✔
122

123
    array_walk($order, function (&$v, $k) use ($array) {
3✔
124
        $v = $array[$k];
3✔
125
    });
3✔
126

127
    return $order;
3✔
128
}
129

130
/**
131
 * Inserts a value in an array before, or after, a given key.
132
 *
133
 * Numeric keys are not preserved.
134
 *
135
 * @param array<int|string, mixed> $array
136
 * @param mixed $relative
137
 * @param mixed $value
138
 * @param string|int|null $key
139
 * @param bool $after
140
 *
141
 * @return array<int|string, mixed>
142
 */
143
function array_insert(array $array, mixed $relative, mixed $value, string|int $key = null, bool $after = false): array
144
{
145
    if ($key) {
1✔
146
        unset($array[$key]);
1✔
147
    }
148

149
    $keys = array_keys($array);
1✔
150
    $pos = array_search($relative, $keys, true);
1✔
151

152
    if ($pos === false) {
1✔
153
        throw new LogicException("Relative not found.");
×
154
    }
155

156
    if ($after) {
1✔
157
        $pos++;
1✔
158
    }
159

160
    $spliced = array_splice($array, $pos);
1✔
161

162
    if ($key !== null) {
1✔
163
        $array = array_merge($array, [ $key => $value ]);
1✔
164
    } else {
165
        array_unshift($spliced, $value);
×
166
    }
167

168
    return array_merge($array, $spliced);
1✔
169
}
170

171
/**
172
 * Flattens an array.
173
 *
174
 * @param array<int|string, mixed> $array
175
 * @param string|array{ string, string } $separator
176
 *
177
 * @return array<int|string, mixed>
178
 */
179
function array_flatten(array $array, string|array $separator = '.', int $depth = 0): array
180
{
181
    $rc = [];
2✔
182

183
    if (is_array($separator)) {
2✔
184
        foreach ($array as $key => $value) {
1✔
185
            if (!is_array($value)) {
1✔
186
                $rc[$key . ($depth ? $separator[1] : '')] = $value;
1✔
187

188
                continue;
1✔
189
            }
190

191
            $values = array_flatten($value, $separator, $depth + 1);
1✔
192

193
            foreach ($values as $sk => $sv) {
1✔
194
                $rc[$key . ($depth ? $separator[1] : '') . $separator[0] . $sk] = $sv;
1✔
195
            }
196
        }
197
    } else {
198
        foreach ($array as $key => $value) {
1✔
199
            if (!is_array($value)) {
1✔
200
                $rc[$key] = $value;
1✔
201

202
                continue;
1✔
203
            }
204

205
            $values = array_flatten($value, $separator);
1✔
206

207
            foreach ($values as $sk => $sv) {
1✔
208
                $rc[$key . $separator . $sk] = $sv;
1✔
209
            }
210
        }
211
    }
212

213
    return $rc;
2✔
214
}
215

216
/**
217
 * Merge arrays recursively with a different algorithm than PHP.
218
 *
219
 * @param array<int|string, mixed> ...$arrays
220
 *
221
 * @return array<int|string, mixed>
222
 */
223
function array_merge_recursive(array ...$arrays): array
224
{
225
    if (count($arrays) < 2) {
×
226
        return reset($arrays) ?: [];
×
227
    }
228

229
    $merge = array_shift($arrays);
×
230

231
    foreach ($arrays as $array) {
×
232
        foreach ($array as $key => $val) {
×
233
            #
234
            # if the value is an array and the key already exists
235
            # we have to make a recursion
236
            #
237

238
            if (is_array($val) && array_key_exists($key, $merge)) {
×
239
                $val = array_merge_recursive((array) $merge[$key], $val);
×
240
            }
241

242
            #
243
            # if the key is numeric, the value is pushed. Otherwise, it replaces
244
            # the value of the _merge_ array.
245
            #
246

247
            if (is_numeric($key)) {
×
248
                $merge[] = $val;
×
249
            } else {
250
                $merge[$key] = $val;
×
251
            }
252
        }
253
    }
254

255
    return $merge;
×
256
}
257

258
/**
259
 * @param array<int|string, mixed> ...$arrays
260
 *
261
 * @return array<int|string, mixed>
262
 */
263
function exact_array_merge_recursive(array ...$arrays): array
264
{
265
    if (count($arrays) < 2) {
×
266
        return reset($arrays) ?: [];
×
267
    }
268

269
    $merge = array_shift($arrays);
×
270

271
    foreach ($arrays as $array) {
×
272
        foreach ($array as $key => $val) {
×
273
            #
274
            # if the value is an array and the key already exists
275
            # we have to make a recursion
276
            #
277

278
            if (is_array($val) && array_key_exists($key, $merge)) {
×
279
                $val = exact_array_merge_recursive((array) $merge[$key], $val);
×
280
            }
281

282
            $merge[$key] = $val;
×
283
        }
284
    }
285

286
    return $merge;
×
287
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc