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

tempestphp / tempest-framework / 11828633715

13 Nov 2024 10:13PM UTC coverage: 82.602% (+0.1%) from 82.479%
11828633715

push

github

web-flow
refactor: replace `ramsey/uuid` with `symfony/uid` (#724)

2 of 2 new or added lines in 2 files covered. (100.0%)

32 existing lines in 4 files now uncovered.

7435 of 9001 relevant lines covered (82.6%)

49.19 hits per line

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

95.19
/src/Tempest/Support/src/StringHelper.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Support;
6

7
use Countable;
8
use function ltrim;
9
use function preg_quote;
10
use function preg_replace;
11
use function rtrim;
12
use Stringable;
13
use function trim;
14

15
final readonly class StringHelper implements Stringable
16
{
17
    private string $string;
18

19
    public function __construct(?string $string = '')
318✔
20
    {
21
        $this->string = $string ?? '';
318✔
22
    }
23

24
    /**
25
     * Converts the instance to a string.
26
     */
27
    public function toString(): string
260✔
28
    {
29
        return $this->string;
260✔
30
    }
31

32
    /**
33
     * Converts the instance to a string.
34
     */
35
    public function __toString(): string
169✔
36
    {
37
        return $this->string;
169✔
38
    }
39

40
    /**
41
     * Asserts whether the instance is equal to the given instance or string.
42
     */
43
    public function equals(string|Stringable $other): bool
45✔
44
    {
45
        return $this->string === (string) $other;
45✔
46
    }
47

48
    /**
49
     * Converts the instance to title case.
50
     */
51
    public function title(): self
1✔
52
    {
53
        return new self(mb_convert_case($this->string, MB_CASE_TITLE, 'UTF-8'));
1✔
54
    }
55

56
    /**
57
     * Converts the instance to lower case.
58
     */
59
    public function lower(): self
18✔
60
    {
61
        return new self(mb_strtolower($this->string, 'UTF-8'));
18✔
62
    }
63

64
    /**
65
     * Converts the instance to upper case.
66
     */
67
    public function upper(): self
×
68
    {
UNCOV
69
        return new self(mb_strtoupper($this->string, 'UTF-8'));
×
70
    }
71

72
    /**
73
     * Converts the instance to snake case.
74
     */
75
    public function snake(string $delimiter = '_'): self
196✔
76
    {
77
        $string = $this->string;
196✔
78

79
        if (ctype_lower($string)) {
196✔
80
            return $this;
69✔
81
        }
82

83
        $string = preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $string);
161✔
84
        $string = preg_replace(
161✔
85
            '![^' . preg_quote($delimiter) . '\pL\pN\s]+!u',
161✔
86
            $delimiter,
161✔
87
            mb_strtolower($string, 'UTF-8')
161✔
88
        );
161✔
89
        $string = preg_replace('/\s+/u', $delimiter, $string);
161✔
90
        $string = trim($string, $delimiter);
161✔
91

92
        return (new self($string))->deduplicate($delimiter);
161✔
93
    }
94

95
    /**
96
     * Converts the instance to kebab case.
97
     */
98
    public function kebab(): self
189✔
99
    {
100
        return $this->snake('-');
189✔
101
    }
102

103
    /**
104
     * Converts the instance to pascal case.
105
     */
106
    public function pascal(): self
59✔
107
    {
108
        $words = explode(' ', str_replace(['-', '_'], ' ', $this->string));
59✔
109

110
        // TODO: use `mb_ucfirst` when it has landed in PHP 8.4
111
        $studlyWords = array_map(static fn (string $word) => ucfirst($word), $words);
59✔
112

113
        return new self(implode('', $studlyWords));
59✔
114
    }
115

116
    /**
117
     * Converts the instance to camel case.
118
     */
119
    public function camel(): self
55✔
120
    {
121
        return new self(lcfirst((string)$this->pascal()));
55✔
122
    }
123

124
    /**
125
     * Replaces consecutive instances of a given character with a single character.
126
     */
127
    public function deduplicate(string|array $characters = ' '): self
162✔
128
    {
129
        $string = $this->string;
162✔
130

131
        foreach (arr($characters) as $character) {
162✔
132
            $string = preg_replace('/' . preg_quote($character, '/') . '+/u', $character, $string);
162✔
133
        }
134

135
        return new self($string);
162✔
136
    }
137

138
    /**
139
     * Converts the instance to its English plural form.
140
     */
141
    public function pluralize(int|array|Countable $count = 2): self
55✔
142
    {
143
        return new self(LanguageHelper::pluralize($this->string, $count));
55✔
144
    }
145

146
    /**
147
     * Converts the last word to its English plural form.
148
     */
149
    public function pluralizeLast(int|array|Countable $count = 2): self
55✔
150
    {
151
        $parts = preg_split('/(.)(?=[A-Z])/u', $this->string, -1, PREG_SPLIT_DELIM_CAPTURE);
55✔
152

153
        $lastWord = array_pop($parts);
55✔
154

155
        $string = implode('', $parts) . (new self($lastWord))->pluralize($count);
55✔
156

157
        return new self($string);
55✔
158
    }
159

160
    /**
161
     * Creates a random alpha-numeric string of the given length.
162
     */
163
    public function random(int $length = 16): self
3✔
164
    {
165
        $string = '';
3✔
166

167
        while (($len = strlen($string)) < $length) {
3✔
168
            $size = $length - $len;
2✔
169
            $bytesSize = (int)ceil($size / 3) * 3;
2✔
170
            $bytes = random_bytes($bytesSize);
2✔
171
            $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), offset: 0, length: $size);
2✔
172
        }
