Completed
Push — master ( 3790e4...3c9715 )
by Lars
14:22
created

Stringy::lines()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.1158

Importance

Changes 0
Metric Value
cc 5
nc 6
nop 1
dl 0
loc 32
ccs 10
cts 12
cp 0.8333
crap 5.1158
rs 9.0968
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stringy;
6
7
use Defuse\Crypto\Crypto;
8
use voku\helper\AntiXSS;
9
use voku\helper\ASCII;
10
use voku\helper\EmailCheck;
11
use voku\helper\URLify;
12
use voku\helper\UTF8;
13
14
/**
15
 * @template-implements \IteratorAggregate<string>
16
 * @template-implements \ArrayAccess<array-key,string>
17
 */
18
class Stringy implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable
19
{
20
    /**
21
     * An instance's string.
22
     *
23
     * @var string
24
     */
25
    protected $str;
26
27
    /**
28
     * The string's encoding, which should be one of the mbstring module's
29
     * supported encodings.
30
     *
31
     * @var string
32
     */
33
    protected $encoding;
34
35
    /**
36
     * @var UTF8
37
     */
38
    private $utf8;
39
40
    /**
41
     * @var ASCII
42
     */
43
    private $ascii;
44
45
    /**
46
     * Initializes a Stringy object and assigns both str and encoding properties
47
     * the supplied values. $str is cast to a string prior to assignment, and if
48
     * $encoding is not specified, it defaults to mb_internal_encoding(). Throws
49
     * an InvalidArgumentException if the first argument is an array or object
50
     * without a __toString method.
51
     *
52
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
53
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
54
     *
55
     * @throws \InvalidArgumentException
56
     *                                   <p>if an array or object without a
57
     *                                   __toString method is passed as the first argument</p>
58
     *
59
     * @psalm-mutation-free
60
     */
61 3625
    public function __construct($str = '', string $encoding = null)
62
    {
63 3625
        if (\is_array($str)) {
64 3
            throw new \InvalidArgumentException(
65 3
                'Passed value cannot be an array'
66
            );
67
        }
68
69
        if (
70 3622
            \is_object($str)
71
            &&
72 3622
            !\method_exists($str, '__toString')
73
        ) {
74 3
            throw new \InvalidArgumentException(
75 3
                'Passed object must have a __toString method'
76
            );
77
        }
78
79 3619
        $this->str = (string) $str;
80
81 3619
        static $ASCII = null;
82 3619
        if ($ASCII === null) {
83
            $ASCII = new ASCII();
84
        }
85 3619
        $this->ascii = $ASCII;
86
87 3619
        static $UTF8 = null;
88 3619
        if ($UTF8 === null) {
89
            $UTF8 = new UTF8();
90
        }
91 3619
        $this->utf8 = $UTF8;
92
93 3619
        if ($encoding !== 'UTF-8') {
94 2449
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
95
        } else {
96 2690
            $this->encoding = $encoding;
97
        }
98 3619
    }
99
100
    /**
101
     * Returns the value in $str.
102
     *
103
     * @psalm-mutation-free
104
     *
105
     * @return string
106
     *                <p>The current value of the $str property.</p>
107
     */
108 1136
    public function __toString()
109
    {
110 1136
        return (string) $this->str;
111
    }
112
113
    /**
114
     * Return part of the string occurring after a specific string.
115
     *
116
     * @param string $string <p>The delimiting string.</p>
117
     *
118
     * @psalm-mutation-free
119
     *
120
     * @return static
121
     */
122 4
    public function after(string $string): self
123
    {
124 4
        $strArray = UTF8::str_split_pattern(
125 4
            $this->str,
126 4
            $string
127
        );
128
129 4
        unset($strArray[0]);
130
131 4
        return new static(
132 4
            \implode(' ', $strArray),
133 4
            $this->encoding
134
        );
135
    }
136
137
    /**
138
     * Gets the substring after the first occurrence of a separator.
139
     * If no match is found returns new empty Stringy object.
140
     *
141
     * @param string $separator
142
     *
143
     * @psalm-mutation-free
144
     *
145
     * @return static
146
     */
147 3
    public function afterFirst(string $separator): self
148
    {
149 3
        return static::create(
150 3
            $this->utf8::str_substr_after_first_separator(
151 3
                $this->str,
152 3
                $separator,
153 3
                $this->encoding
154
            )
155
        );
156
    }
157
158
    /**
159
     * Gets the substring after the first occurrence of a separator.
160
     * If no match is found returns new empty Stringy object.
161
     *
162
     * @param string $separator
163
     *
164
     * @psalm-mutation-free
165
     *
166
     * @return static
167
     */
168 2
    public function afterFirstIgnoreCase(string $separator): self
169
    {
170 2
        return static::create(
171 2
            $this->utf8::str_isubstr_after_first_separator(
172 2
                $this->str,
173 2
                $separator,
174 2
                $this->encoding
175
            )
176
        );
177
    }
178
179
    /**
180
     * Gets the substring after the last occurrence of a separator.
181
     * If no match is found returns new empty Stringy object.
182
     *
183
     * @param string $separator
184
     *
185
     * @psalm-mutation-free
186
     *
187
     * @return static
188
     */
189 2
    public function afterLast(string $separator): self
190
    {
191 2
        return static::create(
192 2
            $this->utf8::str_substr_after_last_separator(
193 2
                $this->str,
194 2
                $separator,
195 2
                $this->encoding
196
            )
197
        );
198
    }
199
200
    /**
201
     * Gets the substring after the last occurrence of a separator.
202
     * If no match is found returns new empty Stringy object.
203
     *
204
     * @param string $separator
205
     *
206
     * @psalm-mutation-free
207
     *
208
     * @return static
209
     */
210 2
    public function afterLastIgnoreCase(string $separator): self
211
    {
212 2
        return static::create(
213 2
            $this->utf8::str_isubstr_after_last_separator(
214 2
                $this->str,
215 2
                $separator,
216 2
                $this->encoding
217
            )
218
        );
219
    }
220
221
    /**
222
     * Returns a new string with $suffix appended.
223
     *
224
     * @param string ...$suffix <p>The string to append.</p>
225
     *
226
     * @psalm-mutation-free
227
     *
228
     * @return static
229
     *                <p>Object with appended $suffix.</p>
230
     *
231
     * @noinspection PhpDocSignatureInspection
232
     */
233 14 View Code Duplication
    public function append(string ...$suffix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
    {
235 14
        if (\count($suffix) <= 1) {
236
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
237 13
            $suffix = $suffix[0];
238
        } else {
239
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
240 1
            $suffix = \implode('', $suffix);
241
        }
242
243 14
        return static::create($this->str . $suffix, $this->encoding);
244
    }
245
246
    /**
247
     * Append an password (limited to chars that are good readable).
248
     *
249
     * @param int $length <p>Length of the random string.</p>
250
     *
251
     * @return static
252
     *                <p>Object with appended password.</p>
253
     */
254 2
    public function appendPassword(int $length): self
255
    {
256 2
        return $this->appendRandomString(
257 2
            $length,
258 2
            '2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!?_#'
259
        );
260
    }
261
262
    /**
263
     * Append an random string.
264
     *
265
     * @param int    $length        <p>Length of the random string.</p>
266
     * @param string $possibleChars [optional] <p>Characters string for the random selection.</p>
267
     *
268
     * @return static
269
     *                <p>Object with appended random string.</p>
270
     */
271 4
    public function appendRandomString(int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): self
272
    {
273 4
        $str = $this->utf8::get_random_string($length, $possibleChars);
274
275 4
        return $this->append($str);
276
    }
277
278
    /**
279
     * Append an unique identifier.
280
     *
281
     * @param int|string $entropyExtra [optional] <p>Extra entropy via a string or int value.</p>
282
     * @param bool       $md5          [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
283
     *
284
     * @return static
285
     *                <p>Object with appended unique identifier as md5-hash.</p>
286
     */
287 2
    public function appendUniqueIdentifier($entropyExtra = '', bool $md5 = true): self
288
    {
289 2
        return $this->append(
290 2
            $this->utf8::get_unique_string($entropyExtra, $md5)
291
        );
292
    }
293
294
    /**
295
     * Returns the character at $index, with indexes starting at 0.
296
     *
297
     * @param int $index <p>Position of the character.</p>
298
     *
299
     * @psalm-mutation-free
300
     *
301
     * @return static
302
     *                <p>The character at $index.</p>
303
     */
304 24
    public function at(int $index): self
305
    {
306 24
        return static::create($this->utf8::char_at($this->str, $index), $this->encoding);
307
    }
308
309
    /**
310
     * Decode the base64 encoded string.
311
     *
312
     * @psalm-mutation-free
313
     *
314
     * @return self
315
     */
316 2
    public function base64Decode(): self
317
    {
318 2
        return static::create(
319 2
            \base64_decode($this->str, true),
320 2
            $this->encoding
321
        );
322
    }
323
324
    /**
325
     * Encode the string to base64.
326
     *
327
     * @psalm-mutation-free
328
     *
329
     * @return self
330
     */
331 2
    public function base64Encode(): self
332
    {
333 2
        return static::create(
334 2
            \base64_encode($this->str),
335 2
            $this->encoding
336
        );
337
    }
338
339
    /**
340
     * Creates a hash from the string using the CRYPT_BLOWFISH algorithm.
341
     *
342
     * WARNING: Using this algorithm, will result in the ```$this->str```
343
     *          being truncated to a maximum length of 72 characters.
344
     *
345
     * @param array<array-key, int|string> $options [optional] <p>An array of bcrypt hasing options.</p>
346
     *
347
     * @psalm-mutation-free
348
     *
349
     * @return static
350
     */
351 3
    public function bcrypt(array $options = []): self
352
    {
353 3
        return new static(
354 3
            \password_hash(
355 3
                $this->str,
356 3
                \PASSWORD_BCRYPT,
357 3
                $options
358
            ),
359 3
            $this->encoding
360
        );
361
    }
362
363
    /**
364
     * Return part of the string occurring before a specific string.
365
     *
366
     * @param string $string <p>The delimiting string.</p>
367
     *
368
     * @psalm-mutation-free
369
     *
370
     * @return static
371
     */
372 4
    public function before(string $string): self
373
    {
374 4
        $strArray = UTF8::str_split_pattern(
375 4
            $this->str,
376 4
            $string,
377 4
            1
378
        );
379
380 4
        return new static(
381 4
            $strArray[0] ?? '',
382 4
            $this->encoding
383
        );
384
    }
385
386
    /**
387
     * Gets the substring before the first occurrence of a separator.
388
     * If no match is found returns new empty Stringy object.
389
     *
390
     * @param string $separator
391
     *
392
     * @psalm-mutation-free
393
     *
394
     * @return static
395
     */
396 2
    public function beforeFirst(string $separator): self
397
    {
398 2
        return static::create(
399 2
            $this->utf8::str_substr_before_first_separator(
400 2
                $this->str,
401 2
                $separator,
402 2
                $this->encoding
403
            )
404
        );
405
    }
406
407
    /**
408
     * Gets the substring before the first occurrence of a separator.
409
     * If no match is found returns new empty Stringy object.
410
     *
411
     * @param string $separator
412
     *
413
     * @psalm-mutation-free
414
     *
415
     * @return static
416
     */
417 2
    public function beforeFirstIgnoreCase(string $separator): self
418
    {
419 2
        return static::create(
420 2
            $this->utf8::str_isubstr_before_first_separator(
421 2
                $this->str,
422 2
                $separator,
423 2
                $this->encoding
424
            )
425
        );
426
    }
427
428
    /**
429
     * Gets the substring before the last occurrence of a separator.
430
     * If no match is found returns new empty Stringy object.
431
     *
432
     * @param string $separator
433
     *
434
     * @psalm-mutation-free
435
     *
436
     * @return static
437
     */
438 2
    public function beforeLast(string $separator): self
439
    {
440 2
        return static::create(
441 2
            $this->utf8::str_substr_before_last_separator(
442 2
                $this->str,
443 2
                $separator,
444 2
                $this->encoding
445
            )
446
        );
447
    }
448
449
    /**
450
     * Gets the substring before the last occurrence of a separator.
451
     * If no match is found returns new empty Stringy object.
452
     *
453
     * @param string $separator
454
     *
455
     * @psalm-mutation-free
456
     *
457
     * @return static
458
     */
459 2
    public function beforeLastIgnoreCase(string $separator): self
460
    {
461 2
        return static::create(
462 2
            $this->utf8::str_isubstr_before_last_separator(
463 2
                $this->str,
464 2
                $separator,
465 2
                $this->encoding
466
            )
467
        );
468
    }
469
470
    /**
471
     * Returns the substring between $start and $end, if found, or an empty
472
     * string. An optional offset may be supplied from which to begin the
473
     * search for the start string.
474
     *
475
     * @param string $start  <p>Delimiter marking the start of the substring.</p>
476
     * @param string $end    <p>Delimiter marking the end of the substring.</p>
477
     * @param int    $offset [optional] <p>Index from which to begin the search. Default: 0</p>
478
     *
479
     * @psalm-mutation-free
480
     *
481
     * @return static
482
     *                <p>Object whose $str is a substring between $start and $end.</p>
483
     */
484 48
    public function between(string $start, string $end, int $offset = null): self
485
    {
486
        /** @noinspection UnnecessaryCastingInspection */
487 48
        $str = $this->utf8::between(
488 48
            $this->str,
489 48
            $start,
490 48
            $end,
491 48
            (int) $offset,
492 48
            $this->encoding
493
        );
494
495 48
        return static::create($str, $this->encoding);
496
    }
497
498
    /**
499
     * Returns a camelCase version of the string. Trims surrounding spaces,
500
     * capitalizes letters following digits, spaces, dashes and underscores,
501
     * and removes spaces, dashes, as well as underscores.
502
     *
503
     * @psalm-mutation-free
504
     *
505
     * @return static
506
     *                <p>Object with $str in camelCase.</p>
507
     */
508 57
    public function camelize(): self
509
    {
510 57
        return static::create(
511 57
            $this->utf8::str_camelize($this->str, $this->encoding),
512 57
            $this->encoding
513
        );
514
    }
515
516
    /**
517
     * Returns the string with the first letter of each word capitalized,
518
     * except for when the word is a name which shouldn't be capitalized.
519
     *
520
     * @psalm-mutation-free
521
     *
522
     * @return static
523
     *                <p>Object with $str capitalized.</p>
524
     */
525 78
    public function capitalizePersonalName(): self
526
    {
527 78
        return static::create(
528 78
            $this->utf8::str_capitalize_name($this->str),
529 78
            $this->encoding
530
        );
531
    }
532
533
    /**
534
     * Returns an array consisting of the characters in the string.
535
     *
536
     * @psalm-mutation-free
537
     *
538
     * @return string[]
539
     *                  <p>An array of string chars.</p>
540
     */
541 14
    public function chars(): array
542
    {
543 14
        return $this->utf8::str_split($this->str);
544
    }
545
546
    /**
547
     * Splits the string into chunks of Stringy objects.
548
     *
549
     * @param int  $length                   [optional] <p>Max character length of each array element.</p>
550
     * @param bool $return_stingy_collection [optional] <p>Return a collection object.</p>
551
     *
552
     * @psalm-mutation-free
553
     *
554
     * @return CollectionStringy|static[]
555
     *                                    <p>An collection of Stringy objects.</p>
556
     *
557
     * @psalm-return CollectionStringy<int,static>|array<int,static>
558
     */
559 13
    public function chunk(int $length = 1, bool $return_stingy_collection = false)
560
    {
561 13
        if ($length < 1) {
562
            throw new \InvalidArgumentException('The chunk length must be greater than zero.');
563
        }
564
565 13
        if ($this->str === '') {
566 2
            if ($return_stingy_collection) {
567
                /**
568
                 * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
569
                 */
570 1
                return CollectionStringy::create([]);
571
            }
572
573 1
            return [];
574
        }
575
576 11
        $chunks = $this->utf8::str_split($this->str, $length);
577
        /** @noinspection AlterInForeachInspection */
578 11
        foreach ($chunks as $i => &$value) {
579 11
            $value = static::create($value, $this->encoding);
580
        }
581
582 11
        if ($return_stingy_collection) {
583
            /**
584
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
585
             */
586 6
            return CollectionStringy::create($chunks);
587
        }
588
589 5
        return $chunks;
590
    }
591
592
    /**
593
     * Trims the string and replaces consecutive whitespace characters with a
594
     * single space. This includes tabs and newline characters, as well as
595
     * multibyte whitespace such as the thin space and ideographic space.
596
     *
597
     * @psalm-mutation-free
598
     *
599
     * @return static
600
     *                <p>Object with a trimmed $str and condensed whitespace.</p>
601
     */
602 39
    public function collapseWhitespace(): self
603
    {
604 39
        return static::create(
605 39
            $this->utf8::collapse_whitespace($this->str),
606 39
            $this->encoding
607
        );
608
    }
609
610
    /**
611
     * Returns true if the string contains $needle, false otherwise. By default
612
     * the comparison is case-sensitive, but can be made insensitive by setting
613
     * $caseSensitive to false.
614
     *
615
     * @param string $needle        <p>Substring to look for.</p>
616
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
617
     *
618
     * @psalm-mutation-free
619
     *
620
     * @return bool
621
     *              <p>Whether or not $str contains $needle.</p>
622
     */
623 63
    public function contains(string $needle, bool $caseSensitive = true): bool
624
    {
625 63
        return $this->utf8::str_contains(
626 63
            $this->str,
627 63
            $needle,
628 63
            $caseSensitive
629
        );
630
    }
631
632
    /**
633
     * Returns true if the string contains all $needles, false otherwise. By
634
     * default the comparison is case-sensitive, but can be made insensitive by
635
     * setting $caseSensitive to false.
636
     *
637
     * @param string[] $needles       <p>SubStrings to look for.</p>
638
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
639
     *
640
     * @psalm-mutation-free
641
     *
642
     * @return bool
643
     *              <p>Whether or not $str contains $needle.</p>
644
     */
645 131
    public function containsAll(array $needles, bool $caseSensitive = true): bool
646
    {
647 131
        return $this->utf8::str_contains_all(
648 131
            $this->str,
649 131
            $needles,
650 131
            $caseSensitive
651
        );
652
    }
653
654
    /**
655
     * Returns true if the string contains any $needles, false otherwise. By
656
     * default the comparison is case-sensitive, but can be made insensitive by
657
     * setting $caseSensitive to false.
658
     *
659
     * @param string[] $needles       <p>SubStrings to look for.</p>
660
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
661
     *
662
     * @psalm-mutation-free
663
     *
664
     * @return bool
665
     *              <p>Whether or not $str contains $needle.</p>
666
     */
667 129
    public function containsAny(array $needles, bool $caseSensitive = true): bool
668
    {
669 129
        return $this->utf8::str_contains_any(
670 129
            $this->str,
671 129
            $needles,
672 129
            $caseSensitive
673
        );
674
    }
675
676
    /**
677
     * Returns the length of the string, implementing the countable interface.
678
     *
679
     * @psalm-mutation-free
680
     *
681
     * @return int
682
     *             <p>The number of characters in the string, given the encoding.</p>
683
     */
684 3
    public function count(): int
685
    {
686 3
        return $this->length();
687
    }
688
689
    /**
690
     * Returns the number of occurrences of $substring in the given string.
691
     * By default, the comparison is case-sensitive, but can be made insensitive
692
     * by setting $caseSensitive to false.
693
     *
694
     * @param string $substring     <p>The substring to search for.</p>
695
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
696
     *
697
     * @psalm-mutation-free
698
     *
699
     * @return int
700
     */
701 45
    public function countSubstr(string $substring, bool $caseSensitive = true): int
702
    {
703 45
        return $this->utf8::substr_count_simple(
704 45
            $this->str,
705 45
            $substring,
706 45
            $caseSensitive,
707 45
            $this->encoding
708
        );
709
    }
710
711
    /**
712
     * Calculates the crc32 polynomial of a string.
713
     *
714
     * @psalm-mutation-free
715
     *
716
     * @return int
717
     */
718 2
    public function crc32(): int
719
    {
720 2
        return \crc32($this->str);
721
    }
722
723
    /**
724
     * Creates a Stringy object and assigns both str and encoding properties
725
     * the supplied values. $str is cast to a string prior to assignment, and if
726
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
727
     * then returns the initialized object. Throws an InvalidArgumentException
728
     * if the first argument is an array or object without a __toString method.
729
     *
730
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
731
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
732
     *
733
     * @throws \InvalidArgumentException
734
     *                                   <p>if an array or object without a
735
     *                                   __toString method is passed as the first argument</p>
736
     *
737
     * @return static
738
     *                <p>A Stringy object.</p>
739
     * @psalm-pure
740
     */
741 3553
    public static function create($str = '', string $encoding = null): self
742
    {
743 3553
        return new static($str, $encoding);
744
    }
745
746
    /**
747
     * One-way string encryption (hashing).
748
     *
749
     * Hash the string using the standard Unix DES-based algorithm or an
750
     * alternative algorithm that may be available on the system.
751
     *
752
     * PS: if you need encrypt / decrypt, please use use ```static::encrypt($password)```
753
     *     and ```static::decrypt($password)```
754
     *
755
     * @param string $salt <p>A salt string to base the hashing on.</p>
756
     *
757
     * @psalm-mutation-free
758
     *
759
     * @return static
760
     */
761 3
    public function crypt(string $salt): self
762
    {
763 3
        return new static(
764 3
            \crypt(
765 3
                $this->str,
766 3
                $salt
767
            ),
768 3
            $this->encoding
769
        );
770
    }
771
772
    /**
773
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
774
     * inserted before uppercase characters (with the exception of the first
775
     * character of the string), and in place of spaces as well as underscores.
776
     *
777
     * @psalm-mutation-free
778
     *
779
     * @return static
780
     *                <p>Object with a dasherized $str</p>
781
     */
782 57
    public function dasherize(): self
783
    {
784 57
        return static::create(
785 57
            $this->utf8::str_dasherize($this->str),
786 57
            $this->encoding
787
        );
788
    }
789
790
    /**
791
     * Decrypt the string.
792
     *
793
     * @param string $password The key for decrypting
794
     *
795
     * @psalm-mutation-free
796
     *
797
     * @return static
798
     */
799 5
    public function decrypt(string $password): self
800
    {
801
        /**
802
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
803
         */
804 5
        return new static(
805 5
            Crypto::decryptWithPassword($this->str, $password),
806 3
            $this->encoding
807
        );
808
    }
809
810
    /**
811
     * Returns a lowercase and trimmed string separated by the given delimiter.
812
     * Delimiters are inserted before uppercase characters (with the exception
813
     * of the first character of the string), and in place of spaces, dashes,
814
     * and underscores. Alpha delimiters are not converted to lowercase.
815
     *
816
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
817
     *
818
     * @psalm-mutation-free
819
     *
820
     * @return static
821
     *                <p>Object with a delimited $str.</p>
822
     */
823 90
    public function delimit(string $delimiter): self
824
    {
825 90
        return static::create(
826 90
            $this->utf8::str_delimit($this->str, $delimiter),
827 90
            $this->encoding
828
        );
829
    }
830
831
    /**
832
     * Encode the given string into the given $encoding + set the internal character encoding
833
     *
834
     * @param string $new_encoding         <p>The desired character encoding.</p>
835
     * @param bool   $auto_detect_encoding [optional] <p>Auto-detect the current string-encoding</p>
836
     *
837
     * @psalm-mutation-free
838
     *
839
     * @return static
840
     */
841 2
    public function encode(string $new_encoding, bool $auto_detect_encoding = false): self
842
    {
843 2
        if ($auto_detect_encoding) {
844 1
            $str = $this->utf8::encode(
845 1
                $new_encoding,
846 1
                $this->str
847
            );
848
        } else {
849 1
            $str = $this->utf8::encode(
850 1
                $new_encoding,
851 1
                $this->str,
852 1
                false,
853 1
                $this->encoding
854
            );
855
        }
856
857 2
        return new static($str, $new_encoding);
858
    }
859
860
    /**
861
     * Encrypt the string.
862
     *
863
     * @param string $password <p>The key for encrypting</p>
864
     *
865
     * @psalm-mutation-free
866
     *
867
     * @return static
868
     */
869 4
    public function encrypt(string $password): self
870
    {
871
        /**
872
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
873
         */
874 4
        return new static(
875 4
            Crypto::encryptWithPassword($this->str, $password),
876 4
            $this->encoding
877
        );
878
    }
879
880
    /**
881
     * Returns true if the string ends with $substring, false otherwise. By
882
     * default, the comparison is case-sensitive, but can be made insensitive
883
     * by setting $caseSensitive to false.
884
     *
885
     * @param string $substring     <p>The substring to look for.</p>
886
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
887
     *
888
     * @psalm-mutation-free
889
     *
890
     * @return bool
891
     *              <p>Whether or not $str ends with $substring.</p>
892
     */
893 97
    public function endsWith(string $substring, bool $caseSensitive = true): bool
894
    {
895 97
        if ($caseSensitive) {
896 53
            return $this->utf8::str_ends_with($this->str, $substring);
897
        }
898
899 44
        return $this->utf8::str_iends_with($this->str, $substring);
900
    }
901
902
    /**
903
     * Returns true if the string ends with any of $substrings, false otherwise.
904
     * By default, the comparison is case-sensitive, but can be made insensitive
905
     * by setting $caseSensitive to false.
906
     *
907
     * @param string[] $substrings    <p>Substrings to look for.</p>
908
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
909
     *
910
     * @psalm-mutation-free
911
     *
912
     * @return bool
913
     *              <p>Whether or not $str ends with $substring.</p>
914
     */
915 33
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
916
    {
917 33
        if ($caseSensitive) {
918 21
            return $this->utf8::str_ends_with_any($this->str, $substrings);
919
        }
920
921 12
        return $this->utf8::str_iends_with_any($this->str, $substrings);
922
    }
923
924
    /**
925
     * Ensures that the string begins with $substring. If it doesn't, it's
926
     * prepended.
927
     *
928
     * @param string $substring <p>The substring to add if not present.</p>
929
     *
930
     * @psalm-mutation-free
931
     *
932
     * @return static
933
     *                <p>Object with its $str prefixed by the $substring.</p>
934
     */
935 30
    public function ensureLeft(string $substring): self
936
    {
937 30
        return static::create(
938 30
            $this->utf8::str_ensure_left($this->str, $substring),
939 30
            $this->encoding
940
        );
941
    }
942
943
    /**
944
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
945
     *
946
     * @param string $substring <p>The substring to add if not present.</p>
947
     *
948
     * @psalm-mutation-free
949
     *
950
     * @return static
951
     *                <p>Object with its $str suffixed by the $substring.</p>
952
     */
953 30
    public function ensureRight(string $substring): self
954
    {
955 30
        return static::create(
956 30
            $this->utf8::str_ensure_right($this->str, $substring),
957 30
            $this->encoding
958
        );
959
    }
960
961
    /**
962
     * Create a escape html version of the string via "htmlspecialchars()".
963
     *
964
     * @psalm-mutation-free
965
     *
966
     * @return static
967
     */
968 12
    public function escape(): self
969
    {
970 12
        return static::create(
971 12
            $this->utf8::htmlspecialchars(
972 12
                $this->str,
973 12
                \ENT_QUOTES | \ENT_SUBSTITUTE,
974 12
                $this->encoding
975
            ),
976 12
            $this->encoding
977
        );
978
    }
979
980
    /**
981
     * Split a string by a string.
982
     *
983
     * @param string $delimiter                <p>The boundary string</p>
984
     * @param int    $limit                    [optional] <p>The maximum number of elements in the exploded
985
     *                                         collection.</p>
986
     * @param bool   $return_stingy_collection [optional] <p>Return a collection object.</p>
987
     *
988
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
989
     *   element containing the rest of string.
990
     *   - If the limit parameter is negative, all components except the last -limit are returned.
991
     *   - If the limit parameter is zero, then this is treated as 1
992
     *
993
     * @psalm-mutation-free
994
     *
995
     * @return array<int,static>|CollectionStringy<int,static>
0 ignored issues
show
Documentation introduced by
The doc-type array<int,static>|CollectionStringy<int,static> could not be parsed: Expected "|" or "end of type", but got "<" at position 35. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
996
     */
997 3
    public function explode(
998
        string $delimiter,
999
        int $limit = \PHP_INT_MAX,
1000
        bool $return_stingy_collection = false
1001
    ) {
1002 3
        if ($this->str === '') {
1003
            if ($return_stingy_collection) {
1004
                /**
1005
                 * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
1006
                 */
1007
                return CollectionStringy::create([]);
1008
            }
1009
1010
            return [];
1011
        }
1012
1013 3
        $data = \explode($delimiter, $this->str, $limit);
1014 3
        if ($data === false) {
1015
            $data = [];
1016
        }
1017
1018 3
        $data = \array_map(
1019 3
            function ($str) {
1020 3
                return new static($str, $this->encoding);
1021 3
            },
1022 3
            $data
1023
        );
1024
1025 3
        if ($return_stingy_collection) {
1026
            /**
1027
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
1028
             */
1029 1
            return CollectionStringy::create($data);
1030
        }
1031
1032 2
        return $data;
1033
    }
1034
1035
    /**
1036
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
1037
     *
1038
     * @param string   $search
1039
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
1040
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
1041
     *
1042
     * @psalm-mutation-free
1043
     *
1044
     * @return static
1045
     */
1046 2
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
1047
    {
1048 2
        return static::create(
1049 2
            $this->utf8::extract_text(
1050 2
                $this->str,
1051 2
                $search,
1052 2
                $length,
1053 2
                $replacerForSkippedText,
1054 2
                $this->encoding
1055
            ),
1056 2
            $this->encoding
1057
        );
1058
    }
1059
1060
    /**
1061
     * Returns the first $n characters of the string.
1062
     *
1063
     * @param int $n <p>Number of characters to retrieve from the start.</p>
1064
     *
1065
     * @psalm-mutation-free
1066
     *
1067
     * @return static
1068
     *                <p>Object with its $str being the first $n chars.</p>
1069
     */
1070 37
    public function first(int $n): self
1071
    {
1072 37
        return static::create(
1073 37
            $this->utf8::first_char($this->str, $n, $this->encoding),
1074 37
            $this->encoding
1075
        );
1076
    }
1077
1078
    /**
1079
     * Return a formatted string via sprintf + named parameters via array syntax.
1080
     *
1081
     * <p>
1082
     * <br>
1083
     * It will use "sprintf()" so you can use e.g.:
1084
     * <br>
1085
     * <br><pre>s('There are %d monkeys in the %s')->format(5, 'tree');</pre>
1086
     * <br>
1087
     * <br><pre>s('There are %2$d monkeys in the %1$s')->format('tree', 5);</pre>
1088
     * <br>
1089
     * <br>
1090
     * But you can also use named parameter via array syntax e.g.:
1091
     * <br>
1092
     * <br><pre>s('There are %:count monkeys in the %:location')->format(['count' => 5, 'location' => 'tree');</pre>
1093
     * </p>
1094
     *
1095
     * @param mixed ...$args [optional]
1096
     *
1097
     * @psalm-mutation-free
1098
     *
1099
     * @return static
1100
     *                <p>A Stringy object produced according to the formatting string
1101
     *                format.</p>
1102
     */
1103 10
    public function format(...$args): self
1104
    {
1105
        // init
1106 10
        $str = $this->str;
1107
1108 10
        if (\strpos($this->str, '%:') !== false) {
1109 8
            $offset = null;
1110 8
            $replacement = null;
1111
            /** @noinspection AlterInForeachInspection */
1112 8
            foreach ($args as $key => &$arg) {
1113 8
                if (!\is_array($arg)) {
1114 4
                    continue;
1115
                }
1116
1117 8
                foreach ($arg as $name => $param) {
1118 8
                    $name = (string) $name;
1119
1120 8
                    if (\strpos($name, '%:') !== 0) {
1121 8
                        $nameTmp = '%:' . $name;
1122
                    } else {
1123
                        $nameTmp = $name;
1124
                    }
1125
1126 8
                    if ($offset === null) {
1127 8
                        $offset = \strpos($str, $nameTmp);
1128
                    } else {
1129 6
                        $offset = \strpos($str, $nameTmp, (int) $offset + \strlen((string) $replacement));
1130
                    }
1131 8
                    if ($offset === false) {
1132 4
                        continue;
1133
                    }
1134
1135 8
                    unset($arg[$name]);
1136
1137 8
                    $str = \substr_replace($str, $param, (int) $offset, \strlen($nameTmp));
1138
                }
1139
1140 8
                unset($args[$key]);
1141
            }
1142
        }
1143
1144 10
        $str = \str_replace('%:', '%%:', $str);
1145
1146 10
        return static::create(
1147 10
            \sprintf($str, ...$args),
1148 10
            $this->encoding
1149
        );
1150
    }
1151
1152
    /**
1153
     * Returns the encoding used by the Stringy object.
1154
     *
1155
     * @psalm-mutation-free
1156
     *
1157
     * @return string
1158
     *                <p>The current value of the $encoding property.</p>
1159
     */
1160 7
    public function getEncoding(): string
1161
    {
1162 7
        return $this->encoding;
1163
    }
1164
1165
    /**
1166
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
1167
     * interface. The ArrayIterator's constructor is passed an array of chars
1168
     * in the multibyte string. This enables the use of foreach with instances
1169
     * of Stringy\Stringy.
1170
     *
1171
     * @psalm-mutation-free
1172
     *
1173
     * @return \ArrayIterator
1174
     *                        <p>An iterator for the characters in the string.</p>
1175
     *
1176
     * @psalm-return \ArrayIterator<array-key,string>
1177
     */
1178 3
    public function getIterator(): \ArrayIterator
1179
    {
1180 3
        return new \ArrayIterator($this->chars());
1181
    }
1182
1183
    /**
1184
     * Wrap the string after an exact number of characters.
1185
     *
1186
     * @param int    $width <p>Number of characters at which to wrap.</p>
1187
     * @param string $break [optional] <p>Character used to break the string. | Default: "\n"</p>
1188
     *
1189
     * @psalm-mutation-free
1190
     *
1191
     * @return static
1192
     */
1193 2
    public function hardWrap($width, $break = "\n"): self
1194
    {
1195 2
        return $this->lineWrap($width, $break, false);
1196
    }
1197
1198
    /**
1199
     * Returns true if the string contains a lower case char, false otherwise.
1200
     *
1201
     * @psalm-mutation-free
1202
     *
1203
     * @return bool
1204
     *              <p>Whether or not the string contains a lower case character.</p>
1205
     */
1206 36
    public function hasLowerCase(): bool
1207
    {
1208 36
        return $this->utf8::has_lowercase($this->str);
1209
    }
1210
1211
    /**
1212
     * Returns true if the string contains an upper case char, false otherwise.
1213
     *
1214
     * @psalm-mutation-free
1215
     *
1216
     * @return bool
1217
     *              <p>Whether or not the string contains an upper case character.</p>
1218
     */
1219 36
    public function hasUpperCase(): bool
1220
    {
1221 36
        return $this->utf8::has_uppercase($this->str);
1222
    }
1223
1224
    /**
1225
     * Generate a hash value (message digest)
1226
     *
1227
     * @see https://php.net/manual/en/function.hash.php
1228
     *
1229
     * @param string $algorithm
1230
     *                          <p>Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4", etc..)</p>
1231
     *
1232
     * @psalm-mutation-free
1233
     *
1234
     * @return static
1235
     */
1236 8
    public function hash($algorithm): self
1237
    {
1238 8
        return static::create(\hash($algorithm, $this->str), $this->encoding);
1239
    }
1240
1241
    /**
1242
     * Decode the string from hex.
1243
     *
1244
     * @psalm-mutation-free
1245
     *
1246
     * @return static
1247
     */
1248 2
    public function hexDecode(): self
1249
    {
1250 2
        $string = \preg_replace_callback(
1251 2
            '/\\\\x([0-9A-Fa-f]+)/',
1252 2
            function (array $matched) {
1253 2
                return (string) $this->utf8::hex_to_chr($matched[1]);
1254 2
            },
1255 2
            $this->str
1256
        );
1257
1258 2
        return static::create(
1259 2
            $string,
1260 2
            $this->encoding
1261
        );
1262
    }
1263
1264
    /**
1265
     * Encode string to hex.
1266
     *
1267
     * @psalm-mutation-free
1268
     *
1269
     * @return static
1270
     */
1271 2
    public function hexEncode(): self
1272
    {
1273 2
        $string = \array_reduce(
1274 2
            $this->chars(),
1275 2
            function (string $str, string $char) {
1276 2
                return $str . $this->utf8::chr_to_hex($char);
1277 2
            },
1278 2
            ''
1279
        );
1280
1281 2
        return static::create(
1282 2
            $string,
1283 2
            $this->encoding
1284
        );
1285
    }
1286
1287
    /**
1288
     * Convert all HTML entities to their applicable characters.
1289
     *
1290
     * @param int $flags [optional] <p>
1291
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1292
     *                   which document type to use. The default is ENT_COMPAT.
1293
     *                   <table>
1294
     *                   Available <i>flags</i> constants
1295
     *                   <tr valign="top">
1296
     *                   <td>Constant Name</td>
1297
     *                   <td>Description</td>
1298
     *                   </tr>
1299
     *                   <tr valign="top">
1300
     *                   <td><b>ENT_COMPAT</b></td>
1301
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1302
     *                   </tr>
1303
     *                   <tr valign="top">
1304
     *                   <td><b>ENT_QUOTES</b></td>
1305
     *                   <td>Will convert both double and single quotes.</td>
1306
     *                   </tr>
1307
     *                   <tr valign="top">
1308
     *                   <td><b>ENT_NOQUOTES</b></td>
1309
     *                   <td>Will leave both double and single quotes unconverted.</td>
1310
     *                   </tr>
1311
     *                   <tr valign="top">
1312
     *                   <td><b>ENT_HTML401</b></td>
1313
     *                   <td>
1314
     *                   Handle code as HTML 4.01.
1315
     *                   </td>
1316
     *                   </tr>
1317
     *                   <tr valign="top">
1318
     *                   <td><b>ENT_XML1</b></td>
1319
     *                   <td>
1320
     *                   Handle code as XML 1.
1321
     *                   </td>
1322
     *                   </tr>
1323
     *                   <tr valign="top">
1324
     *                   <td><b>ENT_XHTML</b></td>
1325
     *                   <td>
1326
     *                   Handle code as XHTML.
1327
     *                   </td>
1328
     *                   </tr>
1329
     *                   <tr valign="top">
1330
     *                   <td><b>ENT_HTML5</b></td>
1331
     *                   <td>
1332
     *                   Handle code as HTML 5.
1333
     *                   </td>
1334
     *                   </tr>
1335
     *                   </table>
1336
     *                   </p>
1337
     *
1338
     * @psalm-mutation-free
1339
     *
1340
     * @return static
1341
     *                <p>Object with the resulting $str after being html decoded.</p>
1342
     */
1343 15 View Code Duplication
    public function htmlDecode(int $flags = \ENT_COMPAT): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1344
    {
1345 15
        return static::create(
1346 15
            $this->utf8::html_entity_decode(
1347 15
                $this->str,
1348 15
                $flags,
1349 15
                $this->encoding
1350
            ),
1351 15
            $this->encoding
1352
        );
1353
    }
1354
1355
    /**
1356
     * Convert all applicable characters to HTML entities.
1357
     *
1358
     * @param int $flags [optional] <p>
1359
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1360
     *                   which document type to use. The default is ENT_COMPAT.
1361
     *                   <table>
1362
     *                   Available <i>flags</i> constants
1363
     *                   <tr valign="top">
1364
     *                   <td>Constant Name</td>
1365
     *                   <td>Description</td>
1366
     *                   </tr>
1367
     *                   <tr valign="top">
1368
     *                   <td><b>ENT_COMPAT</b></td>
1369
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1370
     *                   </tr>
1371
     *                   <tr valign="top">
1372
     *                   <td><b>ENT_QUOTES</b></td>
1373
     *                   <td>Will convert both double and single quotes.</td>
1374
     *                   </tr>
1375
     *                   <tr valign="top">
1376
     *                   <td><b>ENT_NOQUOTES</b></td>
1377
     *                   <td>Will leave both double and single quotes unconverted.</td>
1378
     *                   </tr>
1379
     *                   <tr valign="top">
1380
     *                   <td><b>ENT_HTML401</b></td>
1381
     *                   <td>
1382
     *                   Handle code as HTML 4.01.
1383
     *                   </td>
1384
     *                   </tr>
1385
     *                   <tr valign="top">
1386
     *                   <td><b>ENT_XML1</b></td>
1387
     *                   <td>
1388
     *                   Handle code as XML 1.
1389
     *                   </td>
1390
     *                   </tr>
1391
     *                   <tr valign="top">
1392
     *                   <td><b>ENT_XHTML</b></td>
1393
     *                   <td>
1394
     *                   Handle code as XHTML.
1395
     *                   </td>
1396
     *                   </tr>
1397
     *                   <tr valign="top">
1398
     *                   <td><b>ENT_HTML5</b></td>
1399
     *                   <td>
1400
     *                   Handle code as HTML 5.
1401
     *                   </td>
1402
     *                   </tr>
1403
     *                   </table>
1404
     *                   </p>
1405
     *
1406
     * @psalm-mutation-free
1407
     *
1408
     * @return static
1409
     *                <p>Object with the resulting $str after being html encoded.</p>
1410
     */
1411 15 View Code Duplication
    public function htmlEncode(int $flags = \ENT_COMPAT): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1412
    {
1413 15
        return static::create(
1414 15
            $this->utf8::htmlentities(
1415 15
                $this->str,
1416 15
                $flags,
1417 15
                $this->encoding
1418
            ),
1419 15
            $this->encoding
1420
        );
1421
    }
1422
1423
    /**
1424
     * Capitalizes the first word of the string, replaces underscores with
1425
     * spaces, and strips '_id'.
1426
     *
1427
     * @psalm-mutation-free
1428
     *
1429
     * @return static
1430
     *                <p>Object with a humanized $str.</p>
1431
     */
1432 9
    public function humanize(): self
1433
    {
1434 9
        return static::create(
1435 9
            $this->utf8::str_humanize($this->str),
1436 9
            $this->encoding
1437
        );
1438
    }
1439
1440
    /**
1441
     * Determine if the current string exists in another string. By
1442
     * default, the comparison is case-sensitive, but can be made insensitive
1443
     * by setting $caseSensitive to false.
1444
     *
1445
     * @param string $str           <p>The string to compare against.</p>
1446
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1447
     *
1448
     * @psalm-mutation-free
1449
     *
1450
     * @return bool
1451
     */
1452 3
    public function in(string $str, bool $caseSensitive = true): bool
1453
    {
1454 3
        if ($caseSensitive) {
1455 2
            return \strpos($str, $this->str) !== false;
1456
        }
1457
1458 1
        return \stripos($str, $this->str) !== false;
1459
    }
1460
1461
    /**
1462
     * Returns the index of the first occurrence of $needle in the string,
1463
     * and false if not found. Accepts an optional offset from which to begin
1464
     * the search.
1465
     *
1466
     * @param string $needle <p>Substring to look for.</p>
1467
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1468
     *
1469
     * @psalm-mutation-free
1470
     *
1471
     * @return false|int
1472
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1473
     */
1474 31
    public function indexOf(string $needle, int $offset = 0)
1475
    {
1476 31
        return $this->utf8::strpos(
1477 31
            $this->str,
1478 31
            $needle,
1479 31
            $offset,
1480 31
            $this->encoding
1481
        );
1482
    }
1483
1484
    /**
1485
     * Returns the index of the first occurrence of $needle in the string,
1486
     * and false if not found. Accepts an optional offset from which to begin
1487
     * the search.
1488
     *
1489
     * @param string $needle <p>Substring to look for.</p>
1490
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1491
     *
1492
     * @psalm-mutation-free
1493
     *
1494
     * @return false|int
1495
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1496
     */
1497 20
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
1498
    {
1499 20
        return $this->utf8::stripos(
1500 20
            $this->str,
1501 20
            $needle,
1502 20
            $offset,
1503 20
            $this->encoding
1504
        );
1505
    }
1506
1507
    /**
1508
     * Returns the index of the last occurrence of $needle in the string,
1509
     * and false if not found. Accepts an optional offset from which to begin
1510
     * the search. Offsets may be negative to count from the last character
1511
     * in the string.
1512
     *
1513
     * @param string $needle <p>Substring to look for.</p>
1514
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1515
     *
1516
     * @psalm-mutation-free
1517
     *
1518
     * @return false|int
1519
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1520
     */
1521 31
    public function indexOfLast(string $needle, int $offset = 0)
1522
    {
1523 31
        return $this->utf8::strrpos(
1524 31
            $this->str,
1525 31
            $needle,
1526 31
            $offset,
1527 31
            $this->encoding
1528
        );
1529
    }
1530
1531
    /**
1532
     * Returns the index of the last occurrence of $needle in the string,
1533
     * and false if not found. Accepts an optional offset from which to begin
1534
     * the search. Offsets may be negative to count from the last character
1535
     * in the string.
1536
     *
1537
     * @param string $needle <p>Substring to look for.</p>
1538
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1539
     *
1540
     * @psalm-mutation-free
1541
     *
1542
     * @return false|int
1543
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1544
     */
1545 20
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
1546
    {
1547 20
        return $this->utf8::strripos(
1548 20
            $this->str,
1549 20
            $needle,
1550 20
            $offset,
1551 20
            $this->encoding
1552
        );
1553
    }
1554
1555
    /**
1556
     * Inserts $substring into the string at the $index provided.
1557
     *
1558
     * @param string $substring <p>String to be inserted.</p>
1559
     * @param int    $index     <p>The index at which to insert the substring.</p>
1560
     *
1561
     * @psalm-mutation-free
1562
     *
1563
     * @return static
1564
     *                <p>Object with the resulting $str after the insertion.</p>
1565
     */
1566 24
    public function insert(string $substring, int $index): self
1567
    {
1568 24
        return static::create(
1569 24
            $this->utf8::str_insert(
1570 24
                $this->str,
1571 24
                $substring,
1572 24
                $index,
1573 24
                $this->encoding
1574
            ),
1575 24
            $this->encoding
1576
        );
1577
    }
1578
1579
    /**
1580
     * Returns true if the string contains the $pattern, otherwise false.
1581
     *
1582
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
1583
     * expression wildcards.
1584
     *
1585
     * @credit Originally from Laravel, thanks Taylor.
1586
     *
1587
     * @param string $pattern <p>The string or pattern to match against.</p>
1588
     *
1589
     * @psalm-mutation-free
1590
     *
1591
     * @return bool
1592
     *              <p>Whether or not we match the provided pattern.</p>
1593
     */
1594 26
    public function is(string $pattern): bool
1595
    {
1596 26
        if ($this->toString() === $pattern) {
1597 2
            return true;
1598
        }
1599
1600 24
        $quotedPattern = \preg_quote($pattern, '/');
1601 24
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
1602
1603 24
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
1604
    }
1605
1606
    /**
1607
     * Returns true if the string contains only alphabetic chars, false otherwise.
1608
     *
1609
     * @psalm-mutation-free
1610
     *
1611
     * @return bool
1612
     *              <p>Whether or not $str contains only alphabetic chars.</p>
1613
     */
1614 30
    public function isAlpha(): bool
1615
    {
1616 30
        return $this->utf8::is_alpha($this->str);
1617
    }
1618
1619
    /**
1620
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
1621
     *
1622
     * @psalm-mutation-free
1623
     *
1624
     * @return bool
1625
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
1626
     */
1627 39
    public function isAlphanumeric(): bool
1628
    {
1629 39
        return $this->utf8::is_alphanumeric($this->str);
1630
    }
1631
1632
    /**
1633
     * Returns true if the string is base64 encoded, false otherwise.
1634
     *
1635
     * @param bool $emptyStringIsValid
1636
     *
1637
     * @psalm-mutation-free
1638
     *
1639
     * @return bool
1640
     *              <p>Whether or not $str is base64 encoded.</p>
1641
     */
1642 21
    public function isBase64($emptyStringIsValid = true): bool
1643
    {
1644 21
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
1645
    }
1646
1647
    /**
1648
     * Returns true if the string contains only whitespace chars, false otherwise.
1649
     *
1650
     * @psalm-mutation-free
1651
     *
1652
     * @return bool
1653
     *              <p>Whether or not $str contains only whitespace characters.</p>
1654
     */
1655 45
    public function isBlank(): bool
1656
    {
1657 45
        return $this->utf8::is_blank($this->str);
1658
    }
1659
1660
    /**
1661
     * Returns true if the string contains a valid E-Mail address, false otherwise.
1662
     *
1663
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
1664
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
1665
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
1666
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
1667
     *
1668
     * @psalm-mutation-free
1669
     *
1670
     * @return bool
1671
     *              <p>Whether or not $str contains a valid E-Mail address.</p>
1672
     */
1673 2
    public function isEmail(
1674
        bool $useExampleDomainCheck = false,
1675
        bool $useTypoInDomainCheck = false,
1676
        bool $useTemporaryDomainCheck = false,
1677
        bool $useDnsCheck = false
1678
    ): bool {
1679
        /**
1680
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the email-check class
1681
         */
1682 2
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
1683
    }
1684
1685
    /**
1686
     * Determine whether the string is considered to be empty.
1687
     *
1688
     * A variable is considered empty if it does not exist or if its value equals FALSE.
1689
     *
1690
     * @psalm-mutation-free
1691
     *
1692
     * @return bool
1693
     *              <p>Whether or not $str is empty().</p>
1694
     */
1695 10
    public function isEmpty(): bool
1696
    {
1697 10
        return $this->utf8::is_empty($this->str);
1698
    }
1699
1700
    /**
1701
     * Determine whether the string is equals to $str.
1702
     * Alias for isEqualsCaseSensitive()
1703
     *
1704
     * @param string|Stringy ...$str
1705
     *
1706
     * @psalm-mutation-free
1707
     *
1708
     * @return bool
1709
     */
1710 13
    public function isEquals(...$str): bool
1711
    {
1712 13
        return $this->isEqualsCaseSensitive(...$str);
1713
    }
1714
1715
    /**
1716
     * Determine whether the string is equals to $str.
1717
     *
1718
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
1719
     *
1720
     * @psalm-mutation-free
1721
     *
1722
     * @return bool
1723
     *              <p>Whether or not $str is equals.</p>
1724
     */
1725 3
    public function isEqualsCaseInsensitive(...$str): bool
1726
    {
1727 3
        $strUpper = $this->toUpperCase()->str;
1728
1729 3 View Code Duplication
        foreach ($str as $strTmp) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1730
            /**
1731
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
1732
             */
1733 3
            if ($strTmp instanceof self) {
1734
                if ($strUpper !== $strTmp->toUpperCase()) {
1735
                    return false;
1736
                }
1737 3
            } elseif (\is_scalar($strTmp)) {
1738 3
                if ($strUpper !== $this->utf8::strtoupper((string) $strTmp, $this->encoding)) {
1739 3
                    return false;
1740
                }
1741
            } else {
1742 3
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
1743
            }
1744
        }
1745
1746 3
        return true;
1747
    }
1748
1749
    /**
1750
     * Determine whether the string is equals to $str.
1751
     *
1752
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
1753
     *
1754
     * @psalm-mutation-free
1755
     *
1756
     * @return bool
1757
     *              <p>Whether or not $str is equals.</p>
1758
     */
1759 14
    public function isEqualsCaseSensitive(...$str): bool
1760
    {
1761 14 View Code Duplication
        foreach ($str as $strTmp) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1762
            /**
1763
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
1764
             */
1765 14
            if ($strTmp instanceof self) {
1766 2
                if ($this->str !== $strTmp->str) {
1767 2
                    return false;
1768
                }
1769 12
            } elseif (\is_scalar($strTmp)) {
1770 12
                if ($this->str !== (string) $strTmp) {
1771 12
                    return false;
1772
                }
1773
            } else {
1774 3
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
1775
            }
1776
        }
1777
1778 3
        return true;
1779
    }
