Completed
Push — master ( ce1cf8...3790e4 )
by Lars
01:38
created

Stringy::getIterator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
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 3613
    public function __construct($str = '', string $encoding = null)
62
    {
63 3613
        if (\is_array($str)) {
64 3
            throw new \InvalidArgumentException(
65 3
                'Passed value cannot be an array'
66
            );
67
        }
68
69
        if (
70 3610
            \is_object($str)
71
            &&
72 3610
            !\method_exists($str, '__toString')
73
        ) {
74 3
            throw new \InvalidArgumentException(
75 3
                'Passed object must have a __toString method'
76
            );
77
        }
78
79 3607
        $this->str = (string) $str;
80
81 3607
        static $ASCII = null;
82 3607
        if ($ASCII === null) {
83
            $ASCII = new ASCII();
84
        }
85 3607
        $this->ascii = $ASCII;
86
87 3607
        static $UTF8 = null;
88 3607
        if ($UTF8 === null) {
89
            $UTF8 = new UTF8();
90
        }
91 3607
        $this->utf8 = $UTF8;
92
93 3607
        if ($encoding !== 'UTF-8') {
94 2437
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
95
        } else {
96 2682
            $this->encoding = $encoding;
97
        }
98 3607
    }
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 1127
    public function __toString()
109
    {
110 1127
        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 3541
    public static function create($str = '', string $encoding = null): self
742
    {
743 3541
        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
     * Set the internal character encoding.
862
     *
863
     * @param string $new_encoding <p>The desired character encoding.</p>
864
     *
865
     * @psalm-mutation-free
866
     *
867
     * @return static
868
     */
869 1
    public function setInternalEncoding(string $new_encoding): self
870
    {
871 1
        return new static($this->str, $new_encoding);
872
    }
873
874
    /**
875
     * Encrypt the string.
876
     *
877
     * @param string $password <p>The key for encrypting</p>
878
     *
879
     * @psalm-mutation-free
880
     *
881
     * @return static
882
     */
883 4
    public function encrypt(string $password): self
884
    {
885
        /**
886
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
887
         */
888 4
        return new static(
889 4
            Crypto::encryptWithPassword($this->str, $password),
890 4
            $this->encoding
891
        );
892
    }
893
894
    /**
895
     * Returns true if the string ends with $substring, false otherwise. By
896
     * default, the comparison is case-sensitive, but can be made insensitive
897
     * by setting $caseSensitive to false.
898
     *
899
     * @param string $substring     <p>The substring to look for.</p>
900
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
901
     *
902
     * @psalm-mutation-free
903
     *
904
     * @return bool
905
     *              <p>Whether or not $str ends with $substring.</p>
906
     */
907 97
    public function endsWith(string $substring, bool $caseSensitive = true): bool
908
    {
909 97
        if ($caseSensitive) {
910 53
            return $this->utf8::str_ends_with($this->str, $substring);
911
        }
912
913 44
        return $this->utf8::str_iends_with($this->str, $substring);
914
    }
915
916
    /**
917
     * Returns true if the string ends with any of $substrings, false otherwise.
918
     * By default, the comparison is case-sensitive, but can be made insensitive
919
     * by setting $caseSensitive to false.
920
     *
921
     * @param string[] $substrings    <p>Substrings to look for.</p>
922
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
923
     *
924
     * @psalm-mutation-free
925
     *
926
     * @return bool
927
     *              <p>Whether or not $str ends with $substring.</p>
928
     */
929 33
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
930
    {
931 33
        if ($caseSensitive) {
932 21
            return $this->utf8::str_ends_with_any($this->str, $substrings);
933
        }
934
935 12
        return $this->utf8::str_iends_with_any($this->str, $substrings);
936
    }
937
938
    /**
939
     * Ensures that the string begins with $substring. If it doesn't, it's
940
     * prepended.
941
     *
942
     * @param string $substring <p>The substring to add if not present.</p>
943
     *
944
     * @psalm-mutation-free
945
     *
946
     * @return static
947
     *                <p>Object with its $str prefixed by the $substring.</p>
948
     */
949 30
    public function ensureLeft(string $substring): self
950
    {
951 30
        return static::create(
952 30
            $this->utf8::str_ensure_left($this->str, $substring),
953 30
            $this->encoding
954
        );
955
    }
956
957
    /**
958
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
959
     *
960
     * @param string $substring <p>The substring to add if not present.</p>
961
     *
962
     * @psalm-mutation-free
963
     *
964
     * @return static
965
     *                <p>Object with its $str suffixed by the $substring.</p>
966
     */
967 30
    public function ensureRight(string $substring): self
968
    {
969 30
        return static::create(
970 30
            $this->utf8::str_ensure_right($this->str, $substring),
971 30
            $this->encoding
972
        );
973
    }
974
975
    /**
976
     * Create a escape html version of the string via "htmlspecialchars()".
977
     *
978
     * @psalm-mutation-free
979
     *
980
     * @return static
981
     */
982 12
    public function escape(): self
983
    {
984 12
        return static::create(
985 12
            $this->utf8::htmlspecialchars(
986 12
                $this->str,
987 12
                \ENT_QUOTES | \ENT_SUBSTITUTE,
988 12
                $this->encoding
989
            ),
990 12
            $this->encoding
991
        );
992
    }
993
994
    /**
995
     * Split a string by a string.
996
     *
997
     * @param string $delimiter                <p>The boundary string</p>
998
     * @param int    $limit                    [optional] <p>The maximum number of elements in the exploded
999
     *                                         collection.</p>
1000
     * @param bool   $return_stingy_collection [optional] <p>Return a collection object.</p>
1001
     *
1002
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
1003
     *   element containing the rest of string.
1004
     *   - If the limit parameter is negative, all components except the last -limit are returned.
1005
     *   - If the limit parameter is zero, then this is treated as 1
1006
     *
1007
     * @psalm-mutation-free
1008
     *
1009
     * @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...
1010
     */
1011 3
    public function explode(
1012
        string $delimiter,
1013
        int $limit = \PHP_INT_MAX,
1014
        bool $return_stingy_collection = false
1015
    ) {
1016 3
        if ($this->str === '') {
1017
            if ($return_stingy_collection) {
1018
                /**
1019
                 * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
1020
                 */
1021
                return CollectionStringy::create([]);
1022
            }
1023
1024
            return [];
1025
        }
1026
1027 3
        $data = \explode($delimiter, $this->str, $limit);
1028 3
        if ($data === false) {
1029
            $data = [];
1030
        }
1031
1032 3
        $data = \array_map(
1033
            function ($str) {
1034 3
                return new static($str, $this->encoding);
1035 3
            },
1036 3
            $data
1037
        );
1038
1039 3
        if ($return_stingy_collection) {
1040
            /**
1041
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
1042
             */
1043 1
            return CollectionStringy::create($data);
1044
        }
1045
1046 2
        return $data;
1047
    }
1048
1049
    /**
1050
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
1051
     *
1052
     * @param string   $search
1053
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
1054
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
1055
     *
1056
     * @psalm-mutation-free
1057
     *
1058
     * @return static
1059
     */
1060 2
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
1061
    {
1062 2
        return static::create(
1063 2
            $this->utf8::extract_text(
1064 2
                $this->str,
1065 2
                $search,
1066 2
                $length,
1067 2
                $replacerForSkippedText,
1068 2
                $this->encoding
1069
            ),
1070 2
            $this->encoding
1071
        );
1072
    }
1073
1074
    /**
1075
     * Returns the first $n characters of the string.
1076
     *
1077
     * @param int $n <p>Number of characters to retrieve from the start.</p>
1078
     *
1079
     * @psalm-mutation-free
1080
     *
1081
     * @return static
1082
     *                <p>Object with its $str being the first $n chars.</p>
1083
     */
1084 37
    public function first(int $n): self
1085
    {
1086 37
        return static::create(
1087 37
            $this->utf8::first_char($this->str, $n, $this->encoding),
1088 37
            $this->encoding
1089
        );
1090
    }
1091
1092
    /**
1093
     * Return a formatted string via sprintf + named parameters via array syntax.
1094
     *
1095
     * <p>
1096
     * <br>
1097
     * It will use "sprintf()" so you can use e.g.:
1098
     * <br>
1099
     * <br><pre>s('There are %d monkeys in the %s')->format(5, 'tree');</pre>
1100
     * <br>
1101
     * <br><pre>s('There are %2$d monkeys in the %1$s')->format('tree', 5);</pre>
1102
     * <br>
1103
     * <br>
1104
     * But you can also use named parameter via array syntax e.g.:
1105
     * <br>
1106
     * <br><pre>s('There are %:count monkeys in the %:location')->format(['count' => 5, 'location' => 'tree');</pre>
1107
     * </p>
1108
     *
1109
     * @param mixed ...$args [optional]
1110
     *
1111
     * @psalm-mutation-free
1112
     *
1113
     * @return static
1114
     *                <p>A Stringy object produced according to the formatting string
1115
     *                format.</p>
1116
     */
1117 10
    public function format(...$args): self
1118
    {
1119
        // init
1120 10
        $str = $this->str;
1121
1122 10
        if (\strpos($this->str, '%:') !== false) {
1123 8
            $offset = null;
1124 8
            $replacement = null;
1125
            /** @noinspection AlterInForeachInspection */
1126 8
            foreach ($args as $key => &$arg) {
1127 8
                if (!\is_array($arg)) {
1128 4
                    continue;
1129
                }
1130
1131 8
                foreach ($arg as $name => $param) {
1132 8
                    $name = (string) $name;
1133
1134 8
                    if (\strpos($name, '%:') !== 0) {
1135 8
                        $nameTmp = '%:' . $name;
1136
                    } else {
1137
                        $nameTmp = $name;
1138
                    }
1139
1140 8
                    if ($offset === null) {
1141 8
                        $offset = \strpos($str, $nameTmp);
1142
                    } else {
1143 6
                        $offset = \strpos($str, $nameTmp, (int) $offset + \strlen((string) $replacement));
1144
                    }
1145 8
                    if ($offset === false) {
1146 4
                        continue;
1147
                    }
1148
1149 8
                    unset($arg[$name]);
1150
1151 8
                    $str = \substr_replace($str, $param, (int) $offset, \strlen($nameTmp));
1152
                }
1153
1154 8
                unset($args[$key]);
1155
            }
1156
        }
1157
1158 10
        $str = \str_replace('%:', '%%:', $str);
1159
1160 10
        return static::create(
1161 10
            \sprintf($str, ...$args),
1162 10
            $this->encoding
1163
        );
1164
    }
1165
1166
    /**
1167
     * Returns the encoding used by the Stringy object.
1168
     *
1169
     * @psalm-mutation-free
1170
     *
1171
     * @return string
1172
     *                <p>The current value of the $encoding property.</p>
1173
     */
1174 7
    public function getEncoding(): string
1175
    {
1176 7
        return $this->encoding;
1177
    }
1178
1179
    /**
1180
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
1181
     * interface. The ArrayIterator's constructor is passed an array of chars
1182
     * in the multibyte string. This enables the use of foreach with instances
1183
     * of Stringy\Stringy.
1184
     *
1185
     * @psalm-mutation-free
1186
     *
1187
     * @return \ArrayIterator
1188
     *                        <p>An iterator for the characters in the string.</p>
1189
     *
1190
     * @psalm-return \ArrayIterator<array-key,string>
1191
     */
1192 3
    public function getIterator(): \ArrayIterator
1193
    {
1194 3
        return new \ArrayIterator($this->chars());
1195
    }
1196
1197
    /**
1198
     * Wrap the string after an exact number of characters.
1199
     *
1200
     * @param int    $width <p>Number of characters at which to wrap.</p>
1201
     * @param string $break [optional] <p>Character used to break the string. | Default: "\n"</p>
1202
     *
1203
     * @psalm-mutation-free
1204
     *
1205
     * @return static
1206
     */
1207 2
    public function hardWrap($width, $break = "\n"): self
1208
    {
1209 2
        return $this->lineWrap($width, $break, false);
1210
    }
1211
1212
    /**
1213
     * Returns true if the string contains a lower case char, false otherwise.
1214
     *
1215
     * @psalm-mutation-free
1216
     *
1217
     * @return bool
1218
     *              <p>Whether or not the string contains a lower case character.</p>
1219
     */
1220 36
    public function hasLowerCase(): bool
1221
    {
1222 36
        return $this->utf8::has_lowercase($this->str);
1223
    }
1224
1225
    /**
1226
     * Returns true if the string contains an upper case char, false otherwise.
1227
     *
1228
     * @psalm-mutation-free
1229
     *
1230
     * @return bool
1231
     *              <p>Whether or not the string contains an upper case character.</p>
1232
     */
1233 36
    public function hasUpperCase(): bool
1234
    {
1235 36
        return $this->utf8::has_uppercase($this->str);
1236
    }
1237
1238
    /**
1239
     * Generate a hash value (message digest)
1240
     *
1241
     * @see https://php.net/manual/en/function.hash.php
1242
     *
1243
     * @param string $algorithm
1244
     *                          <p>Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4", etc..)</p>
1245
     *
1246
     * @psalm-mutation-free
1247
     *
1248
     * @return static
1249
     */
1250 8
    public function hash($algorithm): self
1251
    {
1252 8
        return static::create(\hash($algorithm, $this->str), $this->encoding);
1253
    }
1254
1255
    /**
1256
     * Decode the string from hex.
1257
     *
1258
     * @psalm-mutation-free
1259
     *
1260
     * @return static
1261
     */
1262 2
    public function hexDecode(): self
1263
    {
1264 2
        $string = \preg_replace_callback(
1265 2
            '/\\\\x([0-9A-Fa-f]+)/',
1266
            function (array $matched) {
1267 2
                return (string) $this->utf8::hex_to_chr($matched[1]);
1268 2
            },
1269 2
            $this->str
1270
        );
1271
1272 2
        return static::create(
1273 2
            $string,
1274 2
            $this->encoding
1275
        );
1276
    }
1277
1278
    /**
1279
     * Encode string to hex.
1280
     *
1281
     * @psalm-mutation-free
1282
     *
1283
     * @return static
1284
     */
1285 2
    public function hexEncode(): self
1286
    {
1287 2
        $string = \array_reduce(
1288 2
            $this->chars(),
1289
            function (string $str, string $char) {
1290 2
                return $str . $this->utf8::chr_to_hex($char);
1291 2
            },
1292 2
            ''
1293
        );
1294
1295 2
        return static::create(
1296 2
            $string,
1297 2
            $this->encoding
1298
        );
1299
    }
1300
1301
    /**
1302
     * Convert all HTML entities to their applicable characters.
1303
     *
1304
     * @param int $flags [optional] <p>
1305
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1306
     *                   which document type to use. The default is ENT_COMPAT.
1307
     *                   <table>
1308
     *                   Available <i>flags</i> constants
1309
     *                   <tr valign="top">
1310
     *                   <td>Constant Name</td>
1311
     *                   <td>Description</td>
1312
     *                   </tr>
1313
     *                   <tr valign="top">
1314
     *                   <td><b>ENT_COMPAT</b></td>
1315
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1316
     *                   </tr>
1317
     *                   <tr valign="top">
1318
     *                   <td><b>ENT_QUOTES</b></td>
1319
     *                   <td>Will convert both double and single quotes.</td>
1320
     *                   </tr>
1321
     *                   <tr valign="top">
1322
     *                   <td><b>ENT_NOQUOTES</b></td>
1323
     *                   <td>Will leave both double and single quotes unconverted.</td>
1324
     *                   </tr>
1325
     *                   <tr valign="top">
1326
     *                   <td><b>ENT_HTML401</b></td>
1327
     *                   <td>
1328
     *                   Handle code as HTML 4.01.
1329
     *                   </td>
1330
     *                   </tr>
1331
     *                   <tr valign="top">
1332
     *                   <td><b>ENT_XML1</b></td>
1333
     *                   <td>
1334
     *                   Handle code as XML 1.
1335
     *                   </td>
1336
     *                   </tr>
1337
     *                   <tr valign="top">
1338
     *                   <td><b>ENT_XHTML</b></td>
1339
     *                   <td>
1340
     *                   Handle code as XHTML.
1341
     *                   </td>
1342
     *                   </tr>
1343
     *                   <tr valign="top">
1344
     *                   <td><b>ENT_HTML5</b></td>
1345
     *                   <td>
1346
     *                   Handle code as HTML 5.
1347
     *                   </td>
1348
     *                   </tr>
1349
     *                   </table>
1350
     *                   </p>
1351
     *
1352
     * @psalm-mutation-free
1353
     *
1354
     * @return static
1355
     *                <p>Object with the resulting $str after being html decoded.</p>
1356
     */
1357 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...
1358
    {
1359 15
        return static::create(
1360 15
            $this->utf8::html_entity_decode(
1361 15
                $this->str,
1362 15
                $flags,
1363 15
                $this->encoding
1364
            ),
1365 15
            $this->encoding
1366
        );
1367
    }
1368
1369
    /**
1370
     * Convert all applicable characters to HTML entities.
1371
     *
1372
     * @param int $flags [optional] <p>
1373
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1374
     *                   which document type to use. The default is ENT_COMPAT.
1375
     *                   <table>
1376
     *                   Available <i>flags</i> constants
1377
     *                   <tr valign="top">
1378
     *                   <td>Constant Name</td>
1379
     *                   <td>Description</td>
1380
     *                   </tr>
1381
     *                   <tr valign="top">
1382
     *                   <td><b>ENT_COMPAT</b></td>
1383
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1384
     *                   </tr>
1385
     *                   <tr valign="top">
1386
     *                   <td><b>ENT_QUOTES</b></td>
1387
     *                   <td>Will convert both double and single quotes.</td>
1388
     *                   </tr>
1389
     *                   <tr valign="top">
1390
     *                   <td><b>ENT_NOQUOTES</b></td>
1391
     *                   <td>Will leave both double and single quotes unconverted.</td>
1392
     *                   </tr>
1393
     *                   <tr valign="top">
1394
     *                   <td><b>ENT_HTML401</b></td>
1395
     *                   <td>
1396
     *                   Handle code as HTML 4.01.
1397
     *                   </td>
1398
     *                   </tr>
1399
     *                   <tr valign="top">
1400
     *                   <td><b>ENT_XML1</b></td>
1401
     *                   <td>
1402
     *                   Handle code as XML 1.
1403
     *                   </td>
1404
     *                   </tr>
1405
     *                   <tr valign="top">
1406
     *                   <td><b>ENT_XHTML</b></td>
1407
     *                   <td>
1408
     *                   Handle code as XHTML.
1409
     *                   </td>
1410
     *                   </tr>
1411
     *                   <tr valign="top">
1412
     *                   <td><b>ENT_HTML5</b></td>
1413
     *                   <td>
1414
     *                   Handle code as HTML 5.
1415
     *                   </td>
1416
     *                   </tr>
1417
     *                   </table>
1418
     *                   </p>
1419
     *
1420
     * @psalm-mutation-free
1421
     *
1422
     * @return static
1423
     *                <p>Object with the resulting $str after being html encoded.</p>
1424
     */
1425 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...
1426
    {
1427 15
        return static::create(
1428 15
            $this->utf8::htmlentities(
1429 15
                $this->str,
1430 15
                $flags,
1431 15
                $this->encoding
1432
            ),
1433 15
            $this->encoding
1434
        );
1435
    }
1436
1437
    /**
1438
     * Capitalizes the first word of the string, replaces underscores with
1439
     * spaces, and strips '_id'.
1440
     *
1441
     * @psalm-mutation-free
1442
     *
1443
     * @return static
1444
     *                <p>Object with a humanized $str.</p>
1445
     */
1446 9
    public function humanize(): self
1447
    {
1448 9
        return static::create(
1449 9
            $this->utf8::str_humanize($this->str),
1450 9
            $this->encoding
1451
        );
1452
    }
1453
1454
    /**
1455
     * Determine if the current string exists in another string. By
1456
     * default, the comparison is case-sensitive, but can be made insensitive
1457
     * by setting $caseSensitive to false.
1458
     *
1459
     * @param string $str           <p>The string to compare against.</p>
1460
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1461
     *
1462
     * @psalm-mutation-free
1463
     *
1464
     * @return bool
1465
     */
1466 3
    public function in(string $str, bool $caseSensitive = true): bool
1467
    {
1468 3
        if ($caseSensitive) {
1469 2
            return \strpos($str, $this->str) !== false;
1470
        }
1471
1472 1
        return \stripos($str, $this->str) !== false;
1473
    }
1474
1475
    /**
1476
     * Returns the index of the first occurrence of $needle in the string,
1477
     * and false if not found. Accepts an optional offset from which to begin
1478
     * the search.
1479
     *
1480
     * @param string $needle <p>Substring to look for.</p>
1481
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1482
     *
1483
     * @psalm-mutation-free
1484
     *
1485
     * @return false|int
1486
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1487
     */
1488 31
    public function indexOf(string $needle, int $offset = 0)
1489
    {
1490 31
        return $this->utf8::strpos(
1491 31
            $this->str,
1492 31
            $needle,
1493 31
            $offset,
1494 31
            $this->encoding
1495
        );
1496
    }
1497
1498
    /**
1499
     * Returns the index of the first occurrence of $needle in the string,
1500
     * and false if not found. Accepts an optional offset from which to begin
1501
     * the search.
1502
     *
1503
     * @param string $needle <p>Substring to look for.</p>
1504
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1505
     *
1506
     * @psalm-mutation-free
1507
     *
1508
     * @return false|int
1509
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1510
     */
1511 20
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
1512
    {
1513 20
        return $this->utf8::stripos(
1514 20
            $this->str,
1515 20
            $needle,
1516 20
            $offset,
1517 20
            $this->encoding
1518
        );
1519
    }
1520
1521
    /**
1522
     * Returns the index of the last occurrence of $needle in the string,
1523
     * and false if not found. Accepts an optional offset from which to begin
1524
     * the search. Offsets may be negative to count from the last character
1525
     * in the string.
1526
     *
1527
     * @param string $needle <p>Substring to look for.</p>
1528
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1529
     *
1530
     * @psalm-mutation-free
1531
     *
1532
     * @return false|int
1533
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1534
     */
1535 31
    public function indexOfLast(string $needle, int $offset = 0)
1536
    {
1537 31
        return $this->utf8::strrpos(
1538 31
            $this->str,
1539 31
            $needle,
1540 31
            $offset,
1541 31
            $this->encoding
1542
        );
1543
    }
1544
1545
    /**
1546
     * Returns the index of the last occurrence of $needle in the string,
1547
     * and false if not found. Accepts an optional offset from which to begin
1548
     * the search. Offsets may be negative to count from the last character
1549
     * in the string.
1550
     *
1551
     * @param string $needle <p>Substring to look for.</p>
1552
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1553
     *
1554
     * @psalm-mutation-free
1555
     *
1556
     * @return false|int
1557
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1558
     */
1559 20
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
1560
    {
1561 20
        return $this->utf8::strripos(
1562 20
            $this->str,
1563 20
            $needle,
1564 20
            $offset,
1565 20
            $this->encoding
1566
        );
1567
    }
1568
1569
    /**
1570
     * Inserts $substring into the string at the $index provided.
1571
     *
1572
     * @param string $substring <p>String to be inserted.</p>
1573
     * @param int    $index     <p>The index at which to insert the substring.</p>
1574
     *
1575
     * @psalm-mutation-free
1576
     *
1577
     * @return static
1578
     *                <p>Object with the resulting $str after the insertion.</p>
1579
     */
1580 24
    public function insert(string $substring, int $index): self
1581
    {
1582 24
        return static::create(
1583 24
            $this->utf8::str_insert(
1584 24
                $this->str,
1585 24
                $substring,
1586 24
                $index,
1587 24
                $this->encoding
1588
            ),
1589 24
            $this->encoding
1590
        );
1591
    }
1592
1593
    /**
1594
     * Returns true if the string contains the $pattern, otherwise false.
1595
     *
1596
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
1597
     * expression wildcards.
1598
     *
1599
     * @credit Originally from Laravel, thanks Taylor.
1600
     *
1601
     * @param string $pattern <p>The string or pattern to match against.</p>
1602
     *
1603
     * @psalm-mutation-free
1604
     *
1605
     * @return bool
1606
     *              <p>Whether or not we match the provided pattern.</p>
1607
     */
1608 26
    public function is(string $pattern): bool
1609
    {
1610 26
        if ($this->toString() === $pattern) {
1611 2
            return true;
1612
        }
1613
1614 24
        $quotedPattern = \preg_quote($pattern, '/');
1615 24
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
1616
1617 24
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
1618
    }
1619
1620
    /**
1621
     * Returns true if the string contains only alphabetic chars, false otherwise.
1622
     *
1623
     * @psalm-mutation-free
1624
     *
1625
     * @return bool
1626
     *              <p>Whether or not $str contains only alphabetic chars.</p>
1627
     */
1628 30
    public function isAlpha(): bool
1629
    {
1630 30
        return $this->utf8::is_alpha($this->str);
1631
    }
1632
1633
    /**
1634
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
1635
     *
1636
     * @psalm-mutation-free
1637
     *
1638
     * @return bool
1639
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
1640
     */
1641 39
    public function isAlphanumeric(): bool
1642
    {
1643 39
        return $this->utf8::is_alphanumeric($this->str);
1644
    }
1645
1646
    /**
1647
     * Determine if the string is composed of punctuation characters.
1648
     *
1649
     * @psalm-mutation-free
1650
     *
1651
     * @return bool
1652
     */
1653 3
    public function isPunctuation(): bool
1654
    {
1655 3
        return $this->utf8::is_punctuation($this->str);
1656
    }
1657
1658
    /**
1659
     * Determine if the string is composed of printable (non-invisible) characters.
1660
     *
1661
     * @psalm-mutation-free
1662
     *
1663
     * @return bool
1664
     */
1665 3
    public function isPrintable(): bool
1666
    {
1667 3
        return $this->utf8::is_printable($this->str);
1668
    }
1669
1670
    /**
1671
     * Returns true if the string is base64 encoded, false otherwise.
1672
     *
1673
     * @param bool $emptyStringIsValid
1674
     *
1675
     * @psalm-mutation-free
1676
     *
1677
     * @return bool
1678
     *              <p>Whether or not $str is base64 encoded.</p>
1679
     */
1680 21
    public function isBase64($emptyStringIsValid = true): bool
1681
    {
1682 21
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
1683
    }
1684
1685
    /**
1686
     * Returns true if the string contains only whitespace chars, false otherwise.
1687
     *
1688
     * @psalm-mutation-free
1689
     *
1690
     * @return bool
1691
     *              <p>Whether or not $str contains only whitespace characters.</p>
1692
     */
1693 45
    public function isBlank(): bool
1694
    {
1695 45
        return $this->utf8::is_blank($this->str);
1696
    }
1697
1698
    /**
1699
     * Returns true if the string contains a valid E-Mail address, false otherwise.
1700
     *
1701
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
1702
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
1703
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
1704
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
1705
     *
1706
     * @psalm-mutation-free
1707
     *
1708
     * @return bool
1709
     *              <p>Whether or not $str contains a valid E-Mail address.</p>
1710
     */
1711 2
    public function isEmail(
1712
        bool $useExampleDomainCheck = false,
1713
        bool $useTypoInDomainCheck = false,
1714
        bool $useTemporaryDomainCheck = false,
1715
        bool $useDnsCheck = false
1716
    ): bool {
1717
        /**
1718
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the email-check class
1719
         */
1720 2
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
1721
    }
1722
1723
    /**
1724
     * Determine whether the string is considered to be empty.
1725
     *
1726
     * A variable is considered empty if it does not exist or if its value equals FALSE.
1727
     *
1728
     * @psalm-mutation-free
1729
     *
1730
     * @return bool
1731
     *              <p>Whether or not $str is empty().</p>
1732
     */
1733 10
    public function isEmpty(): bool
1734
    {
1735 10
        return $this->utf8::is_empty($this->str);
1736
    }
1737
1738
    /**
1739
     * Determine whether the string is equals to $str.
1740
     * Alias for isEqualsCaseSensitive()
1741
     *
1742
     * @param string|Stringy ...$str
1743
     *
1744
     * @psalm-mutation-free
1745
     *
1746
     * @return bool
1747
     */
1748 13
    public function isEquals(...$str): bool
1749
    {
1750 13
        return $this->isEqualsCaseSensitive(...$str);
1751
    }
1752
1753
    /**
1754
     * Determine whether the string is equals to $str.
1755
     *
1756
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
1757
     *
1758
     * @psalm-mutation-free
1759
     *
1760
     * @return bool
1761
     *              <p>Whether or not $str is equals.</p>
1762
     */
1763 3
    public function isEqualsCaseInsensitive(...$str): bool
1764
    {
1765 3
        $strUpper = $this->toUpperCase()->str;
1766
1767 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...
1768
            /**
1769
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
1770
             */
1771 3
            if ($strTmp instanceof self) {
1772
                if ($strUpper !== $strTmp->toUpperCase()) {
1773
                    return false;
1774
                }
1775 3
            } elseif (\is_scalar($strTmp)) {
1776 3
                if ($strUpper !== $this->utf8::strtoupper((string) $strTmp, $this->encoding)) {
1777 3
                    return false;
1778
                }
1779
            } else {
1780
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
1781
            }
1782
        }
1783
1784 3
        return true;
1785
    }
1786
1787
    /**
1788
     * Determine whether the string is equals to $str.
1789
     *
1790
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
1791
     *
1792
     * @psalm-mutation-free
1793
     *
1794
     * @return bool
1795
     *              <p>Whether or not $str is equals.</p>
1796
     */
1797 14
    public function isEqualsCaseSensitive(...$str): bool
1798
    {
1799 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...
1800
            /**
1801
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
1802
             */
1803 14
            if ($strTmp instanceof self) {
1804 2
                if ($this->str !== $strTmp->str) {
1805 2
                    return false;
1806
                }
1807 12
            } elseif (\is_scalar($strTmp)) {
1808 12
                if ($this->str !== (string) $strTmp) {
1809 12
                    return false;
1810
                }
1811
            } else {
1812
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
1813
            }
1814
        }
1815
1816 3
        return true;
1817
    }