173

174
        return new self($string);
3✔
175
    }
176

177
    /**
178
     * Caps the instance with the given string.
179
     */
180
    public function finish(string $cap): self
1✔
181
    {
182
        return new self(
1✔
183
            preg_replace('/(?:' . preg_quote($cap, '/') . ')+$/u', replacement: '', subject: $this->string) . $cap
1✔
184
        );
1✔
185
    }
186

187
    /**
188
     * Prefixes the instance with the given string.
189
     */
190
    public function start(string $prefix): self
1✔
191
    {
192
        return new self(
1✔
193
            $prefix.preg_replace('/^(?:'.preg_quote($prefix, '/').')+/u', replacement: '', subject: $this->string)
1✔
194
        );
1✔
195
    }
196

197
    /**
198
     * Returns the remainder of the string after the first occurrence of the given value.
199
     */
200
    public function after(Stringable|string|array $search): self
3✔
201
    {
202
        $search = $this->normalizeString($search);
3✔
203

204
        if ($search === '' || $search === []) {
3✔
205
            return $this;
1✔
206
        }
207

208
        $nearestPosition = mb_strlen($this->string); // Initialize with a large value
3✔
209
        $foundSearch = '';
3✔
210

211
        foreach (arr($search) as $term) {
3✔
212
            $position = mb_strpos($this->string, $term);
3✔
213

214
            if ($position !== false && $position < $nearestPosition) {
3✔
215
                $nearestPosition = $position;
3✔
216
                $foundSearch = $term;
3✔
217
            }
218
        }
219

220
        if ($nearestPosition === mb_strlen($this->string)) {
3✔
221
            return $this;
3✔
222
        }
223

224
        $string = mb_substr($this->string, $nearestPosition + mb_strlen($foundSearch));
3✔
225

226
        return new self($string);
3✔
227
    }
228

229
    /**
230
     * Returns the remainder of the string after the last occurrence of the given value.
231
     */
232
    public function afterLast(Stringable|string|array $search): self
3✔
233
    {
234
        $search = $this->normalizeString($search);
3✔
235

236
        if ($search === '' || $search === []) {
3✔
237
            return $this;
1✔
238
        }
239

240
        $farthestPosition = -1;
3✔
241
        $foundSearch = null;
3✔
242

243
        foreach (arr($search) as $term) {
3✔
244
            $position = mb_strrpos($this->string, $term);
3✔
245

246
            if ($position !== false && $position > $farthestPosition) {
3✔
247
                $farthestPosition = $position;
3✔
248
                $foundSearch = $term;
3✔
249
            }
250
        }
251

252
        if ($farthestPosition === -1 || $foundSearch === null) {
3✔
253
            return $this;
1✔
254
        }
255

256
        $string = mb_substr($this->string, $farthestPosition + strlen($foundSearch));
3✔
257

258
        return new self($string);
3✔
259
    }
260

261
    /**
262
     * Returns the portion of the string before the first occurrence of the given value.
263
     */
264
    public function before(Stringable|string|array $search): self