1780
1781
    /**
1782
     * Returns true if the string contains only hexadecimal chars, false otherwise.
1783
     *
1784
     * @psalm-mutation-free
1785
     *
1786
     * @return bool
1787
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
1788
     */
1789 39
    public function isHexadecimal(): bool
1790
    {
1791 39
        return $this->utf8::is_hexadecimal($this->str);
1792
    }
1793
1794
    /**
1795
     * Returns true if the string contains HTML-Tags, false otherwise.
1796
     *
1797
     * @psalm-mutation-free
1798
     *
1799
     * @return bool
1800
     *              <p>Whether or not $str contains HTML-Tags.</p>
1801
     */
1802 2
    public function isHtml(): bool
1803
    {
1804 2
        return $this->utf8::is_html($this->str);
1805
    }
1806
1807
    /**
1808
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
1809
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
1810
     * in that an empty string is not considered valid JSON.
1811
     *
1812
     * @param bool $onlyArrayOrObjectResultsAreValid
1813
     *
1814
     * @psalm-mutation-free
1815
     *
1816
     * @return bool
1817
     *              <p>Whether or not $str is JSON.</p>
1818
     */
1819 60
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
1820
    {
1821
        /**
1822
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff?
1823
         */
1824 60
        return $this->utf8::is_json(
1825 60
            $this->str,
1826 60
            $onlyArrayOrObjectResultsAreValid
1827
        );
1828
    }