1818
1819
    /**
1820
     * Returns true if the string contains only hexadecimal chars, false otherwise.
1821
     *
1822
     * @psalm-mutation-free
1823
     *
1824
     * @return bool
1825
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
1826
     */
1827 39
    public function isHexadecimal(): bool
1828
    {
1829 39
        return $this->utf8::is_hexadecimal($this->str);
1830
    }
1831
1832
    /**
1833
     * Returns true if the string contains HTML-Tags, false otherwise.
1834
     *
1835
     * @psalm-mutation-free
1836
     *
1837
     * @return bool
1838
     *              <p>Whether or not $str contains HTML-Tags.</p>
1839
     */
1840 2
    public function isHtml(): bool
1841
    {
1842 2
        return $this->utf8::is_html($this->str);
1843
    }
1844
1845
    /**
1846
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
1847
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
1848
     * in that an empty string is not considered valid JSON.
1849
     *
1850
     * @param bool $onlyArrayOrObjectResultsAreValid
1851
     *
1852
     * @psalm-mutation-free
1853
     *
1854
     * @return bool
1855
     *              <p>Whether or not $str is JSON.</p>
1856
     */
1857 60
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
1858
    {
1859
        /**
1860
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff?
1861
         */
1862 60
        return $this->utf8::is_json(
1863 60
            $this->str,
1864 60
            $onlyArrayOrObjectResultsAreValid
1865
        );
1866
    }