1✔
265
    {
266
        $search = $this->normalizeString($search);
1✔
267

268
        if ($search === '' || $search === []) {
1✔
269
            return $this;
1✔
270
        }
271

272
        $nearestPosition = mb_strlen($this->string);
1✔
273

274
        foreach (arr($search) as $char) {
1✔
275
            $position = mb_strpos($this->string, $char);
1✔
276

277
            if ($position !== false && $position < $nearestPosition) {
1✔
278
                $nearestPosition = $position;
1✔
279
            }
280
        }
281

282
        if ($nearestPosition === mb_strlen($this->string)) {
1✔
283
            return $this;
1✔
284
        }
285

286
        $string = mb_substr($this->string, start: 0, length: $nearestPosition);
1✔
287

288
        return new self($string);
1✔
289
    }
290

291
    /**
292
     * Returns the portion of the string before the last occurrence of the given value.
293
     */
294
    public function beforeLast(Stringable|string|array $search): self
3✔
295
    {
296
        $search = $this->normalizeString($search);
3✔
297

298
        if ($search === '' || $search === []) {
3✔
299
            return $this;
1✔
300
        }
301

302
        $farthestPosition = -1;
3✔
303

304
        foreach (arr($search) as $char) {
3✔
305
            $position = mb_strrpos($this->string, $char);
3✔
306

307
            if ($position !== false && $position > $farthestPosition) {
3✔
308
                $farthestPosition = $position;
3✔
309
            }
310
        }
311

312
        if ($farthestPosition === -1) {
3✔
313
            return $this;
3✔
314
        }
315

316
        $string = mb_substr($this->string, start: 0, length: $farthestPosition);
3✔
317

318
        return new self($string);
3✔
319
    }
320

321
    /**
322
     * Returns the portion of the string between the widest possible instances of the given strings.
323
     */
324
    public function between(string|Stringable $from, string|Stringable $to): self
1✔
325
    {
326
        $from = $this->normalizeString($from);
1✔
327
        $to = $this->normalizeString($to);
1✔
328

329
        if ($from === '' || $to === '') {
1✔
330
            return $this;
1✔
331
        }
332

333
        return $this->after($from)->beforeLast($to);
1✔
334
    }
335

336
    /**
337
     * Removes all whitespace (or specified characters) from both ends of the instance.
338
     */
339
    public function trim(string $characters = " \n\r\t\v\0"): self
3✔
340
    {
341
        return new self(trim($this->string, $characters));
3✔
342
    }
343

344
    /**
345
     * Removes all whitespace (or specified characters) from the start of the instance.
346
     */
347
    public function ltrim(string $characters = " \n\r\t\v\0"): self
×
348
    {
UNCOV
349
        return new self(ltrim($this->string, $characters));
×
350
    }
351

352
    /**
353
     * Removes all whitespace (or specified characters) from the end of the instance.
354
     */
355
    public function rtrim(string $characters = " \n\r\t\v\0"): self
×
356
    {
UNCOV
357
        return new self(rtrim($this->string, $characters));
×
358
    }
359

360
    /**
361
     * Returns the multi-bytes length of the instance.
362
     */
363
    public function length(): int
3✔
364
    {
365
        return mb_strlen($this->string);
3✔
366
    }
367

368
    /**
369
     * Returns the base name of the instance, assuming the instance is a class name.
370
     */
371
    public function classBasename(): self
57✔
372
    {
373
        return new self(basename(str_replace('\\', '/', $this->string)));
57✔
374
    }
375

376
    /**
377
     * Asserts whether the instance starts with one of the given needles.
378
     */
379
    public function startsWith(Stringable|string|array $needles): bool
196✔
380
    {
381
        if (! is_array($needles)) {
196✔
382
            $needles = [$needles];
185✔
383
        }
384

385
        foreach ($needles as $needle) {
196✔
386
            if (str_starts_with($this->string, (string) $needle)) {
196✔
387
                return true;
19✔
388
            }
389
        }
390

391
        return false;
190✔
392
    }
393

394
    /**
395
     * Asserts whether the instance ends with one of the given `$needles`.
396
     */
397
    public function endsWith(Stringable|string|array $needles): bool