1829
1830
    /**
1831
     * Returns true if the string contains only lower case chars, false otherwise.
1832
     *
1833
     * @psalm-mutation-free
1834
     *
1835
     * @return bool
1836
     *              <p>Whether or not $str contains only lower case characters.</p>
1837
     */
1838 24
    public function isLowerCase(): bool
1839
    {
1840 24
        return $this->utf8::is_lowercase($this->str);
1841
    }
1842
1843
    /**
1844
     * Determine whether the string is considered to be NOT empty.
1845
     *
1846
     * A variable is considered NOT empty if it does exist or if its value equals TRUE.
1847
     *
1848
     * @psalm-mutation-free
1849
     *
1850
     * @return bool
1851
     *              <p>Whether or not $str is empty().</p>
1852
     */
1853 10
    public function isNotEmpty(): bool
1854
    {
1855 10
        return !$this->utf8::is_empty($this->str);
1856
    }
1857
1858
    /**
1859
     * Determine if the string is composed of numeric characters.
1860
     *
1861
     * @psalm-mutation-free
1862
     *
1863
     * @return bool
1864
     */
1865 4
    public function isNumeric(): bool
1866
    {
1867 4
        return \is_numeric($this->str);
1868
    }
1869
1870
    /**
1871
     * Determine if the string is composed of printable (non-invisible) characters.
1872
     *
1873
     * @psalm-mutation-free
1874
     *
1875
     * @return bool
1876
     */