1867
1868
    /**
1869
     * Determine if the string is composed of numeric characters.
1870
     *
1871
     * @psalm-mutation-free
1872
     *
1873
     * @return bool
1874
     */
1875 4
    public function isNumeric(): bool
1876
    {
1877 4
        return \is_numeric($this->str);
1878
    }
1879
1880
    /**
1881
     * Returns true if the string contains only lower case chars, false otherwise.
1882
     *
1883
     * @psalm-mutation-free
1884
     *
1885
     * @return bool
1886
     *              <p>Whether or not $str contains only lower case characters.</p>
1887
     */
1888 24
    public function isLowerCase(): bool
1889
    {
1890 24
        return $this->utf8::is_lowercase($this->str);
1891
    }
1892
1893
    /**
1894
     * Determine whether the string is considered to be NOT empty.
1895
     *
1896
     * A variable is considered NOT empty if it does exist or if its value equals TRUE.
1897
     *
1898
     * @psalm-mutation-free
1899
     *
1900
     * @return bool
1901
     *              <p>Whether or not $str is empty().</p>
1902
     */
1903 10
    public function isNotEmpty(): bool
1904
    {
1905 10
        return !$this->utf8::is_empty($this->str);
1906
    }
1907
1908
    /**
1909
     * Returns true if the string is serialized, false otherwise.
1910
     *
1911
     * @psalm-mutation-free
1912
     *
1913
     * @return bool
1914
     *              <p>Whether or not $str is serialized.</p>
1915
     */
1916 21
    public function isSerialized(): bool
1917
    {
1918 21
        return $this->utf8::is_serialized($this->str);
1919
    }
1920
1921
    /**
1922
     * Check if two strings are similar.
1923
     *
1924
     * @param string $str                     <p>The string to compare against.</p>
1925
     * @param float  $minPercentForSimilarity [optional] <p>The percentage of needed similarity. | Default: 80%</p>
1926
     *
1927
     * @psalm-mutation-free
1928
     *
1929
     * @return bool
1930
     */
1931 2
    public function isSimilar(string $str, float $minPercentForSimilarity = 80.0): bool
1932
    {
1933 2
        return $this->similarity($str) >= $minPercentForSimilarity;
1934
    }
1935
1936
    /**
1937
     * Returns true if the string contains only lower case chars, false
1938
     * otherwise.
1939
     *
1940
     * @psalm-mutation-free
1941
     *
1942
     * @return bool
1943
     *              <p>Whether or not $str contains only lower case characters.</p>
1944
     */
1945 24
    public function isUpperCase(): bool
1946
    {
1947 24
        return $this->utf8::is_uppercase($this->str);
1948
    }
1949
1950
    /**
1951
     * Returns true if the string contains only whitespace chars, false otherwise.
1952
     *
1953
     * @psalm-mutation-free
1954
     *
1955
     * @return bool
1956
     *              <p>Whether or not $str contains only whitespace characters.</p>
1957
     */
1958 30
    public function isWhitespace(): bool
1959
    {
1960 30
        return $this->isBlank();
1961
    }
1962
1963
    /**
1964
     * Returns value which can be serialized by json_encode().
1965
     *
1966
     * @noinspection ReturnTypeCanBeDeclaredInspection
1967
     *
1968
     * @psalm-mutation-free
1969
     *
1970
     * @return string The current value of the $str property
1971
     */
1972 2
    public function jsonSerialize()
1973
    {
1974 2
        return (string) $this;
1975
    }
1976
1977
    /**
1978
     * Returns the last $n characters of the string.
1979
     *
1980
     * @param int $n <p>Number of characters to retrieve from the end.</p>
1981
     *
1982
     * @psalm-mutation-free
1983
     *
1984
     * @return static
1985
     *                <p>Object with its $str being the last $n chars.</p>
1986
     */
1987 36
    public function last(int $n): self
1988
    {
1989 36
        return static::create(
1990 36
            $this->utf8::str_last_char(
1991 36
                $this->str,
1992 36
                $n,
1993 36
                $this->encoding
1994
            ),
1995 36
            $this->encoding
1996
        );
1997
    }