7✔
398
    {
399
        if (! is_array($needles)) {
7✔
400
            $needles = [$needles];
5✔
401
        }
402

403
        foreach ($needles as $needle) {
7✔
404
            if (str_ends_with($this->string, (string) $needle)) {
7✔
405
                return true;
7✔
406
            }
407
        }
408

409
        return false;
3✔
410
    }
411

412
    /**
413
     * Replaces the first occurence of `$search` with `$replace`.
414
     */
415
    public function replaceFirst(Stringable|string $search, Stringable|string $replace): self
27✔
416
    {
417
        $search = $this->normalizeString($search);
27✔
418

419
        if ($search === '') {
27✔
420
            return $this;
1✔
421
        }
422

423
        $position = strpos($this->string, (string) $search);
27✔
424

425
        if ($position === false) {
27✔
426
            return $this;
1✔
427
        }
428

429
        return new self(substr_replace($this->string, $replace, $position, strlen($search)));
27✔
430
    }
431

432
    /**
433
     * Replaces the last occurence of `$search` with `$replace`.
434
     */
435
    public function replaceLast(Stringable|string $search, Stringable|string $replace): self
22✔
436
    {
437
        $search = $this->normalizeString($search);
22✔
438

439
        if ($search === '') {
22✔
440
            return $this;
1✔
441
        }
442

443
        $position = strrpos($this->string, (string) $search);
22✔
444

445
        if ($position === false) {
22✔
446
            return $this;
1✔
447
        }
448

449
        return new self(substr_replace($this->string, $replace, $position, strlen($search)));
22✔
450
    }
451

452
    /**
453
     * Replaces `$search` with `$replace` if `$search` is at the end of the instance.
454
     */
455
    public function replaceEnd(Stringable|string $search, Stringable|string $replace): self
3✔
456
    {
457
        $search = $this->normalizeString($search);
3✔
458

459
        if ($search === '') {
3✔
460
            return $this;
1✔
461
        }
462

463
        if (! $this->endsWith($search)) {
3✔
464
            return $this;
1✔
465
        }
466

467
        return $this->replaceLast($search, $replace);
3✔
468
    }
469

470
    /**
471
     * Replaces `$search` with `$replace` if `$search` is at the start of the instance.
472
     */
473
    public function replaceStart(Stringable|string $search, Stringable|string $replace): self
151✔
474
    {
475
        if ($search === '') {
151✔
UNCOV
476
            return $this;
×
477
        }
478

479
        if (! $this->startsWith($search)) {
151✔
480
            return $this;
151✔
481
        }
482

483
        return $this->replaceFirst($search, $replace);
8✔
484
    }
485

486
    /**
487
     * Replaces the portion of the specified `$length` at the specified `$position` with the specified `$replace`.
488
     *
489
     * ### Example
490
     * ```php
491
     * str('Lorem dolor')->replaceAt(6, 5, 'ipsum'); // Lorem ipsum
492
     * ```
493
     */
494
    public function replaceAt(int $position, int $length, Stringable|string $replace): self
1✔
495
    {
496
        if ($length < 0) {
1✔
497
            $position += $length;
1✔
498
            $length = abs($length);
1✔
499
        }
500

501
        return new self(substr_replace($this->string, (string) $replace, $position, $length));
1✔
502
    }
503

504
    /**
505
     * Appends the given strings to the instance.
506
     */
507
    public function append(string|Stringable ...$append): self
19✔
508
    {
509
        return new self($this->string . implode('', $append));
19✔
510
    }
511

512
    /**
513
     * Prepends the given strings to the instance.
514
     */
515
    public function prepend(string|Stringable ...$prepend): self
80✔
516
    {
517
        return new self(implode('', $prepend) . $this->string);
80✔
518
    }
519

520
    /**
521
     * Wraps the instance with the given string. If `$after` is specified, it will be appended instead of `$before`.
522
     *
523
     * ### Example
524
     * ```php
525
     * str('Scott')->wrap(before: 'Leon ', after: ' Kennedy'); // Leon Scott Kennedy
526
     * ```
527
     */
528
    public function wrap(string|Stringable $before, string|Stringable $after = null): self
2✔
529
    {
530
        return new self($before . $this->string . ($after ??= $before));
2✔
531
    }
532