1877 3
    public function isPrintable(): bool
1878
    {
1879 3
        return $this->utf8::is_printable($this->str);
1880
    }
1881
1882
    /**
1883
     * Determine if the string is composed of punctuation characters.
1884
     *
1885
     * @psalm-mutation-free
1886
     *
1887
     * @return bool
1888
     */
1889 3
    public function isPunctuation(): bool
1890
    {
1891 3
        return $this->utf8::is_punctuation($this->str);
1892
    }
1893
1894
    /**
1895
     * Returns true if the string is serialized, false otherwise.
1896
     *
1897
     * @psalm-mutation-free
1898
     *
1899
     * @return bool
1900
     *              <p>Whether or not $str is serialized.</p>
1901
     */
1902 21
    public function isSerialized(): bool
1903
    {
1904 21
        return $this->utf8::is_serialized($this->str);
1905
    }
1906
1907
    /**
1908
     * Check if two strings are similar.
1909
     *
1910
     * @param string $str                     <p>The string to compare against.</p>
1911
     * @param float  $minPercentForSimilarity [optional] <p>The percentage of needed similarity. | Default: 80%</p>
1912
     *
1913
     * @psalm-mutation-free
1914
     *
1915
     * @return bool
1916
     */
1917 2
    public function isSimilar(string $str, float $minPercentForSimilarity = 80.0): bool
1918
    {
1919 2
        return $this->similarity($str) >= $minPercentForSimilarity;
1920
    }
1921
1922
    /**
1923
     * Returns true if the string contains only lower case chars, false
1924
     * otherwise.
1925
     *
1926
     * @psalm-mutation-free
1927
     *
1928
     * @return bool
1929
     *              <p>Whether or not $str contains only lower case characters.</p>
1930
     */
1931 24
    public function isUpperCase(): bool
1932
    {
1933 24
        return $this->utf8::is_uppercase($this->str);
1934
    }
1935
1936
    /**
1937
     * Returns true if the string contains only whitespace chars, false otherwise.
1938
     *
1939
     * @psalm-mutation-free
1940
     *
1941
     * @return bool
1942
     *              <p>Whether or not $str contains only whitespace characters.</p>
1943
     */
1944 30
    public function isWhitespace(): bool
1945
    {
1946 30
        return $this->isBlank();
1947
    }
1948
1949
    /**
1950
     * Returns value which can be serialized by json_encode().
1951
     *
1952
     * @noinspection ReturnTypeCanBeDeclaredInspection
1953
     *
1954
     * @psalm-mutation-free
1955
     *
1956
     * @return string The current value of the $str property
1957
     */
1958 2
    public function jsonSerialize()
1959
    {
1960 2
        return (string) $this;
1961
    }
1962
1963
    /**
1964
     * Convert the string to kebab-case.
1965
     *
1966
     * @psalm-mutation-free
1967
     *
1968
     * @return static
1969
     */