1998
1999
    /**
2000
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2001
     * If no match is found returns new empty Stringy object.
2002
     *
2003
     * @param string $needle       <p>The string to look for.</p>
2004
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2005
     *
2006
     * @psalm-mutation-free
2007
     *
2008
     * @return static
2009
     */
2010 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...
2011
    {
2012 4
        return static::create(
2013 4
            $this->utf8::str_substr_last(
2014 4
                $this->str,
2015 4
                $needle,
2016 4
                $beforeNeedle,
2017 4
                $this->encoding
2018
            ),
2019 4
            $this->encoding
2020
        );
2021
    }
2022
2023
    /**
2024
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2025
     * If no match is found returns new empty Stringy object.
2026
     *
2027
     * @param string $needle       <p>The string to look for.</p>
2028
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2029
     *
2030
     * @psalm-mutation-free
2031
     *
2032
     * @return static
2033
     */
2034 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...
2035
    {
2036 2
        return static::create(
2037 2
            $this->utf8::str_isubstr_last(
2038 2
                $this->str,
2039 2
                $needle,
2040 2
                $beforeNeedle,
2041 2
                $this->encoding
2042
            ),
2043 2
            $this->encoding
2044
        );
2045
    }
2046
2047
    /**
2048
     * Returns the length of the string.
2049
     *
2050
     * @psalm-mutation-free
2051
     *
2052
     * @return int
2053
     *             <p>The number of characters in $str given the encoding.</p>
2054
     */
2055 17
    public function length(): int
2056
    {
2057 17
        return (int) $this->utf8::strlen($this->str, $this->encoding);
2058
    }
2059
2060
    /**
2061
     * Line-Wrap the string after $limit, but also after the next word.
2062
     *
2063
     * @param int         $limit           [optional] <p>The column width.</p>
2064
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2065
     * @param bool        $add_final_break [optional] <p>
2066
     *                                     If this flag is true, then the method will add a $break at the end
2067
     *                                     of the result string.
2068
     *                                     </p>
2069
     * @param string|null $delimiter       [optional] <p>
2070
     *                                     You can change the default behavior, where we split the string by newline.
2071
     *                                     </p>
2072
     *
2073
     * @psalm-mutation-free
2074
     *
2075
     * @return static
2076
     */
2077 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...
2078
        int $limit,
2079
        string $break = "\n",
2080
        bool $add_final_break = true,
2081
        string $delimiter = null
2082
    ): self {
2083 3
        return static::create(
2084 3
            $this->utf8::wordwrap_per_line(
2085 3
                $this->str,
2086 3
                $limit,
2087 3
                $break,
2088 3
                true,
2089 3
                $add_final_break,
2090 3
                $delimiter
2091
            ),
2092 3
            $this->encoding
2093
        );
2094
    }
2095
2096
    /**
2097
     * Line-Wrap the string after $limit, but also after the next word.
2098
     *
2099
     * @param int         $limit           [optional] <p>The column width.</p>
2100
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2101
     * @param bool        $add_final_break [optional] <p>
2102
     *                                     If this flag is true, then the method will add a $break at the end
2103
     *                                     of the result string.
2104
     *                                     </p>
2105
     * @param string|null $delimiter       [optional] <p>
2106
     *                                     You can change the default behavior, where we split the string by newline.
2107
     *                                     </p>
2108
     *
2109
     * @psalm-mutation-free
2110
     *
2111
     * @return static
2112
     */
2113 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...
2114
        int $limit,
2115
        string $break = "\n",
2116
        bool $add_final_break = true,
2117
        string $delimiter = null
2118
    ): self {
2119 4
        return static::create(
2120 4
            $this->utf8::wordwrap_per_line(
2121 4
                $this->str,
2122 4
                $limit,
2123 4
                $break,
2124 4
                false,
2125 4
                $add_final_break,
2126 4
                $delimiter
2127
            ),
2128 4
            $this->encoding
2129
        );
2130
    }
2131
2132
    /**
2133
     * Splits on newlines and carriage returns, returning an array of Stringy
2134
     * objects corresponding to the lines in the string.
2135
     *
2136
     * @param bool $return_stingy_collection [optional] <p>Return a collection object.</p>
2137
     *
2138
     * @psalm-mutation-free
2139
     *
2140
     * @return CollectionStringy|static[]
2141
     *                                    <p>An collection of Stringy objects.</p>
2142
     *
2143
     * @psalm-return CollectionStringy<int,static>|array<int,static>
2144
     */
2145 51
    public function lines(bool $return_stingy_collection = false)
2146
    {
2147 51
        if ($this->str === '') {
2148 3
            if ($return_stingy_collection) {
2149
                /**
2150
                 * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
2151
                 */
2152 3
                return CollectionStringy::create([static::create('')]);
2153
            }
2154
2155
            return [static::create('')];
2156
        }
2157
2158 48
        $array = $this->utf8::str_to_lines($this->str);
2159
        /** @noinspection AlterInForeachInspection */
2160 48
        foreach ($array as $i => &$value) {
2161 48
            $value = static::create($value, $this->encoding);
2162
        }
2163
2164
        /** @noinspection PhpSillyAssignmentInspection */
2165
        /** @var static[] $array */
2166 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...
2167
2168 48
        if ($return_stingy_collection) {
2169
            /**
2170
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
2171
             */
2172 48
            return CollectionStringy::create($array);
2173
        }
2174
2175
        return $array;
2176
    }
2177
2178
    /**
2179
     * Returns the longest common prefix between the string and $otherStr.
2180
     *
2181
     * @param string $otherStr <p>Second string for comparison.</p>
2182
     *
2183
     * @psalm-mutation-free
2184
     *
2185
     * @return static
2186
     *                <p>Object with its $str being the longest common prefix.</p>
2187
     */
2188 30
    public function longestCommonPrefix(string $otherStr): self
2189
    {
2190 30
        return static::create(
2191 30
            $this->utf8::str_longest_common_prefix(
2192 30
                $this->str,
2193 30
                $otherStr,
2194 30
                $this->encoding
2195
            ),
2196 30
            $this->encoding
2197
        );
2198
    }
2199
2200
    /**
2201
     * Returns the longest common substring between the string and $otherStr.
2202
     * In the case of ties, it returns that which occurs first.
2203
     *
2204
     * @param string $otherStr <p>Second string for comparison.</p>
2205
     *
2206
     * @psalm-mutation-free
2207
     *
2208
     * @return static
2209
     *                <p>Object with its $str being the longest common substring.</p>
2210
     */
2211 30
    public function longestCommonSubstring(string $otherStr): self
2212
    {
2213 30
        return static::create(
2214 30
            $this->utf8::str_longest_common_substring(
2215 30
                $this->str,
2216 30
                $otherStr,
2217 30
                $this->encoding
2218
            ),
2219 30
            $this->encoding
2220
        );
2221
    }
2222
2223
    /**
2224
     * Returns the longest common suffix between the string and $otherStr.
2225
     *
2226
     * @param string $otherStr <p>Second string for comparison.</p>
2227
     *
2228
     * @psalm-mutation-free
2229
     *
2230
     * @return static
2231
     *                <p>Object with its $str being the longest common suffix.</p>
2232
     */
2233 30
    public function longestCommonSuffix(string $otherStr): self
2234
    {
2235 30
        return static::create(
2236 30
            $this->utf8::str_longest_common_suffix(
2237 30
                $this->str,
2238 30
                $otherStr,
2239 30
                $this->encoding
2240
            ),
2241 30
            $this->encoding
2242
        );
2243
    }
2244
2245
    /**
2246
     * Converts the first character of the string to lower case.
2247
     *
2248
     * @psalm-mutation-free
2249
     *
2250
     * @return static
2251
     *                <p>Object with the first character of $str being lower case.</p>
2252
     */
2253 15
    public function lowerCaseFirst(): self
2254
    {
2255 15
        return static::create(
2256 15
            $this->utf8::lcfirst($this->str, $this->encoding),
2257 15
            $this->encoding
2258
        );
2259
    }
2260
2261
    /**
2262
     * Determine if the string matches another string regardless of case.
2263
     * Alias for isEqualsCaseInsensitive()
2264
     *
2265
     * @psalm-mutation-free
2266
     *
2267
     * @param string|Stringy ...$str
2268
     *                               <p>The string to compare against.</p>
2269
     *
2270
     * @psalm-mutation-free
2271
     *
2272
     * @return bool
2273
     */
2274 3
    public function matchCaseInsensitive(...$str): bool
2275
    {
2276 3
        return $this->isEqualsCaseInsensitive(...$str);
2277
    }
2278
2279
    /**
2280
     * Determine if the string matches another string.
2281
     * Alias for isEqualsCaseSensitive()
2282
     *
2283
     * @psalm-mutation-free
2284
     *
2285
     * @param string|Stringy ...$str
2286
     *                               <p>The string to compare against.</p>
2287
     *
2288
     * @psalm-mutation-free
2289
     *
2290
     * @return bool
2291
     */
2292 7
    public function matchCaseSensitive(...$str): bool
2293
    {
2294 7
        return $this->isEqualsCaseSensitive(...$str);
2295
    }
2296
2297
    /**
2298
     * Create a md5 hash from the current string.
2299
     *
2300
     * @psalm-mutation-free
2301
     *
2302
     * @return static
2303
     */
2304 2
    public function md5(): self
2305
    {
2306 2
        return static::create($this->hash('md5'), $this->encoding);
2307
    }
2308
2309
    /**
2310
     * Get every nth character of the string.
2311
     *
2312
     * @param int $step   <p>The number of characters to step.</p>
2313
     * @param int $offset [optional] <p>The string offset to start at.</p>
2314
     *
2315
     * @psalm-mutation-free
2316
     *
2317
     * @return static
2318
     */
2319 4
    public function nth(int $step, int $offset = 0): self
2320
    {
2321 4
        $length = $step - 1;
2322 4
        $substring = $this->substr($offset)->toString();
2323
2324 4
        if ($substring === '') {
2325
            return new static('', $this->encoding);
2326
        }
2327
2328 4
        \preg_match_all(
2329 4
            "/(?:^|(?:.|\p{L}|\w){" . $length . "})(.|\p{L}|\w)/u",
2330 4
            $substring,
2331 4
            $matches
2332
        );
2333
2334 4
        return new static(\implode('', $matches[1] ?? []), $this->encoding);
2335
    }
2336
2337
    /**
2338
     * Returns whether or not a character exists at an index. Offsets may be
2339
     * negative to count from the last character in the string. Implements
2340
     * part of the ArrayAccess interface.
2341
     *
2342
     * @param int $offset <p>The index to check.</p>
2343
     *
2344
     * @psalm-mutation-free
2345
     *
2346
     * @return bool
2347
     *              <p>Whether or not the index exists.</p>
2348
     */
2349 18
    public function offsetExists($offset): bool
2350
    {
2351 18
        return $this->utf8::str_offset_exists(
2352 18
            $this->str,
2353 18
            $offset,
2354 18
            $this->encoding
2355
        );
2356
    }
2357
2358
    /**
2359
     * Returns the character at the given index. Offsets may be negative to
2360
     * count from the last character in the string. Implements part of the
2361
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
2362
     * does not exist.
2363
     *
2364
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
2365
     *
2366
     * @throws \OutOfBoundsException
2367
     *                               <p>If the positive or negative offset does not exist.</p>
2368
     *
2369
     * @return string
2370
     *                <p>The character at the specified index.</p>
2371
     *
2372
     * @psalm-mutation-free
2373
     */
2374 6
    public function offsetGet($offset): string
2375
    {
2376 6
        return $this->utf8::str_offset_get($this->str, $offset, $this->encoding);
2377
    }
2378
2379
    /**
2380
     * Implements part of the ArrayAccess interface, but throws an exception
2381
     * when called. This maintains the immutability of Stringy objects.
2382
     *
2383
     * @param int   $offset <p>The index of the character.</p>
2384
     * @param mixed $value  <p>Value to set.</p>
2385
     *
2386
     * @throws \Exception
2387
     *                    <p>When called.</p>
2388
     *
2389
     * @return void
2390
     */