533
    /**
534
     * Removes the specified `$before` and `$after` from the beginning and the end of the instance. If `$after` is null, `$before` is used instead.
535
     * Setting `$strict` to `false` will unwrap the instance even if both ends do not correspond to the specified `$before` and `$after`.
536
     *
537
     * ### Example
538
     * ```php
539
     *  str('Scott Kennedy')->unwrap(before: 'Leon ', after: ' Kennedy', strict: false); // Scott
540
     * ```
541
     */
542
    public function unwrap(string|Stringable $before, string|Stringable $after = null, bool $strict = true): self
1✔
543
    {
544
        $string = $this->string;
1✔
545

546
        if ($string === '') {
1✔
UNCOV
547
            return $this;
×
548
        }
549

550
        if ($after === null) {
1✔
551
            $after = $before;
1✔
552
        }
553

554
        if (! $strict) {
1✔
555
            return (new self($string))->after($before)->beforeLast($after);
1✔
556
        }
557

558
        if ($this->startsWith($before) && $this->endsWith($after)) {
1✔
559
            $string = (string) (new self($string))->after($before)->beforeLast($after);
1✔
560
        }
561

562
        return new self($string);
1✔
563
    }
564

565
    /**
566
     * Replaces all occurrences of the given `$search` with `$replace`.
567
     */
568
    public function replace(Stringable|string|array $search, Stringable|string|array $replace): self
88✔
569
    {
570
        $search = $this->normalizeString($search);
88✔
571
        $replace = $this->normalizeString($replace);
88✔
572

573
        return new self(str_replace($search, $replace, $this->string));
88✔
574
    }
575

576
    /**
577
     * Replaces the patterns matching the given regular expression.
578
     */
579
    public function replaceRegex(string|array $regex, string|array|callable $replace): self
71✔
580
    {
581
        if (is_callable($replace)) {
71✔
582
            return new self(preg_replace_callback($regex, $replace, $this->string));
66✔
583
        }
584

585
        return new self(preg_replace($regex, $replace, $this->string));
71✔
586
    }
587

588
    /**
589
     * Gets the first portion of the instance that matches the given regular expression.
590
     */
591
    public function match(string $regex): array
15✔
592
    {
593
        preg_match($regex, $this->string, $matches);
15✔
594

595
        return $matches;
15✔
596
    }
597

598
    /**
599
     * Gets all portions of the instance that match the given regular expression.
600
     */
601
    public function matchAll(string $regex, int $flags = 0, int $offset = 0): array
1✔
602
    {
603
        $result = preg_match_all($regex, $this->string, $matches, $flags, $offset);
1✔
604

605
        if ($result === 0) {
1✔
606
            return [];
1✔
607
        }
608

609
        return $matches;
1✔
610
    }
611

612
    /**
613
     * Asserts whether the instance matches the given regular expression.
614
     */
615
    public function matches(string $regex): bool
10✔
616
    {
617
        return ($this->match($regex)[0] ?? null) !== null;
10✔
618
    }
619

620
    /**
621
     * Dumps the instance and stops the execution of the script.
622
     */
UNCOV
623
    public function dd(mixed ...$dd): void
×
624
    {
UNCOV
625
        ld($this->string, ...$dd);
×
626
    }
627

628
    /**
629
     * Dumps the instance.
630
     */
UNCOV
631
    public function dump(mixed ...$dumps): self
×
632
    {
UNCOV
633
        lw($this->string, ...$dumps);
×
634

UNCOV
635
        return $this;
×
636
    }
637

638
    /**
639
     * Extracts an excerpt from the instance.
640
     */
641
    public function excerpt(int $from, int $to, bool $asArray = false): self|ArrayHelper
1✔
642
    {
643
        $lines = explode(PHP_EOL, $this->string);
1✔
644

645
        $from = max(0, $from - 1);
1✔
646

647
        $to = min($to - 1, count($lines));
1✔
648

649
        $lines = array_slice($lines, $from, $to - $from + 1, true);
1✔
650

651
        if ($asArray) {
1✔
652
            return arr($lines)
1✔
653
                ->mapWithKeys(fn (string $line, int $number) => yield $number + 1 => $line);
1✔
654
        }
655

656
        return new self(implode(PHP_EOL, $lines));
1✔
657
    }
658

659
    /**
660
     * Truncates the instance to the specified amount of characters.
661
     *
662
     * ### Example
663
     * ```php
664
     * str('Lorem ipsum')->truncate(5, end: '...'); // Lorem...
665
     * ```
666
     */
667
    public function truncate(int $characters, string $end = ''): self