1970 3 View Code Duplication
    public function kebabCase(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1971
    {
1972 3
        $words = \array_map(
1973 3
            function ($word) {
1974 3
                return $this->utf8::strtolower($word, $this->encoding);
1975 3
            },
1976 3
            $this->words('', true)
1977
        );
1978
1979 3
        return new static(\implode('-', $words), $this->encoding);
1980
    }
1981
1982
    /**
1983
     * Returns the last $n characters of the string.
1984
     *
1985
     * @param int $n <p>Number of characters to retrieve from the end.</p>
1986
     *
1987
     * @psalm-mutation-free
1988
     *
1989
     * @return static
1990
     *                <p>Object with its $str being the last $n chars.</p>
1991
     */
1992 36
    public function last(int $n): self
1993
    {
1994 36
        return static::create(
1995 36
            $this->utf8::str_last_char(
1996 36
                $this->str,
1997 36
                $n,
1998 36
                $this->encoding
1999
            ),
2000 36
            $this->encoding
2001
        );
2002
    }
2003
2004
    /**
2005
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2006
     * If no match is found returns new empty Stringy object.
2007
     *
2008
     * @param string $needle       <p>The string to look for.</p>
2009
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2010
     *
2011
     * @psalm-mutation-free
2012
     *
2013
     * @return static
2014
     */
2015 4 View Code Duplication
    public function lastSubstringOf(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2016
    {
2017 4
        return static::create(
2018 4
            $this->utf8::str_substr_last(
2019 4
                $this->str,
2020 4
                $needle,
2021 4
                $beforeNeedle,
2022 4
                $this->encoding
2023
            ),
2024 4
            $this->encoding
2025
        );
2026
    }
2027
2028
    /**
2029
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2030
     * If no match is found returns new empty Stringy object.
2031
     *
2032
     * @param string $needle       <p>The string to look for.</p>
2033
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2034
     *
2035
     * @psalm-mutation-free
2036
     *
2037
     * @return static
2038
     */
2039 2 View Code Duplication
    public function lastSubstringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2040
    {
2041 2
        return static::create(
2042 2
            $this->utf8::str_isubstr_last(
2043 2
                $this->str,
2044 2
                $needle,
2045 2
                $beforeNeedle,
2046 2
                $this->encoding
2047
            ),
2048 2
            $this->encoding
2049
        );
2050
    }
2051
2052
    /**
2053
     * Returns the length of the string.
2054
     *
2055
     * @psalm-mutation-free
2056
     *
2057
     * @return int
2058
     *             <p>The number of characters in $str given the encoding.</p>
2059
     */
2060 17
    public function length(): int
2061
    {
2062 17
        return (int) $this->utf8::strlen($this->str, $this->encoding);
2063
    }
2064
2065
    /**
2066
     * Line-Wrap the string after $limit, but also after the next word.
2067
     *
2068
     * @param int         $limit           [optional] <p>The column width.</p>
2069
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2070
     * @param bool        $add_final_break [optional] <p>
2071
     *                                     If this flag is true, then the method will add a $break at the end
2072
     *                                     of the result string.
2073
     *                                     </p>
2074
     * @param string|null $delimiter       [optional] <p>
2075
     *                                     You can change the default behavior, where we split the string by newline.
2076
     *                                     </p>
2077
     *
2078
     * @psalm-mutation-free
2079
     *
2080
     * @return static
2081
     */
2082 3 View Code Duplication
    public function lineWrap(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2083
        int $limit,
2084
        string $break = "\n",
2085
        bool $add_final_break = true,
2086
        string $delimiter = null
2087
    ): self {
2088 3
        return static::create(
2089 3
            $this->utf8::wordwrap_per_line(
2090 3
                $this->str,
2091 3
                $limit,
2092 3
                $break,
2093 3
                true,
2094 3
                $add_final_break,
2095 3
                $delimiter
2096
            ),
2097 3
            $this->encoding
2098
        );
2099
    }
2100
2101
    /**
2102
     * Line-Wrap the string after $limit, but also after the next word.
2103
     *
2104
     * @param int         $limit           [optional] <p>The column width.</p>
2105
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2106
     * @param bool        $add_final_break [optional] <p>
2107
     *                                     If this flag is true, then the method will add a $break at the end
2108
     *                                     of the result string.
2109
     *                                     </p>
2110
     * @param string|null $delimiter       [optional] <p>
2111
     *                                     You can change the default behavior, where we split the string by newline.
2112
     *                                     </p>
2113
     *
2114
     * @psalm-mutation-free
2115
     *
2116
     * @return static
2117
     */
2118 4 View Code Duplication
    public function lineWrapAfterWord(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2119
        int $limit,
2120
        string $break = "\n",
2121
        bool $add_final_break = true,
2122
        string $delimiter = null
2123
    ): self {
2124 4
        return static::create(
2125 4
            $this->utf8::wordwrap_per_line(
2126 4
                $this->str,
2127 4
                $limit,
2128 4
                $break,
2129 4
                false,
2130 4
                $add_final_break,
2131 4
                $delimiter
2132
            ),
2133 4
            $this->encoding
2134
        );
2135
    }
2136
2137
    /**
2138
     * Splits on newlines and carriage returns, returning an array of Stringy
2139
     * objects corresponding to the lines in the string.
2140
     *
2141
     * @param bool $return_stingy_collection [optional] <p>Return a collection object.</p>
2142
     *
2143
     * @psalm-mutation-free
2144
     *
2145
     * @return CollectionStringy|static[]
2146
     *                                    <p>An collection of Stringy objects.</p>
2147
     *
2148
     * @psalm-return CollectionStringy<int,static>|array<int,static>
2149
     */
2150 51
    public function lines(bool $return_stingy_collection = false)
2151
    {
2152 51
        if ($this->str === '') {
2153 3
            if ($return_stingy_collection) {
2154
                /**
2155
                 * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
2156
                 */
2157 3
                return CollectionStringy::create([static::create('')]);
2158
            }
2159
2160
            return [static::create('')];
2161
        }
2162
2163 48
        $array = $this->utf8::str_to_lines($this->str);
2164
        /** @noinspection AlterInForeachInspection */
2165 48
        foreach ($array as $i => &$value) {
2166 48
            $value = static::create($value, $this->encoding);
2167
        }
2168
2169
        /** @noinspection PhpSillyAssignmentInspection */
2170
        /** @var static[] $array */
2171 48
        $array = $array;
0 ignored issues
show
Bug introduced by
Why assign $array to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
2172
2173 48
        if ($return_stingy_collection) {
2174
            /**
2175
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
2176
             */
2177 48
            return CollectionStringy::create($array);
2178
        }
2179
2180
        return $array;
2181
    }
2182
2183
    /**
2184
     * Returns the longest common prefix between the string and $otherStr.
2185
     *
2186
     * @param string $otherStr <p>Second string for comparison.</p>
2187
     *
2188
     * @psalm-mutation-free
2189
     *
2190
     * @return static
2191
     *                <p>Object with its $str being the longest common prefix.</p>
2192
     */
2193 30
    public function longestCommonPrefix(string $otherStr): self
2194
    {
2195 30
        return static::create(
2196 30
            $this->utf8::str_longest_common_prefix(
2197 30
                $this->str,
2198 30
                $otherStr,
2199 30
                $this->encoding
2200
            ),
2201 30
            $this->encoding
2202
        );
2203
    }
2204
2205
    /**
2206
     * Returns the longest common substring between the string and $otherStr.
2207
     * In the case of ties, it returns that which occurs first.
2208
     *
2209
     * @param string $otherStr <p>Second string for comparison.</p>
2210
     *
2211
     * @psalm-mutation-free
2212
     *
2213
     * @return static
2214
     *                <p>Object with its $str being the longest common substring.</p>
2215
     */
2216 30
    public function longestCommonSubstring(string $otherStr): self
2217
    {
2218 30
        return static::create(
2219 30
            $this->utf8::str_longest_common_substring(
2220 30
                $this->str,
2221 30
                $otherStr,
2222 30
                $this->encoding
2223
            ),
2224 30
            $this->encoding
2225
        );
2226
    }
2227
2228
    /**
2229
     * Returns the longest common suffix between the string and $otherStr.
2230
     *
2231
     * @param string $otherStr <p>Second string for comparison.</p>
2232
     *
2233
     * @psalm-mutation-free
2234
     *
2235
     * @return static
2236
     *                <p>Object with its $str being the longest common suffix.</p>
2237
     */
2238 30
    public function longestCommonSuffix(string $otherStr): self
2239
    {
2240 30
        return static::create(
2241 30
            $this->utf8::str_longest_common_suffix(
2242 30
                $this->str,
2243 30
                $otherStr,
2244 30
                $this->encoding
2245
            ),
2246 30
            $this->encoding
2247
        );
2248
    }
2249
2250
    /**
2251
     * Converts the first character of the string to lower case.
2252
     *
2253
     * @psalm-mutation-free
2254
     *
2255
     * @return static
2256
     *                <p>Object with the first character of $str being lower case.</p>
2257
     */
2258 15
    public function lowerCaseFirst(): self
2259
    {
2260 15
        return static::create(
2261 15
            $this->utf8::lcfirst($this->str, $this->encoding),
2262 15
            $this->encoding
2263
        );
2264
    }
2265
2266
    /**
2267
     * Determine if the string matches another string regardless of case.
2268
     * Alias for isEqualsCaseInsensitive()
2269
     *
2270
     * @psalm-mutation-free
2271
     *
2272
     * @param string|Stringy ...$str
2273
     *                               <p>The string to compare against.</p>
2274
     *
2275
     * @psalm-mutation-free
2276
     *
2277
     * @return bool
2278
     */
2279 3
    public function matchCaseInsensitive(...$str): bool
2280
    {
2281 3
        return $this->isEqualsCaseInsensitive(...$str);
2282
    }
2283
2284
    /**
2285
     * Determine if the string matches another string.
2286
     * Alias for isEqualsCaseSensitive()
2287
     *
2288
     * @psalm-mutation-free
2289
     *
2290
     * @param string|Stringy ...$str
2291
     *                               <p>The string to compare against.</p>
2292
     *
2293
     * @psalm-mutation-free
2294
     *
2295
     * @return bool
2296
     */
2297 7
    public function matchCaseSensitive(...$str): bool
2298
    {
2299 7
        return $this->isEqualsCaseSensitive(...$str);
2300
    }
2301
2302
    /**
2303
     * Create a md5 hash from the current string.
2304
     *
2305
     * @psalm-mutation-free
2306
     *
2307
     * @return static
2308
     */
2309 2
    public function md5(): self
2310
    {
2311 2
        return static::create($this->hash('md5'), $this->encoding);
2312
    }
2313
2314
    /**
2315
     * Get every nth character of the string.
2316
     *
2317
     * @param int $step   <p>The number of characters to step.</p>
2318
     * @param int $offset [optional] <p>The string offset to start at.</p>
2319
     *
2320
     * @psalm-mutation-free
2321
     *
2322
     * @return static
2323
     */
2324 4
    public function nth(int $step, int $offset = 0): self
2325
    {
2326 4
        $length = $step - 1;
2327 4
        $substring = $this->substr($offset)->toString();
2328
2329 4
        if ($substring === '') {
2330
            return new static('', $this->encoding);
2331
        }
2332
2333 4
        \preg_match_all(
2334 4
            "/(?:^|(?:.|\p{L}|\w){" . $length . "})(.|\p{L}|\w)/u",
2335 4
            $substring,
2336 4
            $matches
2337
        );
2338
2339 4
        return new static(\implode('', $matches[1] ?? []), $this->encoding);
2340
    }
2341
2342
    /**
2343
     * Returns whether or not a character exists at an index. Offsets may be
2344
     * negative to count from the last character in the string. Implements
2345
     * part of the ArrayAccess interface.
2346
     *
2347
     * @param int $offset <p>The index to check.</p>
2348
     *
2349
     * @psalm-mutation-free
2350
     *
2351
     * @return bool
2352
     *              <p>Whether or not the index exists.</p>
2353
     */
2354 18
    public function offsetExists($offset): bool
2355
    {
2356 18
        return $this->utf8::str_offset_exists(
2357 18
            $this->str,
2358 18
            $offset,
2359 18
            $this->encoding
2360
        );
2361
    }
2362
2363
    /**
2364
     * Returns the character at the given index. Offsets may be negative to
2365
     * count from the last character in the string. Implements part of the
2366
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
2367
     * does not exist.
2368
     *
2369
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
2370
     *
2371
     * @throws \OutOfBoundsException
2372
     *                               <p>If the positive or negative offset does not exist.</p>
2373
     *
2374
     * @return string
2375
     *                <p>The character at the specified index.</p>
2376
     *
2377
     * @psalm-mutation-free
2378
     */
2379 6
    public function offsetGet($offset): string
2380
    {
2381 6
        return $this->utf8::str_offset_get($this->str, $offset, $this->encoding);
2382
    }
2383
2384
    /**
2385
     * Implements part of the ArrayAccess interface, but throws an exception
2386
     * when called. This maintains the immutability of Stringy objects.
2387
     *
2388
     * @param int   $offset <p>The index of the character.</p>
2389
     * @param mixed $value  <p>Value to set.</p>
2390
     *
2391
     * @throws \Exception
2392
     *                    <p>When called.</p>
2393
     *
2394
     * @return void
2395
     */
2396 3
    public function offsetSet($offset, $value)
2397
    {
2398
        // Stringy is immutable, cannot directly set char
2399
        /** @noinspection ThrowRawExceptionInspection */
2400 3
        throw new \Exception('Stringy object is immutable, cannot modify char');
2401
    }
2402
2403
    /**
2404
     * Implements part of the ArrayAccess interface, but throws an exception
2405
     * when called. This maintains the immutability of Stringy objects.
2406
     *
2407
     * @param int $offset <p>The index of the character.</p>
2408
     *
2409
     * @throws \Exception
2410
     *                    <p>When called.</p>
2411
     *
2412
     * @return void
2413
     */
2414 3
    public function offsetUnset($offset)
2415
    {
2416
        // Don't allow directly modifying the string
2417
        /** @noinspection ThrowRawExceptionInspection */
2418 3
        throw new \Exception('Stringy object is immutable, cannot unset char');
2419
    }
2420
2421
    /**
2422
     * Pads the string to a given length with $padStr. If length is less than
2423
     * or equal to the length of the string, no padding takes places. The
2424
     * default string used for padding is a space, and the default type (one of
2425
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
2426
     * if $padType isn't one of those 3 values.
2427
     *
2428
     * @param int    $length  <p>Desired string length after padding.</p>
2429
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2430
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
2431
     *
2432
     * @throws \InvalidArgumentException
2433
     *                                   <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
2434
     *
2435
     * @return static
2436
     *                <p>Object with a padded $str.</p>
2437
     *
2438
     * @psalm-mutation-free
2439
     */
2440 39
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
2441
    {
2442 39
        return static::create(
2443 39
            $this->utf8::str_pad(
2444 39
                $this->str,
2445 39
                $length,
2446 39
                $padStr,
2447 39
                $padType,
2448 39
                $this->encoding
2449
            )
2450
        );
2451
    }
2452
2453
    /**
2454
     * Returns a new string of a given length such that both sides of the
2455
     * string are padded. Alias for pad() with a $padType of 'both'.
2456
     *
2457
     * @param int    $length <p>Desired string length after padding.</p>
2458
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2459
     *
2460
     * @psalm-mutation-free
2461
     *
2462
     * @return static
2463
     *                <p>String with padding applied.</p>
2464
     */
2465 33
    public function padBoth(int $length, string $padStr = ' '): self
2466
    {
2467 33
        return static::create(
2468 33
            $this->utf8::str_pad_both(
2469 33
                $this->str,
2470 33
                $length,
2471 33
                $padStr,
2472 33
                $this->encoding
2473
            )
2474
        );
2475
    }
2476
2477
    /**
2478
     * Returns a new string of a given length such that the beginning of the
2479
     * string is padded. Alias for pad() with a $padType of 'left'.
2480
     *
2481
     * @param int    $length <p>Desired string length after padding.</p>
2482
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2483
     *
2484
     * @psalm-mutation-free
2485
     *
2486
     * @return static
2487
     *                <p>String with left padding.</p>
2488
     */
2489 21
    public function padLeft(int $length, string $padStr = ' '): self
2490
    {
2491 21
        return static::create(
2492 21
            $this->utf8::str_pad_left(
2493 21
                $this->str,
2494 21
                $length,
2495 21
                $padStr,
2496 21
                $this->encoding
2497
            )
2498
        );
2499
    }
2500
2501
    /**
2502
     * Returns a new string of a given length such that the end of the string
2503
     * is padded. Alias for pad() with a $padType of 'right'.
2504
     *
2505
     * @param int    $length <p>Desired string length after padding.</p>
2506
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2507
     *
2508
     * @psalm-mutation-free
2509
     *
2510
     * @return static
2511
     *                <p>String with right padding.</p>
2512
     */
2513 21
    public function padRight(int $length, string $padStr = ' '): self
2514
    {
2515 21
        return static::create(
2516 21
            $this->utf8::str_pad_right(
2517 21
                $this->str,
2518 21
                $length,
2519 21
                $padStr,
2520 21
                $this->encoding
2521
            )
2522
        );
2523
    }
2524
2525
    /**
2526
     * Convert the string to PascalCase.
2527
     * Alias for studlyCase()
2528
     *
2529
     * @psalm-mutation-free
2530
     *
2531
     * @return static
2532
     */
2533 3
    public function pascalCase(): self
2534
    {
2535 3
        return $this->studlyCase();
2536
    }
2537
2538
    /**
2539
     * Returns a new string starting with $prefix.
2540
     *
2541
     * @param string ...$prefix <p>The string to append.</p>
2542
     *
2543
     * @psalm-mutation-free
2544
     *
2545
     * @return static
2546
     *                <p>Object with appended $prefix.</p>
2547
     *
2548
     * @noinspection PhpDocSignatureInspection
2549
     */
2550 7 View Code Duplication
    public function prepend(string ...$prefix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2551
    {
2552 7
        if (\count($prefix) <= 1) {
2553
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
2554 6
            $prefix = $prefix[0];
2555
        } else {
2556
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
2557 1
            $prefix = \implode('', $prefix);
2558
        }
2559
2560 7
        return static::create($prefix . $this->str, $this->encoding);
2561
    }
2562
2563
    /**
2564
     * Replaces all occurrences of $pattern in $str by $replacement.
2565
     *
2566
     * @param string $pattern     <p>The regular expression pattern.</p>
2567
     * @param string $replacement <p>The string to replace with.</p>
2568
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
2569
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
2570
     *
2571
     * @psalm-mutation-free
2572
     *
2573
     * @return static
2574
     *                <p>Object with the result2ing $str after the replacements.</p>
2575
     */
2576 29
    public function regexReplace(string $pattern, string $replacement, string $options = '', string $delimiter = '/'): self
2577
    {
2578 29
        return static::create(
2579 29
            $this->utf8::regex_replace(
2580 29
                $this->str,
2581 29
                $pattern,
2582 29
                $replacement,
2583 29
                $options,
2584 29
                $delimiter
2585
            ),
2586 29
            $this->encoding
2587
        );
2588
    }
2589
2590
    /**
2591
     * Remove html via "strip_tags()" from the string.
2592
     *
2593
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
2594
     *                              not be stripped. Default: null
2595
     *                              </p>
2596
     *
2597
     * @psalm-mutation-free
2598
     *
2599
     * @return static
2600
     */
2601 12
    public function removeHtml(string $allowableTags = ''): self
2602
    {
2603 12
        return static::create(
2604 12
            $this->utf8::remove_html($this->str, $allowableTags),
2605 12
            $this->encoding
2606
        );
2607
    }
2608
2609
    /**
2610
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
2611
     *
2612
     * @param string $replacement [optional] <p>Default is a empty string.</p>
2613
     *
2614
     * @psalm-mutation-free
2615
     *
2616
     * @return static
2617
     */
2618 12
    public function removeHtmlBreak(string $replacement = ''): self
2619
    {
2620 12
        return static::create(
2621 12
            $this->utf8::remove_html_breaks($this->str, $replacement),
2622 12
            $this->encoding
2623
        );
2624
    }
2625
2626
    /**
2627
     * Returns a new string with the prefix $substring removed, if present.
2628
     *
2629
     * @param string $substring <p>The prefix to remove.</p>
2630
     *
2631
     * @psalm-mutation-free
2632
     *
2633
     * @return static
2634
     *                <p>Object having a $str without the prefix $substring.</p>
2635
     */
2636 36
    public function removeLeft(string $substring): self
2637
    {
2638 36
        return static::create(
2639 36
            $this->utf8::remove_left($this->str, $substring, $this->encoding),
2640 36
            $this->encoding
2641
        );
2642
    }
2643
2644
    /**
2645
     * Returns a new string with the suffix $substring removed, if present.
2646
     *
2647
     * @param string $substring <p>The suffix to remove.</p>
2648
     *
2649
     * @psalm-mutation-free
2650
     *
2651
     * @return static
2652
     *                <p>Object having a $str without the suffix $substring.</p>
2653
     */
2654 36
    public function removeRight(string $substring): self
2655
    {
2656 36
        return static::create(
2657 36
            $this->utf8::remove_right($this->str, $substring, $this->encoding),
2658 36
            $this->encoding
2659
        );
2660
    }
2661
2662
    /**
2663
     * Try to remove all XSS-attacks from the string.
2664
     *
2665
     * @psalm-mutation-free
2666
     *
2667
     * @return static
2668
     */
2669 12
    public function removeXss(): self
2670
    {
2671
        /**
2672
         * @var AntiXSS|null
2673
         *
2674
         * @psalm-suppress ImpureStaticVariable
2675
         */
2676 12
        static $antiXss = null;
2677
2678 12
        if ($antiXss === null) {
2679 1
            $antiXss = new AntiXSS();
2680
        }
2681
2682
        /**
2683
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the anti-xss class
2684
         */
2685 12
        $str = $antiXss->xss_clean($this->str);
2686
2687 12
        return static::create($str, $this->encoding);
2688
    }
2689
2690
    /**
2691
     * Returns a repeated string given a multiplier.
2692
     *
2693
     * @param int $multiplier <p>The number of times to repeat the string.</p>
2694
     *
2695
     * @psalm-mutation-free
2696
     *
2697
     * @return static
2698
     *                <p>Object with a repeated str.</p>
2699
     */
2700 21
    public function repeat(int $multiplier): self
2701
    {
2702 21
        return static::create(
2703 21
            \str_repeat($this->str, $multiplier),
2704 21
            $this->encoding
2705
        );
2706
    }
2707
2708
    /**
2709
     * Replaces all occurrences of $search in $str by $replacement.
2710
     *
2711
     * @param string $search        <p>The needle to search for.</p>
2712
     * @param string $replacement   <p>The string to replace with.</p>
2713
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
2714
     *
2715
     * @psalm-mutation-free
2716
     *
2717
     * @return static
2718
     *                <p>Object with the resulting $str after the replacements.</p>
2719
     */
2720 76
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
2721
    {
2722 76
        if ($search === '' && $replacement === '') {
2723 16
            return static::create($this->str, $this->encoding);
2724
        }
2725
2726 60
        if ($this->str === '' && $search === '') {
2727 2
            return static::create($replacement, $this->encoding);
2728
        }
2729
2730 58
        if ($caseSensitive) {
2731 48
            return static::create(
2732 48
                $this->utf8::str_replace($search, $replacement, $this->str),
2733 48
                $this->encoding
2734
            );
2735
        }
2736
2737 10
        return static::create(
2738 10
            $this->utf8::str_ireplace($search, $replacement, $this->str),
2739 10
            $this->encoding
2740
        );
2741
    }
2742
2743
    /**
2744
     * Replaces all occurrences of $search in $str by $replacement.
2745
     *
2746
     * @param string[]        $search        <p>The elements to search for.</p>
2747
     * @param string|string[] $replacement   <p>The string to replace with.</p>
2748
     * @param bool            $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
2749
     *
2750
     * @psalm-mutation-free
2751
     *
2752
     * @return static
2753
     *                <p>Object with the resulting $str after the replacements.</p>
2754
     */
2755 61
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
2756
    {
2757 61
        if ($caseSensitive) {
2758 47
            return static::create(
2759 47
                $this->utf8::str_replace($search, $replacement, $this->str),
2760 47
                $this->encoding
2761
            );
2762
        }
2763
2764 14
        return static::create(
2765 14
            $this->utf8::str_ireplace($search, $replacement, $this->str),
2766 14
            $this->encoding
2767
        );
2768
    }
2769
2770
    /**
2771
     * Replaces all occurrences of $search from the beginning of string with $replacement.
2772
     *
2773
     * @param string $search      <p>The string to search for.</p>
2774
     * @param string $replacement <p>The replacement.</p>
2775
     *
2776
     * @psalm-mutation-free
2777
     *
2778
     * @return static
2779
     *                <p>Object with the resulting $str after the replacements.</p>
2780
     */
2781 32
    public function replaceBeginning(string $search, string $replacement): self
2782
    {
2783 32
        return static::create(
2784 32
            $this->utf8::str_replace_beginning($this->str, $search, $replacement),
2785 32
            $this->encoding
2786
        );
2787
    }
2788
2789
    /**
2790
     * Replaces all occurrences of $search from the ending of string with $replacement.
2791
     *
2792
     * @param string $search      <p>The string to search for.</p>
2793
     * @param string $replacement <p>The replacement.</p>
2794
     *
2795
     * @psalm-mutation-free
2796
     *
2797
     * @return static
2798
     *                <p>Object with the resulting $str after the replacements.</p>
2799
     */
2800 32
    public function replaceEnding(string $search, string $replacement): self
2801
    {
2802 32
        return static::create(
2803 32
            $this->utf8::str_replace_ending($this->str, $search, $replacement),
2804 32
            $this->encoding
2805
        );
2806
    }
2807
2808
    /**
2809
     * Replaces first occurrences of $search from the beginning of string with $replacement.
2810
     *
2811
     * @param string $search      <p>The string to search for.</p>
2812
     * @param string $replacement <p>The replacement.</p>
2813
     *
2814
     * @psalm-mutation-free
2815
     *
2816
     * @return static
2817
     *                <p>Object with the resulting $str after the replacements.</p>
2818
     */
2819 32
    public function replaceFirst(string $search, string $replacement): self
2820
    {
2821 32
        return static::create(
2822 32
            $this->utf8::str_replace_first($search, $replacement, $this->str),
2823 32
            $this->encoding
2824
        );
2825
    }
2826
2827
    /**
2828
     * Replaces last occurrences of $search from the ending of string with $replacement.
2829
     *
2830
     * @param string $search      <p>The string to search for.</p>
2831
     * @param string $replacement <p>The replacement.</p>
2832
     *
2833
     * @psalm-mutation-free
2834
     *
2835
     * @return static
2836
     *                <p>Object with the resulting $str after the replacements.</p>
2837
     */
2838 30
    public function replaceLast(string $search, string $replacement): self
2839
    {
2840 30
        return static::create(
2841 30
            $this->utf8::str_replace_last($search, $replacement, $this->str),
2842 30
            $this->encoding
2843
        );
2844
    }
2845
2846
    /**
2847
     * Returns a reversed string. A multibyte version of strrev().
2848
     *
2849
     * @psalm-mutation-free
2850
     *
2851
     * @return static
2852
     *                <p>Object with a reversed $str.</p>
2853
     */
2854 15
    public function reverse(): self
2855
    {
2856 15
        return static::create($this->utf8::strrev($this->str), $this->encoding);
2857
    }
2858
2859
    /**
2860
     * Truncates the string to a given length, while ensuring that it does not
2861
     * split words. If $substring is provided, and truncating occurs, the
2862
     * string is further truncated so that the substring may be appended without
2863
     * exceeding the desired length.
2864
     *
2865
     * @param int    $length                          <p>Desired length of the truncated string.</p>
2866
     * @param string $substring                       [optional] <p>The substring to append if it can fit. Default: ''</p>
2867
     * @param bool   $ignoreDoNotSplitWordsForOneWord
2868
     *
2869
     * @psalm-mutation-free
2870
     *
2871
     * @return static
2872
     *                <p>Object with the resulting $str after truncating.</p>
2873
     */
2874 68
    public function safeTruncate(
2875
        int $length,
2876
        string $substring = '',
2877
        bool $ignoreDoNotSplitWordsForOneWord = true
2878
    ): self {
2879 68
        return static::create(
2880 68
            $this->utf8::str_truncate_safe(
2881 68
                $this->str,
2882 68
                $length,
2883 68
                $substring,
2884 68
                $this->encoding,
2885 68
                $ignoreDoNotSplitWordsForOneWord
2886
            ),
2887 68
            $this->encoding
2888
        );
2889
    }
2890
2891
    /**
2892
     * Set the internal character encoding.
2893
     *
2894
     * @param string $new_encoding <p>The desired character encoding.</p>
2895
     *
2896
     * @psalm-mutation-free
2897
     *
2898
     * @return static
2899
     */
2900 1
    public function setInternalEncoding(string $new_encoding): self
2901
    {
2902 1
        return new static($this->str, $new_encoding);
2903
    }
2904
2905
    /**
2906
     * Create a sha1 hash from the current string.
2907
     *
2908
     * @psalm-mutation-free
2909
     *
2910
     * @return static
2911
     */
2912 2
    public function sha1(): self
2913
    {
2914 2
        return static::create($this->hash('sha1'), $this->encoding);
2915
    }
2916
2917
    /**
2918
     * Create a sha256 hash from the current string.
2919
     *
2920
     * @psalm-mutation-free
2921
     *
2922
     * @return static
2923
     */
2924 2
    public function sha256(): self
2925
    {
2926 2
        return static::create($this->hash('sha256'), $this->encoding);
2927
    }
2928
2929
    /**
2930
     * Create a sha512 hash from the current string.
2931
     *
2932
     * @psalm-mutation-free
2933
     *
2934
     * @return static
2935
     */
2936 2
    public function sha512(): self
2937
    {
2938 2
        return static::create($this->hash('sha512'), $this->encoding);
2939
    }
2940
2941
    /**
2942
     * Shorten the string after $length, but also after the next word.
2943
     *
2944
     * @param int    $length   <p>The given length.</p>
2945
     * @param string $strAddOn [optional] <p>Default: '…'</p>
2946
     *
2947
     * @psalm-mutation-free
2948
     *
2949
     * @return static
2950
     */
2951 8
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
2952
    {
2953 8
        return static::create(
2954 8
            $this->utf8::str_limit_after_word($this->str, $length, $strAddOn),
2955 8
            $this->encoding
2956
        );
2957
    }
2958
2959
    /**
2960
     * A multibyte string shuffle function. It returns a string with its
2961
     * characters in random order.
2962
     *
2963
     * @psalm-mutation-free
2964
     *
2965
     * @return static
2966
     *                <p>Object with a shuffled $str.</p>
2967
     */
2968 9
    public function shuffle(): self
2969
    {
2970 9
        return static::create($this->utf8::str_shuffle($this->str), $this->encoding);
2971
    }
2972
2973
    /**
2974
     * Calculate the similarity between two strings.
2975
     *
2976
     * @param string $str <p>The delimiting string.</p>
2977
     *
2978
     * @psalm-mutation-free
2979
     *
2980
     * @return float
2981
     */
2982 2
    public function similarity(string $str): float
2983
    {
2984 2
        \similar_text($this->str, $str, $percent);
2985
2986 2
        return $percent;
2987
    }
2988
2989
    /**
2990
     * Returns the substring beginning at $start, and up to, but not including
2991
     * the index specified by $end. If $end is omitted, the function extracts
2992
     * the remaining string. If $end is negative, it is computed from the end
2993
     * of the string.
2994
     *
2995
     * @param int $start <p>Initial index from which to begin extraction.</p>
2996
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
2997
     *
2998
     * @psalm-mutation-free
2999
     *
3000
     * @return static
3001
     *                <p>Object with its $str being the extracted substring.</p>
3002
     */
3003 50
    public function slice(int $start, int $end = null): self
3004
    {
3005 50
        return static::create(
3006 50
            $this->utf8::str_slice($this->str, $start, $end, $this->encoding),
3007 50
            $this->encoding
3008
        );
3009
    }
3010
3011
    /**
3012
     * Converts the string into an URL slug. This includes replacing non-ASCII
3013
     * characters with their closest ASCII equivalents, removing remaining
3014
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
3015
     * $separator. The separator defaults to a single dash, and the string
3016
     * is also converted to lowercase. The language of the source string can
3017
     * also be supplied for language-specific transliteration.
3018
     *
3019
     * @param string                $separator             [optional] <p>The string used to replace whitespace.</p>
3020
     * @param string                $language              [optional] <p>Language of the source string.</p>
3021
     * @param array<string, string> $replacements          [optional] <p>A map of replaceable strings.</p>
3022
     * @param bool                  $replace_extra_symbols [optional]  <p>Add some more replacements e.g. "£" with "
3023
     *                                                     pound ".</p>
3024
     * @param bool                  $use_str_to_lower      [optional] <p>Use "string to lower" for the input.</p>
3025
     * @param bool                  $use_transliterate     [optional]  <p>Use ASCII::to_transliterate() for unknown
3026
     *                                                     chars.</p>
3027
     *
3028
     * @psalm-mutation-free
3029
     *
3030
     * @return static
3031
     *                <p>Object whose $str has been converted to an URL slug.</p>
3032
     *
3033
     * @noinspection PhpTooManyParametersInspection
3034
     */
3035 17
    public function slugify(
3036
        string $separator = '-',
3037
        string $language = 'en',
3038
        array $replacements = [],
3039
        bool $replace_extra_symbols = true,
3040
        bool $use_str_to_lower = true,
3041
        bool $use_transliterate = false
3042
    ): self {
3043 17
        return static::create(
3044 17
            $this->ascii::to_slugify(
3045 17
                $this->str,
3046 17
                $separator,
3047 17
                $language,
3048 17
                $replacements,
3049 17
                $replace_extra_symbols,
3050 17
                $use_str_to_lower,
3051 17
                $use_transliterate
3052
            ),
3053 17
            $this->encoding
3054
        );
3055
    }
3056
3057
    /**
3058
     * Convert the string to snake_case.
3059
     *
3060
     * @psalm-mutation-free
3061
     *
3062
     * @return static
3063
     */
3064 3 View Code Duplication
    public function snakeCase(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3065
    {
3066 3
        $words = \array_map(
3067 3
            function ($word) {
3068 3
                return $this->utf8::strtolower($word, $this->encoding);
3069 3
            },
3070 3
            $this->words('', true)
3071
        );
3072
3073 3
        return new static(\implode('_', $words), $this->encoding);
3074
    }
3075
3076
    /**
3077
     * Convert a string to e.g.: "snake_case"
3078
     *
3079
     * @psalm-mutation-free
3080
     *
3081
     * @return static
3082
     *                <p>Object with $str in snake_case.</p>
3083
     */
3084 40
    public function snakeize(): self
3085
    {
3086 40
        return static::create(
3087 40
            $this->utf8::str_snakeize($this->str, $this->encoding),
3088 40
            $this->encoding
3089
        );
3090
    }
3091
3092
    /**
3093
     * Wrap the string after the first whitespace character after a given number
3094
     * of characters.
3095
     *
3096
     * @param int    $width <p>Number of characters at which to wrap.</p>
3097
     * @param string $break [optional] <p>Character used to break the string. | Default "\n"</p>
3098
     *
3099
     * @psalm-mutation-free
3100
     *
3101
     * @return static
3102
     */
3103 2
    public function softWrap(int $width, string $break = "\n"): self
3104
    {
3105 2
        return $this->lineWrapAfterWord($width, $break, false);
3106
    }
3107
3108
    /**
3109
     * Splits the string with the provided regular expression, returning an
3110
     * array of Stringy objects. An optional integer $limit will truncate the
3111
     * results.
3112
     *
3113
     * @param string $pattern                  <p>The regex with which to split the string.</p>
3114
     * @param int    $limit                    [optional] <p>Maximum number of results to return. Default: -1 === no
3115
     *                                         limit</p>
3116
     * @param bool   $return_stingy_collection [optional] <p>Return a collection object.</p>
3117
     *
3118
     * @psalm-mutation-free
3119
     *
3120
     * @return CollectionStringy|static[]
3121
     *                                    <p>An collection of Stringy objects.</p>
3122
     *
3123
     * @psalm-return CollectionStringy<int,static>|array<int,static>
3124
     */
3125 51
    public function split(
3126
        string $pattern,
3127
        int $limit = null,
3128
        bool $return_stingy_collection = false
3129
    ) {
3130 51
        if ($this->str === '') {
3131
            if ($return_stingy_collection) {
3132
                /**
3133
                 * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3134
                 */
3135
                return CollectionStringy::create([]);
3136
            }
3137
3138
            return [];
3139
        }
3140
3141 51
        if ($limit === null) {
3142 7
            $limit = -1;
3143
        }
3144
3145 51
        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
3146
        /** @noinspection AlterInForeachInspection */
3147 51
        foreach ($array as $i => &$value) {
3148 45
            $value = static::create($value, $this->encoding);
3149
        }
3150
3151
        /** @noinspection PhpSillyAssignmentInspection */
3152
        /** @var static[] $array */
3153 51
        $array = $array;
0 ignored issues
show
Bug introduced by
Why assign $array to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
3154
3155 51
        if ($return_stingy_collection) {
3156
            /**
3157
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3158
             */
3159 35
            return CollectionStringy::create($array);
3160
        }
3161
3162 16
        return $array;
3163
    }
3164
3165
    /**
3166
     * Returns true if the string begins with $substring, false otherwise. By
3167
     * default, the comparison is case-sensitive, but can be made insensitive
3168
     * by setting $caseSensitive to false.
3169
     *
3170
     * @param string $substring     <p>The substring to look for.</p>
3171
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3172
     *
3173
     * @psalm-mutation-free
3174
     *
3175
     * @return bool
3176
     *              <p>Whether or not $str starts with $substring.</p>
3177
     */
3178 99
    public function startsWith(string $substring, bool $caseSensitive = true): bool
3179
    {
3180 99
        if ($caseSensitive) {
3181 53
            return $this->utf8::str_starts_with($this->str, $substring);
3182
        }
3183
3184 46
        return $this->utf8::str_istarts_with($this->str, $substring);
3185
    }
3186
3187
    /**
3188
     * Returns true if the string begins with any of $substrings, false otherwise.
3189
     * By default the comparison is case-sensitive, but can be made insensitive by
3190
     * setting $caseSensitive to false.
3191
     *
3192
     * @param string[] $substrings    <p>Substrings to look for.</p>
3193
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3194
     *
3195
     * @psalm-mutation-free
3196
     *
3197
     * @return bool
3198
     *              <p>Whether or not $str starts with $substring.</p>
3199
     */
3200 35
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
3201
    {
3202 35
        if ($caseSensitive) {
3203 23
            return $this->utf8::str_starts_with_any($this->str, $substrings);
3204
        }
3205
3206 12
        return $this->utf8::str_istarts_with_any($this->str, $substrings);
3207
    }
3208
3209
    /**
3210
     * Remove one or more strings from the string.
3211
     *
3212
     * @param string|string[] $search One or more strings to be removed
3213
     *
3214
     * @psalm-mutation-free
3215
     *
3216
     * @return static
3217
     */
3218 3
    public function strip($search): self
3219
    {
3220 3
        if (\is_array($search)) {
3221 1
            return $this->replaceAll($search, '');
3222
        }
3223
3224 2
        return $this->replace($search, '');
3225
    }
3226
3227
    /**
3228
     * Strip all whitespace characters. This includes tabs and newline characters,
3229
     * as well as multibyte whitespace such as the thin space and ideographic space.
3230
     *
3231
     * @psalm-mutation-free
3232
     *
3233
     * @return static
3234
     */
3235 36
    public function stripWhitespace(): self
3236
    {
3237 36
        return static::create(
3238 36
            $this->utf8::strip_whitespace($this->str),
3239 36
            $this->encoding
3240
        );
3241
    }
3242
3243
    /**
3244
     * Remove css media-queries.
3245
     *
3246
     * @psalm-mutation-free
3247
     *
3248
     * @return static
3249
     */
3250 2
    public function stripeCssMediaQueries(): self
3251
    {
3252 2
        return static::create(
3253 2
            $this->utf8::css_stripe_media_queries($this->str),
3254 2
            $this->encoding
3255
        );
3256
    }
3257
3258
    /**
3259
     * Remove empty html-tag.
3260
     *
3261
     * e.g.: <tag></tag>
3262
     *
3263
     * @psalm-mutation-free
3264
     *
3265
     * @return static
3266
     */
3267 2
    public function stripeEmptyHtmlTags(): self
3268
    {
3269 2
        return static::create(
3270 2
            $this->utf8::html_stripe_empty_tags($this->str),
3271 2
            $this->encoding
3272
        );
3273
    }
3274
3275
    /**
3276
     * Convert the string to StudlyCase.
3277
     *
3278
     * @psalm-mutation-free
3279
     *
3280
     * @return static
3281
     */
3282 6
    public function studlyCase(): self
3283
    {
3284 6
        $words = \array_map(
3285 6
            function (self $word) {
3286 6
                return $this->utf8::strtoupper(
3287 6
                    $this->utf8::substr($word->toString(), 0, 1, $this->encoding),
3288 6
                    $this->encoding
3289 6
                ) . $this->utf8::substr($word->toString(), 1, null, $this->encoding);
3290 6
            },
3291 6
            $this->words('', true)
3292
        );
3293
3294 6
        return new static(\implode('', $words), $this->encoding);
3295
    }
3296
3297
    /**
3298
     * Returns the substring beginning at $start with the specified $length.
3299
     * It differs from the $this->utf8::substr() function in that providing a $length of
3300
     * null will return the rest of the string, rather than an empty string.
3301
     *
3302
     * @param int $start  <p>Position of the first character to use.</p>
3303
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
3304
     *
3305
     * @psalm-mutation-free
3306
     *
3307
     * @return static
3308
     *                <p>Object with its $str being the substring.</p>
3309
     */
3310 31
    public function substr(int $start, int $length = null): self
3311
    {
3312 31
        return static::create(
3313 31
            $this->utf8::substr(
3314 31
                $this->str,
3315 31
                $start,
3316 31
                $length,
3317 31
                $this->encoding
3318
            ),
3319 31
            $this->encoding
3320
        );
3321
    }
3322
3323
    /**
3324
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
3325
     * If no match is found returns new empty Stringy object.
3326
     *
3327
     * @param string $needle       <p>The string to look for.</p>
3328
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
3329
     *
3330
     * @psalm-mutation-free
3331
     *
3332
     * @return static
3333
     */
3334 4 View Code Duplication
    public function substringOf(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3335
    {
3336 4
        return static::create(
3337 4
            $this->utf8::str_substr_first(
3338 4
                $this->str,
3339 4
                $needle,
3340 4
                $beforeNeedle,
3341 4
                $this->encoding
3342
            ),
3343 4
            $this->encoding
3344
        );
3345
    }
3346
3347
    /**
3348
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
3349
     * If no match is found returns new empty Stringy object.
3350
     *
3351
     * @param string $needle       <p>The string to look for.</p>
3352
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
3353
     *
3354
     * @psalm-mutation-free
3355
     *
3356
     * @return static
3357
     */
3358 4 View Code Duplication
    public function substringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3359
    {
3360 4
        return static::create(
3361 4
            $this->utf8::str_isubstr_first(
3362 4
                $this->str,
3363 4
                $needle,
3364 4
                $beforeNeedle,
3365 4
                $this->encoding
3366
            ),
3367 4
            $this->encoding
3368
        );
3369
    }
3370
3371
    /**
3372
     * Surrounds $str with the given substring.
3373
     *
3374
     * @param string $substring <p>The substring to add to both sides.</P>
3375
     *
3376
     * @psalm-mutation-free
3377
     *
3378
     * @return static
3379
     *                <p>Object whose $str had the substring both prepended and appended.</p>
3380
     */
3381 15
    public function surround(string $substring): self
3382
    {
3383 15
        return static::create(
3384 15
            $substring . $this->str . $substring,
3385 15
            $this->encoding
3386
        );
3387
    }
3388
3389
    /**
3390
     * Returns a case swapped version of the string.
3391
     *
3392
     * @psalm-mutation-free
3393
     *
3394
     * @return static
3395
     *                <p>Object whose $str has each character's case swapped.</P>
3396
     */
3397 15
    public function swapCase(): self
3398
    {
3399 15
        return static::create(
3400 15
            $this->utf8::swapCase($this->str, $this->encoding),
3401 15
            $this->encoding
3402
        );
3403
    }
3404
3405
    /**
3406
     * Returns a string with smart quotes, ellipsis characters, and dashes from
3407
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
3408
     * equivalents.
3409
     *
3410
     * @psalm-mutation-free
3411
     *
3412
     * @return static
3413
     *                <p>Object whose $str has those characters removed.</p>
3414
     */
3415 12
    public function tidy(): self
3416
    {
3417 12
        return static::create(
3418 12
            $this->ascii::normalize_msword($this->str),
3419 12
            $this->encoding
3420
        );
3421
    }
3422
3423
    /**
3424
     * Returns a trimmed string with the first letter of each word capitalized.
3425
     * Also accepts an array, $ignore, allowing you to list words not to be
3426
     * capitalized.
3427
     *
3428
     * @param array|string[]|null $ignore            [optional] <p>An array of words not to capitalize or null.
3429
     *                                               Default: null</p>
3430
     * @param string|null         $word_define_chars [optional] <p>An string of chars that will be used as whitespace
3431
     *                                               separator === words.</p>
3432
     * @param string|null         $language          [optional] <p>Language of the source string.</p>
3433
     *
3434
     * @psalm-mutation-free
3435
     *
3436
     * @return static
3437
     *                <p>Object with a titleized $str.</p>
3438
     */
3439 23
    public function titleize(
3440
        array $ignore = null,
3441
        string $word_define_chars = null,
3442
        string $language = null
3443
    ): self {
3444 23
        return static::create(
3445 23
            $this->utf8::str_titleize(
3446 23
                $this->str,
3447 23
                $ignore,
3448 23
                $this->encoding,
3449 23
                false,
3450 23
                $language,
3451 23
                false,
3452 23
                true,
3453 23
                $word_define_chars
3454
            ),
3455 23
            $this->encoding
3456
        );
3457
    }
3458
3459
    /**
3460
     * Returns a trimmed string in proper title case.
3461
     *
3462
     * Also accepts an array, $ignore, allowing you to list words not to be
3463
     * capitalized.
3464
     *
3465
     * Adapted from John Gruber's script.
3466
     *
3467
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
3468
     *
3469
     * @param string[] $ignore <p>An array of words not to capitalize.</p>
3470
     *
3471
     * @psalm-mutation-free
3472
     *
3473
     * @return static
3474
     *                <p>Object with a titleized $str</p>
3475
     */
3476 70
    public function titleizeForHumans(array $ignore = []): self
3477
    {
3478 70
        return static::create(
3479 70
            $this->utf8::str_titleize_for_humans(
3480 70
                $this->str,
3481 70
                $ignore,
3482 70
                $this->encoding
3483
            ),
3484 70
            $this->encoding
3485
        );
3486
    }
3487
3488
    /**
3489
     * Returns an ASCII version of the string. A set of non-ASCII characters are
3490
     * replaced with their closest ASCII counterparts, and the rest are removed
3491
     * by default. The language or locale of the source string can be supplied
3492
     * for language-specific transliteration in any of the following formats:
3493
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
3494
     * to "aeoeue" rather than "aou" as in other languages.
3495
     *
3496
     * @param string $language          [optional] <p>Language of the source string.</p>
3497
     * @param bool   $removeUnsupported [optional] <p>Whether or not to remove the
3498
     *                                  unsupported characters.</p>
3499
     *
3500
     * @psalm-mutation-free
3501
     *
3502
     * @return static
3503
     *                <p>Object whose $str contains only ASCII characters.</p>
3504
     */
3505 23
    public function toAscii(string $language = 'en', bool $removeUnsupported = true): self
3506
    {
3507 23
        return static::create(
3508 23
            $this->ascii::to_ascii(
3509 23
                $this->str,
3510 23
                $language,
3511 23
                $removeUnsupported
3512
            ),
3513 23
            $this->encoding
3514
        );
3515
    }
3516
3517
    /**
3518
     * Returns a boolean representation of the given logical string value.
3519
     * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
3520
     * 'off', and 'no' will return false. In all instances, case is ignored.
3521
     * For other numeric strings, their sign will determine the return value.
3522
     * In addition, blank strings consisting of only whitespace will return
3523
     * false. For all other strings, the return value is a result of a
3524
     * boolean cast.
3525
     *
3526
     * @psalm-mutation-free
3527
     *
3528
     * @return bool
3529
     *              <p>A boolean value for the string.</p>
3530
     */
3531 45
    public function toBoolean(): bool
3532
    {
3533 45
        return $this->utf8::to_boolean($this->str);
3534
    }
3535
3536
    /**
3537
     * Converts all characters in the string to lowercase.
3538
     *
3539
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
3540
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
3541
     *
3542
     * @psalm-mutation-free
3543
     *
3544
     * @return static
3545
     *                <p>Object with all characters of $str being lowercase.</p>
3546
     */
3547 17 View Code Duplication
    public function toLowerCase($tryToKeepStringLength = false, $lang = null): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3548
    {
3549 17
        return static::create(
3550 17
            $this->utf8::strtolower(
3551 17
                $this->str,
3552 17
                $this->encoding,
3553 17
                false,
3554 17
                $lang,
3555 17
                $tryToKeepStringLength
3556
            ),
3557 17
            $this->encoding
3558
        );
3559
    }
3560
3561
    /**
3562
     * Converts each tab in the string to some number of spaces, as defined by
3563
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
3564
     *
3565
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
3566
     *
3567
     * @psalm-mutation-free
3568
     *
3569
     * @return static
3570
     *                <p>Object whose $str has had tabs switched to spaces.</p>
3571
     */
3572 18 View Code Duplication
    public function toSpaces(int $tabLength = 4): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3573
    {
3574 18
        if ($tabLength === 4) {
3575 9
            $tab = '    ';
3576 9
        } elseif ($tabLength === 2) {
3577 3
            $tab = '  ';
3578
        } else {
3579 6
            $tab = \str_repeat(' ', $tabLength);
3580
        }
3581
3582 18
        return static::create(
3583 18
            \str_replace("\t", $tab, $this->str),
3584 18
            $this->encoding
3585
        );
3586
    }
3587
3588
    /**
3589
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
3590
     * string.
3591
     *
3592
     * @psalm-mutation-free
3593
     *
3594
     * @return string
3595
     */
3596 2189
    public function toString(): string
3597
    {
3598 2189
        return (string) $this->str;
3599
    }
3600
3601
    /**
3602
     * Converts each occurrence of some consecutive number of spaces, as
3603
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
3604
     * are converted to a tab.
3605
     *
3606
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
3607
     *
3608
     * @psalm-mutation-free
3609
     *
3610
     * @return static
3611
     *                <p>Object whose $str has had spaces switched to tabs.</p>
3612
     */
3613 15 View Code Duplication
    public function toTabs(int $tabLength = 4): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3614
    {
3615 15
        if ($tabLength === 4) {
3616 9
            $tab = '    ';
3617 6
        } elseif ($tabLength === 2) {
3618 3
            $tab = '  ';
3619
        } else {
3620 3
            $tab = \str_repeat(' ', $tabLength);
3621
        }
3622
3623 15
        return static::create(
3624 15
            \str_replace($tab, "\t", $this->str),
3625 15
            $this->encoding
3626
        );
3627
    }
3628
3629
    /**
3630
     * Converts the first character of each word in the string to uppercase
3631
     * and all other chars to lowercase.
3632
     *
3633
     * @psalm-mutation-free
3634
     *
3635
     * @return static
3636
     *                <p>Object with all characters of $str being title-cased.</p>
3637
     */
3638 15
    public function toTitleCase(): self
3639
    {
3640 15
        return static::create(
3641 15
            $this->utf8::titlecase($this->str, $this->encoding),
3642 15
            $this->encoding
3643
        );
3644
    }
3645
3646
    /**
3647
     * Returns an ASCII version of the string. A set of non-ASCII characters are
3648
     * replaced with their closest ASCII counterparts, and the rest are removed
3649
     * unless instructed otherwise.
3650
     *
3651
     * @param bool   $strict  [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad
3652
     *                        performance | Default: false</p>
3653
     * @param string $unknown [optional] <p>Character use if character unknown. (default is ?)</p>
3654
     *
3655
     * @psalm-mutation-free
3656
     *
3657
     * @return static
3658
     *                <p>Object whose $str contains only ASCII characters.</p>
3659
     */
3660 34
    public function toTransliterate(bool $strict = false, string $unknown = '?'): self
3661
    {
3662 34
        return static::create(
3663 34
            $this->ascii::to_transliterate($this->str, $unknown, $strict),
3664 34
            $this->encoding
3665
        );
3666
    }
3667
3668
    /**
3669
     * Converts all characters in the string to uppercase.
3670
     *
3671
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
3672
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
3673
     *
3674
     * @psalm-mutation-free
3675
     *
3676
     * @return static
3677
     *                <p>Object with all characters of $str being uppercase.</p>
3678
     */
3679 20 View Code Duplication
    public function toUpperCase($tryToKeepStringLength = false, $lang = null): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3680
    {
3681 20
        return static::create(
3682 20
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
3683 20
            $this->encoding
3684
        );
3685
    }
3686
3687
    /**
3688
     * Returns a string with whitespace removed from the start and end of the
3689
     * string. Supports the removal of unicode whitespace. Accepts an optional
3690
     * string of characters to strip instead of the defaults.
3691
     *
3692
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
3693
     *
3694
     * @psalm-mutation-free
3695
     *
3696
     * @return static
3697
     *                <p>Object with a trimmed $str.</p>
3698
     */
3699 36
    public function trim(string $chars = null): self
3700
    {
3701 36
        return static::create(
3702 36
            $this->utf8::trim($this->str, $chars),
3703 36
            $this->encoding
3704
        );
3705
    }
3706
3707
    /**
3708
     * Returns a string with whitespace removed from the start of the string.
3709
     * Supports the removal of unicode whitespace. Accepts an optional
3710
     * string of characters to strip instead of the defaults.
3711
     *
3712
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
3713
     *
3714
     * @psalm-mutation-free
3715
     *
3716
     * @return static
3717
     *                <p>Object with a trimmed $str.</p>
3718
     */
3719 39
    public function trimLeft(string $chars = null): self
3720
    {
3721 39
        return static::create(
3722 39
            $this->utf8::ltrim($this->str, $chars),
3723 39
            $this->encoding
3724
        );
3725
    }
3726
3727
    /**
3728
     * Returns a string with whitespace removed from the end of the string.
3729
     * Supports the removal of unicode whitespace. Accepts an optional
3730
     * string of characters to strip instead of the defaults.
3731
     *
3732
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
3733
     *
3734
     * @psalm-mutation-free
3735
     *
3736
     * @return static
3737
     *                <p>Object with a trimmed $str.</p>
3738
     */
3739 39
    public function trimRight(string $chars = null): self
3740
    {
3741 39
        return static::create(
3742 39
            $this->utf8::rtrim($this->str, $chars),
3743 39
            $this->encoding
3744
        );
3745
    }
3746
3747
    /**
3748
     * Truncates the string to a given length. If $substring is provided, and
3749
     * truncating occurs, the string is further truncated so that the substring
3750
     * may be appended without exceeding the desired length.
3751
     *
3752
     * @param int    $length    <p>Desired length of the truncated string.</p>
3753
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
3754
     *
3755
     * @psalm-mutation-free
3756
     *
3757
     * @return static
3758
     *                <p>Object with the resulting $str after truncating.</p>
3759
     */
3760 66
    public function truncate(int $length, string $substring = ''): self
3761
    {
3762 66
        return static::create(
3763 66
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
3764 66
            $this->encoding
3765
        );
3766
    }
3767
3768
    /**
3769
     * Returns a lowercase and trimmed string separated by underscores.
3770
     * Underscores are inserted before uppercase characters (with the exception
3771
     * of the first character of the string), and in place of spaces as well as
3772
     * dashes.
3773
     *
3774
     * @psalm-mutation-free
3775
     *
3776
     * @return static
3777
     *                <p>Object with an underscored $str.</p>
3778
     */
3779 48
    public function underscored(): self
3780
    {
3781 48
        return $this->delimit('_');
3782
    }
3783
3784
    /**
3785
     * Returns an UpperCamelCase version of the supplied string. It trims
3786
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
3787
     * and underscores, and removes spaces, dashes, underscores.
3788
     *
3789
     * @psalm-mutation-free
3790
     *
3791
     * @return static
3792
     *                <p>Object with $str in UpperCamelCase.</p>
3793
     */
3794 39
    public function upperCamelize(): self
3795
    {
3796 39
        return static::create(
3797 39
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
3798 39
            $this->encoding
3799
        );
3800
    }
3801
3802
    /**
3803
     * Converts the first character of the supplied string to upper case.
3804
     *
3805
     * @psalm-mutation-free
3806
     *
3807
     * @return static
3808
     *                <p>Object with the first character of $str being upper case.</p>
3809
     */
3810 18
    public function upperCaseFirst(): self
3811
    {
3812 18
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
3813
    }
3814
3815
    /**
3816
     * Converts the string into an URL slug. This includes replacing non-ASCII
3817
     * characters with their closest ASCII equivalents, removing remaining
3818
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
3819
     * $separator. The separator defaults to a single dash, and the string
3820
     * is also converted to lowercase.
3821
     *
3822
     * @param string                $separator    [optional] <p>The string used to replace whitespace. Default: '-'</p>
3823
     * @param string                $language     [optional] <p>The language for the url. Default: 'en'</p>
3824
     * @param array<string, string> $replacements [optional] <p>A map of replaceable strings.</p>
3825
     * @param bool                  $strToLower   [optional] <p>string to lower. Default: true</p>
3826
     *
3827
     * @psalm-mutation-free
3828
     *
3829
     * @return static
3830
     *                <p>Object whose $str has been converted to an URL slug.</p>
3831
     *
3832
     * @psalm-suppress ImpureMethodCall :/
3833
     */
3834 32
    public function urlify(
3835
        string $separator = '-',
3836
        string $language = 'en',
3837
        array $replacements = [],
3838
        bool $strToLower = true
3839
    ): self {
3840
        // init
3841 32
        $str = $this->str;
3842
3843 32
        foreach ($replacements as $from => $to) {
3844 32
            $str = \str_replace($from, $to, $str);
3845
        }
3846
3847 32
        return static::create(
3848 32
            URLify::slug(
3849 32
                $str,
3850 32
                $language,
3851 32
                $separator,
3852 32
                $strToLower
3853
            ),
3854 32
            $this->encoding
3855
        );
3856
    }
3857
3858
    /**
3859
     * Converts the string into an valid UTF-8 string.
3860
     *
3861
     * @psalm-mutation-free
3862
     *
3863
     * @return static
3864
     */
3865 2
    public function utf8ify(): self
3866
    {
3867 2
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
3868
    }
3869
3870
    /**
3871
     * Convert a string into an array of words.
3872
     *
3873
     * @param string   $char_list                [optional] <p>Additional chars for the definition of "words".</p>
3874
     * @param bool     $remove_empty_values      [optional] <p>Remove empty values.</p>
3875
     * @param int|null $remove_short_values      [optional] <p>The min. string length or null to disable</p>
3876
     * @param bool     $return_stingy_collection [optional] <p>Return a collection object.</p>
3877
     *
3878
     * @psalm-mutation-free
3879
     *
3880
     * @return CollectionStringy|static[]
3881
     *
3882
     * @psalm-return CollectionStringy<int,static>|array<int,static>
3883
     */
3884 14
    public function words(
3885
        string $char_list = '',
3886
        bool $remove_empty_values = false,
3887
        $remove_short_values = null,
3888
        bool $return_stingy_collection = false
3889
    ) {
3890
        /**
3891
         * @psalm-suppress DocblockTypeContradiction
3892
         */
3893 14
        if ($remove_short_values !== null && !\is_int($remove_short_values)) {
3894
            throw new \InvalidArgumentException(
3895
                'Passed value must be a null or int'
3896
            );
3897
        }
3898
3899 14
        if ($remove_short_values === null) {
3900 14
            $strings = $this->utf8::str_to_words(
3901 14
                $this->str,
3902 14
                $char_list,
3903 14
                $remove_empty_values
3904
            );
3905
        } else {
3906 2
            $strings = $this->utf8::str_to_words(
3907 2
                $this->str,
3908 2
                $char_list,
3909 2
                $remove_empty_values,
3910 2
                $remove_short_values
3911
            );
3912
        }
3913
3914
        /** @noinspection AlterInForeachInspection */
3915 14
        foreach ($strings as &$string) {
3916 14
            $string = static::create($string);
3917
        }
3918
3919
        /** @noinspection PhpSillyAssignmentInspection */
3920
        /** @var static[] $strings */
3921 14
        $strings = $strings;
0 ignored issues
show
Bug introduced by
Why assign $strings to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
3922
3923 14
        if ($return_stingy_collection) {
3924
            /**
3925
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3926
             */
3927 2
            return CollectionStringy::create($strings);
3928
        }
3929
3930 12
        return $strings;
3931
    }
3932
3933
    /**
3934
     * Surrounds $str with the given substring.
3935
     *
3936
     * @param string $substring <p>The substring to add to both sides.</P>
3937
     *
3938
     * @psalm-mutation-free
3939
     *
3940
     * @return static
3941
     *                <p>Object whose $str had the substring both prepended and appended.</p>
3942
     */
3943 10
    public function wrap(string $substring): self
3944
    {
3945 10
        return $this->surround($substring);
3946
    }
3947
3948
    /**
3949
     * Returns the replacements for the toAscii() method.
3950
     *
3951
     * @noinspection PhpUnused
3952
     *
3953
     * @psalm-mutation-free
3954
     *
3955
     * @return array<string, array<int, string>>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
3956
     *                       <p>An array of replacements.</p>
3957
     *
3958
     * @deprecated   this is only here for backward-compatibly reasons
3959
     */
3960 1
    protected function charsArray(): array
3961
    {
3962 1
        return $this->ascii::charsArrayWithMultiLanguageValues();
3963
    }
3964
3965
    /**
3966
     * Returns true if $str matches the supplied pattern, false otherwise.
3967
     *
3968
     * @param string $pattern <p>Regex pattern to match against.</p>
3969
     *
3970
     * @psalm-mutation-free
3971
     *
3972
     * @return bool
3973
     *              <p>Whether or not $str matches the pattern.</p>
3974
     */
3975 24
    protected function matchesPattern(string $pattern): bool
3976
    {
3977 24
        return $this->utf8::str_matches_pattern($this->str, $pattern);
3978
    }
3979
}
3980