2391 3
    public function offsetSet($offset, $value)
2392
    {
2393
        // Stringy is immutable, cannot directly set char
2394
        /** @noinspection ThrowRawExceptionInspection */
2395 3
        throw new \Exception('Stringy object is immutable, cannot modify char');
2396
    }
2397
2398
    /**
2399
     * Implements part of the ArrayAccess interface, but throws an exception
2400
     * when called. This maintains the immutability of Stringy objects.
2401
     *
2402
     * @param int $offset <p>The index of the character.</p>
2403
     *
2404
     * @throws \Exception
2405
     *                    <p>When called.</p>
2406
     *
2407
     * @return void
2408
     */
2409 3
    public function offsetUnset($offset)
2410
    {
2411
        // Don't allow directly modifying the string
2412
        /** @noinspection ThrowRawExceptionInspection */
2413 3
        throw new \Exception('Stringy object is immutable, cannot unset char');
2414
    }
2415
2416
    /**
2417
     * Pads the string to a given length with $padStr. If length is less than
2418
     * or equal to the length of the string, no padding takes places. The
2419
     * default string used for padding is a space, and the default type (one of
2420
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
2421
     * if $padType isn't one of those 3 values.
2422
     *
2423
     * @param int    $length  <p>Desired string length after padding.</p>
2424
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2425
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
2426
     *
2427
     * @throws \InvalidArgumentException
2428
     *                                   <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
2429
     *
2430
     * @return static
2431
     *                <p>Object with a padded $str.</p>
2432
     *
2433
     * @psalm-mutation-free
2434
     */
2435 39
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
2436
    {
2437 39
        return static::create(
2438 39
            $this->utf8::str_pad(
2439 39
                $this->str,
2440 39
                $length,
2441 39
                $padStr,
2442 39
                $padType,
2443 39
                $this->encoding
2444
            )
2445
        );
2446
    }
2447
2448
    /**
2449
     * Returns a new string of a given length such that both sides of the
2450
     * string are padded. Alias for pad() with a $padType of 'both'.
2451
     *
2452
     * @param int    $length <p>Desired string length after padding.</p>
2453
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2454
     *
2455
     * @psalm-mutation-free
2456
     *
2457
     * @return static
2458
     *                <p>String with padding applied.</p>
2459
     */
2460 33
    public function padBoth(int $length, string $padStr = ' '): self
2461
    {
2462 33
        return static::create(
2463 33
            $this->utf8::str_pad_both(
2464 33
                $this->str,
2465 33
                $length,
2466 33
                $padStr,
2467 33
                $this->encoding
2468
            )
2469
        );
2470
    }
2471
2472
    /**
2473
     * Returns a new string of a given length such that the beginning of the
2474
     * string is padded. Alias for pad() with a $padType of 'left'.
2475
     *
2476
     * @param int    $length <p>Desired string length after padding.</p>
2477
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2478
     *
2479
     * @psalm-mutation-free
2480
     *
2481
     * @return static
2482
     *                <p>String with left padding.</p>
2483
     */
2484 21
    public function padLeft(int $length, string $padStr = ' '): self
2485
    {
2486 21
        return static::create(
2487 21
            $this->utf8::str_pad_left(
2488 21
                $this->str,
2489 21
                $length,
2490 21
                $padStr,
2491 21
                $this->encoding
2492
            )
2493
        );
2494
    }
2495
2496
    /**
2497
     * Returns a new string of a given length such that the end of the string
2498
     * is padded. Alias for pad() with a $padType of 'right'.
2499
     *
2500
     * @param int    $length <p>Desired string length after padding.</p>
2501
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2502
     *
2503
     * @psalm-mutation-free
2504
     *
2505
     * @return static
2506
     *                <p>String with right padding.</p>
2507
     */
2508 21
    public function padRight(int $length, string $padStr = ' '): self
2509
    {
2510 21
        return static::create(
2511 21
            $this->utf8::str_pad_right(
2512 21
                $this->str,
2513 21
                $length,
2514 21
                $padStr,
2515 21
                $this->encoding
2516
            )
2517
        );
2518
    }
2519
2520
    /**
2521
     * Returns a new string starting with $prefix.
2522
     *
2523
     * @param string ...$prefix <p>The string to append.</p>
2524
     *
2525
     * @psalm-mutation-free
2526
     *
2527
     * @return static
2528
     *                <p>Object with appended $prefix.</p>
2529
     *
2530
     * @noinspection PhpDocSignatureInspection
2531
     */
2532 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...
2533
    {
2534 7
        if (\count($prefix) <= 1) {
2535
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
2536 6
            $prefix = $prefix[0];
2537
        } else {
2538
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
2539 1
            $prefix = \implode('', $prefix);
2540
        }
2541
2542 7
        return static::create($prefix . $this->str, $this->encoding);
2543
    }
2544
2545
    /**
2546
     * Replaces all occurrences of $pattern in $str by $replacement.
2547
     *
2548
     * @param string $pattern     <p>The regular expression pattern.</p>
2549
     * @param string $replacement <p>The string to replace with.</p>
2550
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
2551
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
2552
     *
2553
     * @psalm-mutation-free
2554
     *
2555
     * @return static
2556
     *                <p>Object with the result2ing $str after the replacements.</p>
2557
     */
2558 29
    public function regexReplace(string $pattern, string $replacement, string $options = '', string $delimiter = '/'): self
2559
    {
2560 29
        return static::create(
2561 29
            $this->utf8::regex_replace(
2562 29
                $this->str,
2563 29
                $pattern,
2564 29
                $replacement,
2565 29
                $options,
2566 29
                $delimiter
2567
            ),
2568 29
            $this->encoding
2569
        );
2570
    }
2571
2572
    /**
2573
     * Remove html via "strip_tags()" from the string.
2574
     *
2575
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
2576
     *                              not be stripped. Default: null
2577
     *                              </p>
2578
     *
2579
     * @psalm-mutation-free
2580
     *
2581
     * @return static
2582
     */
2583 12
    public function removeHtml(string $allowableTags = ''): self
2584
    {
2585 12
        return static::create(
2586 12
            $this->utf8::remove_html($this->str, $allowableTags),
2587 12
            $this->encoding
2588
        );
2589
    }
2590
2591
    /**
2592
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
2593
     *
2594
     * @param string $replacement [optional] <p>Default is a empty string.</p>
2595
     *
2596
     * @psalm-mutation-free
2597
     *
2598
     * @return static
2599
     */
2600 12
    public function removeHtmlBreak(string $replacement = ''): self
2601
    {
2602 12
        return static::create(
2603 12
            $this->utf8::remove_html_breaks($this->str, $replacement),
2604 12
            $this->encoding
2605
        );
2606
    }
2607
2608
    /**
2609
     * Returns a new string with the prefix $substring removed, if present.
2610
     *
2611
     * @param string $substring <p>The prefix to remove.</p>
2612
     *
2613
     * @psalm-mutation-free
2614
     *
2615
     * @return static
2616
     *                <p>Object having a $str without the prefix $substring.</p>
2617
     */
2618 36
    public function removeLeft(string $substring): self
2619
    {
2620 36
        return static::create(
2621 36
            $this->utf8::remove_left($this->str, $substring, $this->encoding),
2622 36
            $this->encoding
2623
        );
2624
    }
2625
2626
    /**
2627
     * Returns a new string with the suffix $substring removed, if present.
2628
     *
2629
     * @param string $substring <p>The suffix to remove.</p>
2630
     *
2631
     * @psalm-mutation-free
2632
     *
2633
     * @return static
2634
     *                <p>Object having a $str without the suffix $substring.</p>
2635
     */
2636 36
    public function removeRight(string $substring): self
2637
    {
2638 36
        return static::create(
2639 36
            $this->utf8::remove_right($this->str, $substring, $this->encoding),
2640 36
            $this->encoding
2641
        );
2642
    }
2643
2644
    /**
2645
     * Try to remove all XSS-attacks from the string.
2646
     *
2647
     * @psalm-mutation-free
2648
     *
2649
     * @return static
2650
     */
2651 12
    public function removeXss(): self
2652
    {
2653
        /**
2654
         * @var AntiXSS|null
2655
         *
2656
         * @psalm-suppress ImpureStaticVariable
2657
         */
2658 12
        static $antiXss = null;
2659
2660 12
        if ($antiXss === null) {
2661 1
            $antiXss = new AntiXSS();
2662
        }
2663
2664
        /**
2665
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the anti-xss class
2666
         */
2667 12
        $str = $antiXss->xss_clean($this->str);
2668
2669 12
        return static::create($str, $this->encoding);
2670
    }
2671
2672
    /**
2673
     * Returns a repeated string given a multiplier.
2674
     *
2675
     * @param int $multiplier <p>The number of times to repeat the string.</p>
2676
     *
2677
     * @psalm-mutation-free
2678
     *
2679
     * @return static
2680
     *                <p>Object with a repeated str.</p>
2681
     */
2682 21
    public function repeat(int $multiplier): self
2683
    {
2684 21
        return static::create(
2685 21
            \str_repeat($this->str, $multiplier),
2686 21
            $this->encoding
2687
        );
2688
    }
2689
2690
    /**
2691
     * Replaces all occurrences of $search in $str by $replacement.
2692
     *
2693
     * @param string $search        <p>The needle to search for.</p>
2694
     * @param string $replacement   <p>The string to replace with.</p>
2695
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
2696
     *
2697
     * @psalm-mutation-free
2698
     *
2699
     * @return static
2700
     *                <p>Object with the resulting $str after the replacements.</p>
2701
     */
2702 76
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
2703
    {
2704 76
        if ($search === '' && $replacement === '') {
2705 16
            return static::create($this->str, $this->encoding);
2706
        }
2707
2708 60
        if ($this->str === '' && $search === '') {
2709 2
            return static::create($replacement, $this->encoding);
2710
        }
2711
2712 58
        if ($caseSensitive) {
2713 48
            return static::create(
2714 48
                $this->utf8::str_replace($search, $replacement, $this->str),
2715 48
                $this->encoding
2716
            );
2717
        }
2718
2719 10
        return static::create(
2720 10
            $this->utf8::str_ireplace($search, $replacement, $this->str),
2721 10
            $this->encoding
2722
        );
2723
    }
2724
2725
    /**
2726
     * Replaces all occurrences of $search in $str by $replacement.
2727
     *
2728
     * @param string[]        $search        <p>The elements to search for.</p>
2729
     * @param string|string[] $replacement   <p>The string to replace with.</p>
2730
     * @param bool            $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
2731
     *
2732
     * @psalm-mutation-free
2733
     *
2734
     * @return static
2735
     *                <p>Object with the resulting $str after the replacements.</p>
2736
     */
2737 61
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
2738
    {
2739 61
        if ($caseSensitive) {
2740 47
            return static::create(
2741 47
                $this->utf8::str_replace($search, $replacement, $this->str),
2742 47
                $this->encoding
2743
            );
2744
        }
2745
2746 14
        return static::create(
2747 14
            $this->utf8::str_ireplace($search, $replacement, $this->str),
2748 14
            $this->encoding
2749
        );
2750
    }
2751
2752
    /**
2753
     * Replaces all occurrences of $search from the beginning of string with $replacement.
2754
     *
2755
     * @param string $search      <p>The string to search for.</p>
2756
     * @param string $replacement <p>The replacement.</p>
2757
     *
2758
     * @psalm-mutation-free
2759
     *
2760
     * @return static
2761
     *                <p>Object with the resulting $str after the replacements.</p>
2762
     */
2763 32
    public function replaceBeginning(string $search, string $replacement): self
2764
    {
2765 32
        return static::create(
2766 32
            $this->utf8::str_replace_beginning($this->str, $search, $replacement),
2767 32
            $this->encoding
2768
        );
2769
    }