1✔
668
    {
669
        if (mb_strwidth($this->string, 'UTF-8') <= $characters) {
1✔
670
            return $this;
1✔
671
        }
672

673
        return new self(rtrim(mb_strimwidth($this->string, 0, $characters, encoding: 'UTF-8')) . $end);
1✔
674
    }
675

676
    /**
677
     * Gets parts of the instance.
678
     *
679
     * ### Example
680
     * ```php
681
     * str('Lorem ipsum')->substr(0, length: 5); // Lorem
682
     * str('Lorem ipsum')->substr(6); // ipsum
683
     * ```
684
     */
685
    public function substr(int $start, ?int $length = null): self
2✔
686
    {
687
        return new self(mb_substr($this->string, $start, $length));
2✔
688
    }
689

690
    /**
691
     * Takes the specified amount of characters. If `$length` is negative, starts from the end.
692
     */
693
    public function take(int $length): self
1✔
694
    {
695
        if ($length < 0) {
1✔
696
            return $this->substr($length);
1✔
697
        }
698

699
        return $this->substr(0, $length);
1✔
700
    }
701

702
    /**
703
     * Splits the instance into chunks of the specified `$length`.
704
     */
705
    public function split(int $length): ArrayHelper
1✔
706
    {
707
        if ($length <= 0) {
1✔
708
            return new ArrayHelper();
1✔
709
        }
710

711
        if ($this->equals('')) {
1✔
712
            return new ArrayHelper(['']);
1✔
713
        }
714

715
        $chunks = [];
1✔
716

717
        foreach (str_split($this->string, $length) as $chunk) {
1✔
718
            $chunks[] = $chunk;
1✔
719
        }
720

721
        return new ArrayHelper($chunks);
1✔
722
    }
723

724
    private function normalizeString(mixed $value): mixed
105✔
725
    {
726
        if ($value instanceof Stringable) {
105✔
727
            return (string) $value;
6✔
728
        }
729

730
        return $value;
105✔
731
    }
732

733
    /**
734
     * Explodes the string into an `ArrayHelper` instance by a separator.
735
     */
736
    public function explode(string $separator = ' '): ArrayHelper
3✔
737
    {
738
        return ArrayHelper::explode($this->string, $separator);
3✔
739
    }
740

741
    /**
742
     * Strips HTML and PHP tags from the instance.
743
     *
744
     * @param null|string|string[] $allowed Allowed tags.
745
     *
746
     * ### Example
747
     * ```php
748
     * str('<p>Lorem ipsum</p>')->stripTags(); // Lorem ipsum
749
     * str('<p>Lorem <strong>ipsum</strong></p>')->stripTags(allowed: 'strong'); // Lorem <strong>ipsum</strong>
750
     * ```
751
     */
752
    public function stripTags(null|string|array $allowed = null): self
1✔
753
    {
754
        $allowed = arr($allowed)
1✔
755
            ->map(fn (string $tag) => str($tag)->wrap('<', '>')->toString())
1✔
756
            ->toArray();
1✔
757

758
        return new self(strip_tags($this->string, $allowed));
1✔
759
    }
760

761
    /**
762
     * Inserts the specified `$string` at the specified `$position`.
763
     *
764
     * ### Example
765
     * ```php
766
     * str('Lorem ipsum sit amet')->insertAt(11, ' dolor'); // Lorem ipsum dolor sit amet
767
     * ```
768
     */
769
    public function insertAt(int $position, string $string): self
1✔
770
    {
771
        return new self(
1✔
772
            mb_substr($this->string, 0, $position) . $string . mb_substr($this->string, $position)
1✔
773
        );
1✔
774
    }
775

776
    /**
777
     * Implodes the given array into a string by a separator.
778
     */
779
    public static function implode(array|ArrayHelper $parts, string $glue = ' '): self
1✔
780
    {
781
        return arr($parts)->implode($glue);
1✔
782
    }
783

784
    /**
785
     * Joins all values using the specified `$glue`. The last item of the string is separated by `$finalGlue`.
786
     */
787
    public static function join(array|ArrayHelper $parts, string $glue = ', ', ?string $finalGlue = ' and '): self
5✔
788
    {
789
        return arr($parts)->join($glue, $finalGlue);
5✔
790
    }
791
}
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

© 2026 Coveralls, Inc