2770
2771
    /**
2772
     * Replaces all occurrences of $search from the ending of string with $replacement.
2773
     *
2774
     * @param string $search      <p>The string to search for.</p>
2775
     * @param string $replacement <p>The replacement.</p>
2776
     *
2777
     * @psalm-mutation-free
2778
     *
2779
     * @return static
2780
     *                <p>Object with the resulting $str after the replacements.</p>
2781
     */
2782 32
    public function replaceEnding(string $search, string $replacement): self
2783
    {
2784 32
        return static::create(
2785 32
            $this->utf8::str_replace_ending($this->str, $search, $replacement),
2786 32
            $this->encoding
2787
        );
2788
    }
2789
2790
    /**
2791
     * Replaces first occurrences of $search from the beginning of string with $replacement.
2792
     *
2793
     * @param string $search      <p>The string to search for.</p>
2794
     * @param string $replacement <p>The replacement.</p>
2795
     *
2796
     * @psalm-mutation-free
2797
     *
2798
     * @return static
2799
     *                <p>Object with the resulting $str after the replacements.</p>
2800
     */
2801 32
    public function replaceFirst(string $search, string $replacement): self
2802
    {
2803 32
        return static::create(
2804 32
            $this->utf8::str_replace_first($search, $replacement, $this->str),
2805 32
            $this->encoding
2806
        );
2807
    }
2808
2809
    /**
2810
     * Replaces last occurrences of $search from the ending of string with $replacement.
2811
     *
2812
     * @param string $search      <p>The string to search for.</p>
2813
     * @param string $replacement <p>The replacement.</p>
2814
     *
2815
     * @psalm-mutation-free
2816
     *
2817
     * @return static
2818
     *                <p>Object with the resulting $str after the replacements.</p>
2819
     */
2820 30
    public function replaceLast(string $search, string $replacement): self
2821
    {
2822 30
        return static::create(
2823 30
            $this->utf8::str_replace_last($search, $replacement, $this->str),
2824 30
            $this->encoding
2825
        );
2826
    }
2827
2828
    /**
2829
     * Returns a reversed string. A multibyte version of strrev().
2830
     *
2831
     * @psalm-mutation-free
2832
     *
2833
     * @return static
2834
     *                <p>Object with a reversed $str.</p>
2835
     */
2836 15
    public function reverse(): self
2837
    {
2838 15
        return static::create($this->utf8::strrev($this->str), $this->encoding);
2839
    }
2840
2841
    /**
2842
     * Truncates the string to a given length, while ensuring that it does not
2843
     * split words. If $substring is provided, and truncating occurs, the
2844
     * string is further truncated so that the substring may be appended without
2845
     * exceeding the desired length.
2846
     *
2847
     * @param int    $length                          <p>Desired length of the truncated string.</p>
2848
     * @param string $substring                       [optional] <p>The substring to append if it can fit. Default: ''</p>
2849
     * @param bool   $ignoreDoNotSplitWordsForOneWord
2850
     *
2851
     * @psalm-mutation-free
2852
     *
2853
     * @return static
2854
     *                <p>Object with the resulting $str after truncating.</p>
2855
     */
2856 68
    public function safeTruncate(
2857
        int $length,
2858
        string $substring = '',
2859
        bool $ignoreDoNotSplitWordsForOneWord = true
2860
    ): self {
2861 68
        return static::create(
2862 68
            $this->utf8::str_truncate_safe(
2863 68
                $this->str,
2864 68
                $length,
2865 68
                $substring,
2866 68
                $this->encoding,
2867 68
                $ignoreDoNotSplitWordsForOneWord
2868
            ),
2869 68
            $this->encoding
2870
        );
2871
    }
2872
2873
    /**
2874
     * Create a sha1 hash from the current string.
2875
     *
2876
     * @psalm-mutation-free
2877
     *
2878
     * @return static
2879
     */
2880 2
    public function sha1(): self
2881
    {
2882 2
        return static::create($this->hash('sha1'), $this->encoding);
2883
    }
2884
2885
    /**
2886
     * Create a sha256 hash from the current string.
2887
     *
2888
     * @psalm-mutation-free
2889
     *
2890
     * @return static
2891
     */
2892 2
    public function sha256(): self
2893
    {
2894 2
        return static::create($this->hash('sha256'), $this->encoding);
2895
    }
2896
2897
    /**
2898
     * Create a sha512 hash from the current string.
2899
     *
2900
     * @psalm-mutation-free
2901
     *
2902
     * @return static
2903
     */
2904 2
    public function sha512(): self
2905
    {
2906 2
        return static::create($this->hash('sha512'), $this->encoding);
2907
    }
2908
2909
    /**
2910
     * Shorten the string after $length, but also after the next word.
2911
     *
2912
     * @param int    $length   <p>The given length.</p>
2913
     * @param string $strAddOn [optional] <p>Default: '…'</p>
2914
     *
2915
     * @psalm-mutation-free
2916
     *
2917
     * @return static
2918
     */
2919 8
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
2920
    {
2921 8
        return static::create(
2922 8
            $this->utf8::str_limit_after_word($this->str, $length, $strAddOn),
2923 8
            $this->encoding
2924
        );
2925
    }
2926
2927
    /**
2928
     * A multibyte string shuffle function. It returns a string with its
2929
     * characters in random order.
2930
     *
2931
     * @psalm-mutation-free
2932
     *
2933
     * @return static
2934
     *                <p>Object with a shuffled $str.</p>
2935
     */
2936 9
    public function shuffle(): self
2937
    {
2938 9
        return static::create($this->utf8::str_shuffle($this->str), $this->encoding);
2939
    }
2940
2941
    /**
2942
     * Calculate the similarity between two strings.
2943
     *
2944
     * @param string $str <p>The delimiting string.</p>
2945
     *
2946
     * @psalm-mutation-free
2947
     *
2948
     * @return float
2949
     */
2950 2
    public function similarity(string $str): float
2951
    {
2952 2
        \similar_text($this->str, $str, $percent);
2953
2954 2
        return $percent;
2955
    }
2956
2957
    /**
2958
     * Returns the substring beginning at $start, and up to, but not including
2959
     * the index specified by $end. If $end is omitted, the function extracts
2960
     * the remaining string. If $end is negative, it is computed from the end
2961
     * of the string.
2962
     *
2963
     * @param int $start <p>Initial index from which to begin extraction.</p>
2964
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
2965
     *
2966
     * @psalm-mutation-free
2967
     *
2968
     * @return static
2969
     *                <p>Object with its $str being the extracted substring.</p>
2970
     */
2971 50
    public function slice(int $start, int $end = null): self
2972
    {
2973 50
        return static::create(
2974 50
            $this->utf8::str_slice($this->str, $start, $end, $this->encoding),
2975 50
            $this->encoding
2976
        );
2977
    }
2978
2979
    /**
2980
     * Converts the string into an URL slug. This includes replacing non-ASCII
2981
     * characters with their closest ASCII equivalents, removing remaining
2982
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
2983
     * $separator. The separator defaults to a single dash, and the string
2984
     * is also converted to lowercase. The language of the source string can
2985
     * also be supplied for language-specific transliteration.
2986
     *
2987
     * @param string                $separator             [optional] <p>The string used to replace whitespace.</p>
2988
     * @param string                $language              [optional] <p>Language of the source string.</p>
2989
     * @param array<string, string> $replacements          [optional] <p>A map of replaceable strings.</p>
2990
     * @param bool                  $replace_extra_symbols [optional]  <p>Add some more replacements e.g. "£" with "
2991
     *                                                     pound ".</p>
2992
     * @param bool                  $use_str_to_lower      [optional] <p>Use "string to lower" for the input.</p>
2993
     * @param bool                  $use_transliterate     [optional]  <p>Use ASCII::to_transliterate() for unknown
2994
     *                                                     chars.</p>
2995
     *
2996
     * @psalm-mutation-free
2997
     *
2998
     * @return static
2999
     *                <p>Object whose $str has been converted to an URL slug.</p>
3000
     *
3001
     * @noinspection PhpTooManyParametersInspection
3002
     */
3003 17
    public function slugify(
3004
        string $separator = '-',
3005
        string $language = 'en',
3006
        array $replacements = [],
3007
        bool $replace_extra_symbols = true,
3008
        bool $use_str_to_lower = true,
3009
        bool $use_transliterate = false
3010
    ): self {
3011 17
        return static::create(
3012 17
            $this->ascii::to_slugify(
3013 17
                $this->str,
3014 17
                $separator,
3015 17
                $language,
3016 17
                $replacements,
3017 17
                $replace_extra_symbols,
3018 17
                $use_str_to_lower,
3019 17
                $use_transliterate
3020
            ),
3021 17
            $this->encoding
3022
        );
3023
    }
3024
3025
    /**
3026
     * Convert a string to e.g.: "snake_case"
3027
     *
3028
     * @psalm-mutation-free
3029
     *
3030
     * @return static
3031
     *                <p>Object with $str in snake_case.</p>
3032
     */
3033 40
    public function snakeize(): self
3034
    {
3035 40
        return static::create(
3036 40
            $this->utf8::str_snakeize($this->str, $this->encoding),
3037 40
            $this->encoding
3038
        );
3039
    }
3040
3041
    /**
3042
     * Wrap the string after the first whitespace character after a given number
3043
     * of characters.
3044
     *
3045
     * @param int    $width <p>Number of characters at which to wrap.</p>
3046
     * @param string $break [optional] <p>Character used to break the string. | Default "\n"</p>
3047
     *
3048
     * @psalm-mutation-free
3049
     *
3050
     * @return static
3051
     */
3052 2
    public function softWrap(int $width, string $break = "\n"): self
3053
    {
3054 2
        return $this->lineWrapAfterWord($width, $break, false);
3055
    }
3056
3057
    /**
3058
     * Splits the string with the provided regular expression, returning an
3059
     * array of Stringy objects. An optional integer $limit will truncate the
3060
     * results.
3061
     *
3062
     * @param string $pattern                  <p>The regex with which to split the string.</p>
3063
     * @param int    $limit                    [optional] <p>Maximum number of results to return. Default: -1 === no
3064
     *                                         limit</p>
3065
     * @param bool   $return_stingy_collection [optional] <p>Return a collection object.</p>
3066
     *
3067
     * @psalm-mutation-free
3068
     *
3069
     * @return CollectionStringy|static[]
3070
     *                                    <p>An collection of Stringy objects.</p>
3071
     *
3072
     * @psalm-return CollectionStringy<int,static>|array<int,static>
3073
     */
3074 51
    public function split(
3075
        string $pattern,
3076
        int $limit = null,
3077
        bool $return_stingy_collection = false
3078
    ) {
3079 51
        if ($this->str === '') {
3080
            if ($return_stingy_collection) {
3081
                /**
3082
                 * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3083
                 */
3084
                return CollectionStringy::create([]);
3085
            }
3086
3087
            return [];
3088
        }
3089
3090 51
        if ($limit === null) {
3091 7
            $limit = -1;
3092
        }
3093
3094 51
        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
3095
        /** @noinspection AlterInForeachInspection */
3096 51
        foreach ($array as $i => &$value) {
3097 45
            $value = static::create($value, $this->encoding);
3098
        }
3099
3100
        /** @noinspection PhpSillyAssignmentInspection */
3101
        /** @var static[] $array */
3102 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...
3103
3104 51
        if ($return_stingy_collection) {
3105
            /**
3106
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3107
             */
3108 35
            return CollectionStringy::create($array);
3109
        }
3110
3111 16
        return $array;
3112
    }
3113
3114
    /**
3115
     * Returns true if the string begins with $substring, false otherwise. By
3116
     * default, the comparison is case-sensitive, but can be made insensitive
3117
     * by setting $caseSensitive to false.
3118
     *
3119
     * @param string $substring     <p>The substring to look for.</p>
3120
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3121
     *
3122
     * @psalm-mutation-free
3123
     *
3124
     * @return bool
3125
     *              <p>Whether or not $str starts with $substring.</p>
3126
     */
3127 99
    public function startsWith(string $substring, bool $caseSensitive = true): bool
3128
    {
3129 99
        if ($caseSensitive) {
3130 53
            return $this->utf8::str_starts_with($this->str, $substring);
3131
        }
3132
3133 46
        return $this->utf8::str_istarts_with($this->str, $substring);
3134
    }
3135
3136
    /**
3137
     * Returns true if the string begins with any of $substrings, false otherwise.
3138
     * By default the comparison is case-sensitive, but can be made insensitive by
3139
     * setting $caseSensitive to false.
3140
     *
3141
     * @param string[] $substrings    <p>Substrings to look for.</p>
3142
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3143
     *
3144
     * @psalm-mutation-free
3145
     *
3146
     * @return bool
3147
     *              <p>Whether or not $str starts with $substring.</p>
3148
     */
3149 35
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
3150
    {
3151 35
        if ($caseSensitive) {
3152 23
            return $this->utf8::str_starts_with_any($this->str, $substrings);
3153
        }
3154
3155 12
        return $this->utf8::str_istarts_with_any($this->str, $substrings);
3156
    }
3157
3158
    /**
3159
     * Remove one or more strings from the string.
3160
     *
3161
     * @param string|string[] $search One or more strings to be removed
3162
     *
3163
     * @psalm-mutation-free
3164
     *
3165
     * @return static
3166
     */
3167 3
    public function strip($search): self
3168
    {
3169 3
        if (\is_array($search)) {
3170 1
            return $this->replaceAll($search, '');
3171
        }
3172
3173 2
        return $this->replace($search, '');
3174
    }
3175
3176
    /**
3177
     * Strip all whitespace characters. This includes tabs and newline characters,
3178
     * as well as multibyte whitespace such as the thin space and ideographic space.
3179
     *
3180
     * @psalm-mutation-free
3181
     *
3182
     * @return static
3183
     */
3184 36
    public function stripWhitespace(): self
3185
    {
3186 36
        return static::create(
3187 36
            $this->utf8::strip_whitespace($this->str),
3188 36
            $this->encoding
3189
        );
3190
    }
3191
3192
    /**
3193
     * Remove css media-queries.
3194
     *
3195
     * @psalm-mutation-free
3196
     *
3197
     * @return static
3198
     */
3199 2
    public function stripeCssMediaQueries(): self
3200
    {
3201 2
        return static::create(
3202 2
            $this->utf8::css_stripe_media_queries($this->str),
3203 2
            $this->encoding
3204
        );
3205
    }
3206
3207
    /**
3208
     * Remove empty html-tag.
3209
     *
3210
     * e.g.: <tag></tag>
3211
     *
3212
     * @psalm-mutation-free
3213
     *
3214
     * @return static
3215
     */
3216 2
    public function stripeEmptyHtmlTags(): self
3217
    {
3218 2
        return static::create(
3219 2
            $this->utf8::html_stripe_empty_tags($this->str),
3220 2
            $this->encoding
3221
        );
3222
    }
3223
3224
    /**
3225
     * Returns the substring beginning at $start with the specified $length.
3226
     * It differs from the $this->utf8::substr() function in that providing a $length of
3227
     * null will return the rest of the string, rather than an empty string.
3228
     *
3229
     * @param int $start  <p>Position of the first character to use.</p>
3230
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
3231
     *
3232
     * @psalm-mutation-free
3233
     *
3234
     * @return static
3235
     *                <p>Object with its $str being the substring.</p>
3236
     */
3237 31
    public function substr(int $start, int $length = null): self
3238
    {
3239 31
        return static::create(
3240 31
            $this->utf8::substr(
3241 31
                $this->str,
3242 31
                $start,
3243 31
                $length,
3244 31
                $this->encoding
3245
            ),
3246 31
            $this->encoding
3247
        );
3248
    }
3249
3250
    /**
3251
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
3252
     * If no match is found returns new empty Stringy object.
3253
     *
3254
     * @param string $needle       <p>The string to look for.</p>
3255
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
3256
     *
3257
     * @psalm-mutation-free
3258
     *
3259
     * @return static
3260
     */
3261 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...
3262
    {
3263 4
        return static::create(
3264 4
            $this->utf8::str_substr_first(
3265 4
                $this->str,
3266 4
                $needle,
3267 4
                $beforeNeedle,
3268 4
                $this->encoding
3269
            ),
3270 4
            $this->encoding
3271
        );
3272
    }
3273
3274
    /**
3275
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
3276
     * If no match is found returns new empty Stringy object.
3277
     *
3278
     * @param string $needle       <p>The string to look for.</p>
3279
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
3280
     *
3281
     * @psalm-mutation-free
3282
     *
3283
     * @return static
3284
     */
3285 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...
3286
    {
3287 4
        return static::create(
3288 4
            $this->utf8::str_isubstr_first(
3289 4
                $this->str,
3290 4
                $needle,
3291 4
                $beforeNeedle,
3292 4
                $this->encoding
3293
            ),
3294 4
            $this->encoding
3295
        );
3296
    }
3297
3298
    /**
3299
     * Surrounds $str with the given substring.
3300
     *
3301
     * @param string $substring <p>The substring to add to both sides.</P>
3302
     *
3303
     * @psalm-mutation-free
3304
     *
3305
     * @return static
3306
     *                <p>Object whose $str had the substring both prepended and appended.</p>
3307
     */
3308 15
    public function surround(string $substring): self
3309
    {
3310 15
        return static::create(
3311 15
            $substring . $this->str . $substring,
3312 15
            $this->encoding
3313
        );
3314
    }
3315
3316
    /**
3317
     * Returns a case swapped version of the string.
3318
     *
3319
     * @psalm-mutation-free
3320
     *
3321
     * @return static
3322
     *                <p>Object whose $str has each character's case swapped.</P>
3323
     */
3324 15
    public function swapCase(): self
3325
    {
3326 15
        return static::create(
3327 15
            $this->utf8::swapCase($this->str, $this->encoding),
3328 15
            $this->encoding
3329
        );
3330
    }
3331
3332
    /**
3333
     * Returns a string with smart quotes, ellipsis characters, and dashes from
3334
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
3335
     * equivalents.
3336
     *
3337
     * @psalm-mutation-free
3338
     *
3339
     * @return static
3340
     *                <p>Object whose $str has those characters removed.</p>
3341
     */
3342 12
    public function tidy(): self
3343
    {
3344 12
        return static::create(
3345 12
            $this->ascii::normalize_msword($this->str),
3346 12
            $this->encoding
3347
        );
3348
    }
3349
3350
    /**
3351
     * Returns a trimmed string with the first letter of each word capitalized.
3352
     * Also accepts an array, $ignore, allowing you to list words not to be
3353
     * capitalized.
3354
     *
3355
     * @param array|string[]|null $ignore            [optional] <p>An array of words not to capitalize or null.
3356
     *                                               Default: null</p>
3357
     * @param string|null         $word_define_chars [optional] <p>An string of chars that will be used as whitespace
3358
     *                                               separator === words.</p>
3359
     * @param string|null         $language          [optional] <p>Language of the source string.</p>
3360
     *
3361
     * @psalm-mutation-free
3362
     *
3363
     * @return static
3364
     *                <p>Object with a titleized $str.</p>
3365
     */
3366 23
    public function titleize(
3367
        array $ignore = null,
3368
        string $word_define_chars = null,
3369
        string $language = null
3370
    ): self {
3371 23
        return static::create(
3372 23
            $this->utf8::str_titleize(
3373 23
                $this->str,
3374 23
                $ignore,
3375 23
                $this->encoding,
3376 23
                false,
3377 23
                $language,
3378 23
                false,
3379 23
                true,
3380 23
                $word_define_chars
3381
            ),
3382 23
            $this->encoding
3383
        );
3384
    }
3385
3386
    /**
3387
     * Returns a trimmed string in proper title case.
3388
     *
3389
     * Also accepts an array, $ignore, allowing you to list words not to be
3390
     * capitalized.
3391
     *
3392
     * Adapted from John Gruber's script.
3393
     *
3394
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
3395
     *
3396
     * @param string[] $ignore <p>An array of words not to capitalize.</p>
3397
     *
3398
     * @psalm-mutation-free
3399
     *
3400
     * @return static
3401
     *                <p>Object with a titleized $str</p>
3402
     */
3403 70
    public function titleizeForHumans(array $ignore = []): self
3404
    {
3405 70
        return static::create(
3406 70
            $this->utf8::str_titleize_for_humans(
3407 70
                $this->str,
3408 70
                $ignore,
3409 70
                $this->encoding
3410
            ),
3411 70
            $this->encoding
3412
        );
3413
    }
3414
3415
    /**
3416
     * Returns an ASCII version of the string. A set of non-ASCII characters are
3417
     * replaced with their closest ASCII counterparts, and the rest are removed
3418
     * by default. The language or locale of the source string can be supplied
3419
     * for language-specific transliteration in any of the following formats:
3420
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
3421
     * to "aeoeue" rather than "aou" as in other languages.
3422
     *
3423
     * @param string $language          [optional] <p>Language of the source string.</p>
3424
     * @param bool   $removeUnsupported [optional] <p>Whether or not to remove the
3425
     *                                  unsupported characters.</p>
3426
     *
3427
     * @psalm-mutation-free
3428
     *
3429
     * @return static
3430
     *                <p>Object whose $str contains only ASCII characters.</p>
3431
     */
3432 23
    public function toAscii(string $language = 'en', bool $removeUnsupported = true): self
3433
    {
3434 23
        return static::create(
3435 23
            $this->ascii::to_ascii(
3436 23
                $this->str,
3437 23
                $language,
3438 23
                $removeUnsupported
3439
            ),
3440 23
            $this->encoding
3441
        );
3442
    }
3443
3444
    /**
3445
     * Returns a boolean representation of the given logical string value.
3446
     * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
3447
     * 'off', and 'no' will return false. In all instances, case is ignored.
3448
     * For other numeric strings, their sign will determine the return value.
3449
     * In addition, blank strings consisting of only whitespace will return
3450
     * false. For all other strings, the return value is a result of a
3451
     * boolean cast.
3452
     *
3453
     * @psalm-mutation-free
3454
     *
3455
     * @return bool
3456
     *              <p>A boolean value for the string.</p>
3457
     */
3458 45
    public function toBoolean(): bool
3459
    {
3460 45
        return $this->utf8::to_boolean($this->str);
3461
    }
3462
3463
    /**
3464
     * Converts all characters in the string to lowercase.
3465
     *
3466
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
3467
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
3468
     *
3469
     * @psalm-mutation-free
3470
     *
3471
     * @return static
3472
     *                <p>Object with all characters of $str being lowercase.</p>
3473
     */
3474 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...
3475
    {
3476 17
        return static::create(
3477 17
            $this->utf8::strtolower(
3478 17
                $this->str,
3479 17
                $this->encoding,
3480 17
                false,
3481 17
                $lang,
3482 17
                $tryToKeepStringLength
3483
            ),
3484 17
            $this->encoding
3485
        );
3486
    }
3487
3488
    /**
3489
     * Converts each tab in the string to some number of spaces, as defined by
3490
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
3491
     *
3492
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
3493
     *
3494
     * @psalm-mutation-free
3495
     *
3496
     * @return static
3497
     *                <p>Object whose $str has had tabs switched to spaces.</p>
3498
     */
3499 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...
3500
    {
3501 18
        if ($tabLength === 4) {
3502 9
            $tab = '    ';
3503 9
        } elseif ($tabLength === 2) {
3504 3
            $tab = '  ';
3505
        } else {
3506 6
            $tab = \str_repeat(' ', $tabLength);
3507
        }
3508
3509 18
        return static::create(
3510 18
            \str_replace("\t", $tab, $this->str),
3511 18
            $this->encoding
3512
        );
3513
    }
3514
3515
    /**
3516
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
3517
     * string.
3518
     *
3519
     * @psalm-mutation-free
3520
     *
3521
     * @return string
3522
     */
3523 2183
    public function toString(): string
3524
    {
3525 2183
        return (string) $this->str;
3526
    }
3527
3528
    /**
3529
     * Converts each occurrence of some consecutive number of spaces, as
3530
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
3531
     * are converted to a tab.
3532
     *
3533
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
3534
     *
3535
     * @psalm-mutation-free
3536
     *
3537
     * @return static
3538
     *                <p>Object whose $str has had spaces switched to tabs.</p>
3539
     */
3540 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...
3541
    {
3542 15
        if ($tabLength === 4) {
3543 9
            $tab = '    ';
3544 6
        } elseif ($tabLength === 2) {
3545 3
            $tab = '  ';
3546
        } else {
3547 3
            $tab = \str_repeat(' ', $tabLength);
3548
        }
3549
3550 15
        return static::create(
3551 15
            \str_replace($tab, "\t", $this->str),
3552 15
            $this->encoding
3553
        );
3554
    }
3555
3556
    /**
3557
     * Converts the first character of each word in the string to uppercase
3558
     * and all other chars to lowercase.
3559
     *
3560
     * @psalm-mutation-free
3561
     *
3562
     * @return static
3563
     *                <p>Object with all characters of $str being title-cased.</p>
3564
     */
3565 15
    public function toTitleCase(): self
3566
    {
3567 15
        return static::create(
3568 15
            $this->utf8::titlecase($this->str, $this->encoding),
3569 15
            $this->encoding
3570
        );
3571
    }
3572
3573
    /**
3574
     * Returns an ASCII version of the string. A set of non-ASCII characters are
3575
     * replaced with their closest ASCII counterparts, and the rest are removed
3576
     * unless instructed otherwise.
3577
     *
3578
     * @param bool   $strict  [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad
3579
     *                        performance | Default: false</p>
3580
     * @param string $unknown [optional] <p>Character use if character unknown. (default is ?)</p>
3581
     *
3582
     * @psalm-mutation-free
3583
     *
3584
     * @return static
3585
     *                <p>Object whose $str contains only ASCII characters.</p>
3586
     */
3587 34
    public function toTransliterate(bool $strict = false, string $unknown = '?'): self
3588
    {
3589 34
        return static::create(
3590 34
            $this->ascii::to_transliterate($this->str, $unknown, $strict),
3591 34
            $this->encoding
3592
        );
3593
    }
3594
3595
    /**
3596
     * Converts all characters in the string to uppercase.
3597
     *
3598
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
3599
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
3600
     *
3601
     * @psalm-mutation-free
3602
     *
3603
     * @return static
3604
     *                <p>Object with all characters of $str being uppercase.</p>
3605
     */
3606 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...
3607
    {
3608 20
        return static::create(
3609 20
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
3610 20
            $this->encoding
3611
        );
3612
    }
3613
3614
    /**
3615
     * Returns a string with whitespace removed from the start and end of the
3616
     * string. Supports the removal of unicode whitespace. Accepts an optional
3617
     * string of characters to strip instead of the defaults.
3618
     *
3619
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
3620
     *
3621
     * @psalm-mutation-free
3622
     *
3623
     * @return static
3624
     *                <p>Object with a trimmed $str.</p>
3625
     */
3626 36
    public function trim(string $chars = null): self
3627
    {
3628 36
        return static::create(
3629 36
            $this->utf8::trim($this->str, $chars),
3630 36
            $this->encoding
3631
        );
3632
    }
3633
3634
    /**
3635
     * Returns a string with whitespace removed from the start of the string.
3636
     * Supports the removal of unicode whitespace. Accepts an optional
3637
     * string of characters to strip instead of the defaults.
3638
     *
3639
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
3640
     *
3641
     * @psalm-mutation-free
3642
     *
3643
     * @return static
3644
     *                <p>Object with a trimmed $str.</p>
3645
     */
3646 39
    public function trimLeft(string $chars = null): self
3647
    {
3648 39
        return static::create(
3649 39
            $this->utf8::ltrim($this->str, $chars),
3650 39
            $this->encoding
3651
        );
3652
    }
3653
3654
    /**
3655
     * Returns a string with whitespace removed from the end of the string.
3656
     * Supports the removal of unicode whitespace. Accepts an optional
3657
     * string of characters to strip instead of the defaults.
3658
     *
3659
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
3660
     *
3661
     * @psalm-mutation-free
3662
     *
3663
     * @return static
3664
     *                <p>Object with a trimmed $str.</p>
3665
     */
3666 39
    public function trimRight(string $chars = null): self
3667
    {
3668 39
        return static::create(
3669 39
            $this->utf8::rtrim($this->str, $chars),
3670 39
            $this->encoding
3671
        );
3672
    }
3673
3674
    /**
3675
     * Truncates the string to a given length. If $substring is provided, and
3676
     * truncating occurs, the string is further truncated so that the substring
3677
     * may be appended without exceeding the desired length.
3678
     *
3679
     * @param int    $length    <p>Desired length of the truncated string.</p>
3680
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
3681
     *
3682
     * @psalm-mutation-free
3683
     *
3684
     * @return static
3685
     *                <p>Object with the resulting $str after truncating.</p>
3686
     */
3687 66
    public function truncate(int $length, string $substring = ''): self
3688
    {
3689 66
        return static::create(
3690 66
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
3691 66
            $this->encoding
3692
        );
3693
    }
3694
3695
    /**
3696
     * Returns a lowercase and trimmed string separated by underscores.
3697
     * Underscores are inserted before uppercase characters (with the exception
3698
     * of the first character of the string), and in place of spaces as well as
3699
     * dashes.
3700
     *
3701
     * @psalm-mutation-free
3702
     *
3703
     * @return static
3704
     *                <p>Object with an underscored $str.</p>
3705
     */
3706 48
    public function underscored(): self
3707
    {
3708 48
        return $this->delimit('_');
3709
    }
3710
3711
    /**
3712
     * Returns an UpperCamelCase version of the supplied string. It trims
3713
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
3714
     * and underscores, and removes spaces, dashes, underscores.
3715
     *
3716
     * @psalm-mutation-free
3717
     *
3718
     * @return static
3719
     *                <p>Object with $str in UpperCamelCase.</p>
3720
     */
3721 39
    public function upperCamelize(): self
3722
    {
3723 39
        return static::create(
3724 39
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
3725 39
            $this->encoding
3726
        );
3727
    }
3728
3729
    /**
3730
     * Converts the first character of the supplied string to upper case.
3731
     *
3732
     * @psalm-mutation-free
3733
     *
3734
     * @return static
3735
     *                <p>Object with the first character of $str being upper case.</p>
3736
     */
3737 18
    public function upperCaseFirst(): self
3738
    {
3739 18
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
3740
    }
3741
3742
    /**
3743
     * Converts the string into an URL slug. This includes replacing non-ASCII
3744
     * characters with their closest ASCII equivalents, removing remaining
3745
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
3746
     * $separator. The separator defaults to a single dash, and the string
3747
     * is also converted to lowercase.
3748
     *
3749
     * @param string                $separator    [optional] <p>The string used to replace whitespace. Default: '-'</p>
3750
     * @param string                $language     [optional] <p>The language for the url. Default: 'en'</p>
3751
     * @param array<string, string> $replacements [optional] <p>A map of replaceable strings.</p>
3752
     * @param bool                  $strToLower   [optional] <p>string to lower. Default: true</p>
3753
     *
3754
     * @psalm-mutation-free
3755
     *
3756
     * @return static
3757
     *                <p>Object whose $str has been converted to an URL slug.</p>
3758
     *
3759
     * @psalm-suppress ImpureMethodCall :/
3760
     */
3761 32
    public function urlify(
3762
        string $separator = '-',
3763
        string $language = 'en',
3764
        array $replacements = [],
3765
        bool $strToLower = true
3766
    ): self {
3767
        // init
3768 32
        $str = $this->str;
3769
3770 32
        foreach ($replacements as $from => $to) {
3771 32
            $str = \str_replace($from, $to, $str);
3772
        }
3773
3774 32
        return static::create(
3775 32
            URLify::slug(
3776 32
                $str,
3777 32
                $language,
3778 32
                $separator,
3779 32
                $strToLower
3780
            ),
3781 32
            $this->encoding
3782
        );
3783
    }
3784
3785
    /**
3786
     * Converts the string into an valid UTF-8 string.
3787
     *
3788
     * @psalm-mutation-free
3789
     *
3790
     * @return static
3791
     */
3792 2
    public function utf8ify(): self
3793
    {
3794 2
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
3795
    }
3796
3797
    /**
3798
     * Convert a string into an array of words.
3799
     *
3800
     * @param string   $char_list                [optional] <p>Additional chars for the definition of "words".</p>
3801
     * @param bool     $remove_empty_values      [optional] <p>Remove empty values.</p>
3802
     * @param int|null $remove_short_values      [optional] <p>The min. string length or null to disable</p>
3803
     * @param bool     $return_stingy_collection [optional] <p>Return a collection object.</p>
3804
     *
3805
     * @psalm-mutation-free
3806
     *
3807
     * @return CollectionStringy|static[]
3808
     *
3809
     * @psalm-return CollectionStringy<int,static>|array<int,static>
3810
     */
3811 2
    public function words(
3812
        string $char_list = '',
3813
        bool $remove_empty_values = false,
3814
        $remove_short_values = null,
3815
        bool $return_stingy_collection = false
3816
    ) {
3817
        /**
3818
         * @psalm-suppress DocblockTypeContradiction
3819
         */
3820 2
        if ($remove_short_values !== null && !\is_int($remove_short_values)) {
3821
            throw new \InvalidArgumentException(
3822
                'Passed value must be a null or int'
3823
            );
3824
        }
3825
3826 2
        if ($remove_short_values === null) {
3827 2
            $strings = $this->utf8::str_to_words(
3828 2
                $this->str,
3829 2
                $char_list,
3830 2
                $remove_empty_values
3831
            );
3832
        } else {
3833 2
            $strings = $this->utf8::str_to_words(
3834 2
                $this->str,
3835 2
                $char_list,
3836 2
                $remove_empty_values,
3837 2
                $remove_short_values
3838
            );
3839
        }
3840
3841
        /** @noinspection AlterInForeachInspection */
3842 2
        foreach ($strings as &$string) {
3843 2
            $string = static::create($string);
3844
        }
3845
3846
        /** @noinspection PhpSillyAssignmentInspection */
3847
        /** @var static[] $strings */
3848 2
        $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...
3849
3850 2
        if ($return_stingy_collection) {
3851
            /**
3852
             * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3853
             */
3854 2
            return CollectionStringy::create($strings);
3855
        }
3856
3857
        return $strings;
3858
    }
3859
3860
    /**
3861
     * Surrounds $str with the given substring.
3862
     *
3863
     * @param string $substring <p>The substring to add to both sides.</P>
3864
     *
3865
     * @psalm-mutation-free
3866
     *
3867
     * @return static
3868
     *                <p>Object whose $str had the substring both prepended and appended.</p>
3869
     */
3870 10
    public function wrap(string $substring): self
3871
    {
3872 10
        return $this->surround($substring);
3873
    }
3874
3875
    /**
3876
     * Returns the replacements for the toAscii() method.
3877
     *
3878
     * @noinspection PhpUnused
3879
     *
3880
     * @psalm-mutation-free
3881
     *
3882
     * @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...
3883
     *                       <p>An array of replacements.</p>
3884
     *
3885
     * @deprecated   this is only here for backward-compatibly reasons
3886
     */
3887 1
    protected function charsArray(): array
3888
    {
3889 1
        return $this->ascii::charsArrayWithMultiLanguageValues();
3890
    }
3891
3892
    /**
3893
     * Returns true if $str matches the supplied pattern, false otherwise.
3894
     *
3895
     * @param string $pattern <p>Regex pattern to match against.</p>
3896
     *
3897
     * @psalm-mutation-free
3898
     *
3899
     * @return bool
3900
     *              <p>Whether or not $str matches the pattern.</p>
3901
     */
3902 24
    protected function matchesPattern(string $pattern): bool
3903
    {
3904 24
        return $this->utf8::str_matches_pattern($this->str, $pattern);
3905
    }
3906
}
3907