Completed
Push — master ( 68429a...46c3ba )
by Lars
02:50
created

Stringy::replaceEnding()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 7
ccs 4
cts 4
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 3640
    public function __construct($str = '', string $encoding = null)
62
    {
63 3640
        if (\is_array($str)) {
64 3
            throw new \InvalidArgumentException(
65 3
                'Passed value cannot be an array'
66
            );
67
        }
68
69
        if (
70 3637
            \is_object($str)
71
            &&
72 3637
            !\method_exists($str, '__toString')
73
        ) {
74 4
            throw new \InvalidArgumentException(
75 4
                'Passed object must have a __toString method'
76
            );
77
        }
78
79 3634
        $this->str = (string) $str;
80
81 3634
        static $ASCII = null;
82 3634
        if ($ASCII === null) {
83
            $ASCII = new ASCII();
84
        }
85 3634
        $this->ascii = $ASCII;
86
87 3634
        static $UTF8 = null;
88 3634
        if ($UTF8 === null) {
89
            $UTF8 = new UTF8();
90
        }
91 3634
        $this->utf8 = $UTF8;
92
93 3634
        if ($encoding !== 'UTF-8') {
94 2463
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
95
        } else {
96 2703
            $this->encoding = $encoding;
97
        }
98 3634
    }
99
100
    /**
101
     * Returns the value in $str.
102
     *
103
     * EXAMPLE: <code>
104
     * </code>
105
     *
106
     * @psalm-mutation-free
107
     *
108
     * @return string
109
     *                <p>The current value of the $str property.</p>
110
     */
111 1143
    public function __toString()
112
    {
113 1143
        return (string) $this->str;
114
    }
115
116
    /**
117
     * Return part of the string occurring after a specific string.
118
     *
119
     * EXAMPLE: <code>
120
     * s('宮本 茂')->after('本'); // ' 茂'
121
     * </code>
122
     *
123
     * @param string $string <p>The delimiting string.</p>
124
     *
125
     * @psalm-mutation-free
126
     *
127
     * @return static
128
     */
129 4
    public function after(string $string): self
130
    {
131 4
        $strArray = UTF8::str_split_pattern(
132 4
            $this->str,
133 4
            $string
134
        );
135
136 4
        unset($strArray[0]);
137
138 4
        return new static(
139 4
            \implode(' ', $strArray),
140 4
            $this->encoding
141
        );
142
    }
143
144
    /**
145
     * Gets the substring after the first occurrence of a separator.
146
     * If no match is found returns new empty Stringy object.
147
     *
148
     * EXAMPLE: <code>
149
     * s('</b></b>')->afterFirst('b'); // '></b>'
150
     * </code>
151
     *
152
     * @param string $separator
153
     *
154
     * @psalm-mutation-free
155
     *
156
     * @return static
157
     */
158 3
    public function afterFirst(string $separator): self
159
    {
160 3
        return static::create(
161 3
            $this->utf8::str_substr_after_first_separator(
162 3
                $this->str,
163 3
                $separator,
164 3
                $this->encoding
165
            )
166
        );
167
    }
168
169
    /**
170
     * Gets the substring after the first occurrence of a separator.
171
     * If no match is found returns new empty Stringy object.
172
     *
173
     * EXAMPLE: <code>
174
     * s('</B></B>')->afterFirstIgnoreCase('b'); // '></B>'
175
     * </code>
176
     *
177
     * @param string $separator
178
     *
179
     * @psalm-mutation-free
180
     *
181
     * @return static
182
     */
183 2
    public function afterFirstIgnoreCase(string $separator): self
184
    {
185 2
        return static::create(
186 2
            $this->utf8::str_isubstr_after_first_separator(
187 2
                $this->str,
188 2
                $separator,
189 2
                $this->encoding
190
            )
191
        );
192
    }
193
194
    /**
195
     * Gets the substring after the last occurrence of a separator.
196
     * If no match is found returns new empty Stringy object.
197
     *
198
     * EXAMPLE: <code>
199
     * s('</b></b>')->afterLast('b'); // '>'
200
     * </code>
201
     *
202
     * @param string $separator
203
     *
204
     * @psalm-mutation-free
205
     *
206
     * @return static
207
     */
208 2
    public function afterLast(string $separator): self
209
    {
210 2
        return static::create(
211 2
            $this->utf8::str_substr_after_last_separator(
212 2
                $this->str,
213 2
                $separator,
214 2
                $this->encoding
215
            )
216
        );
217
    }
218
219
    /**
220
     * Gets the substring after the last occurrence of a separator.
221
     * If no match is found returns new empty Stringy object.
222
     *
223
     * EXAMPLE: <code>
224
     * s('</B></B>')->afterLastIgnoreCase('b'); // '>'
225
     * </code>
226
     *
227
     * @param string $separator
228
     *
229
     * @psalm-mutation-free
230
     *
231
     * @return static
232
     */
233 2
    public function afterLastIgnoreCase(string $separator): self
234
    {
235 2
        return static::create(
236 2
            $this->utf8::str_isubstr_after_last_separator(
237 2
                $this->str,
238 2
                $separator,
239 2
                $this->encoding
240
            )
241
        );
242
    }
243
244
    /**
245
     * Returns a new string with $suffix appended.
246
     *
247
     * EXAMPLE: <code>
248
     * s('fòô')->append('bàř'); // 'fòôbàř'
249
     * </code>
250
     *
251
     * @param string ...$suffix <p>The string to append.</p>
252
     *
253
     * @psalm-mutation-free
254
     *
255
     * @return static
256
     *                <p>Object with appended $suffix.</p>
257
     */
258 15 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...
259
    {
260 15
        if (\count($suffix) <= 1) {
261
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
262 13
            $suffix = $suffix[0];
263
        } else {
264
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
265 2
            $suffix = \implode('', $suffix);
266
        }
267
268 15
        return static::create($this->str . $suffix, $this->encoding);
269
    }
270
271
    /**
272
     * Append an password (limited to chars that are good readable).
273
     *
274
     * EXAMPLE: <code>
275
     * s('')->appendPassword(8); // e.g.: '89bcdfgh'
276
     * </code>
277
     *
278
     * @param int $length <p>Length of the random string.</p>
279
     *
280
     * @return static
281
     *                <p>Object with appended password.</p>
282
     */
283 2
    public function appendPassword(int $length): self
284
    {
285 2
        return $this->appendRandomString(
286 2
            $length,
287 2
            '2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!?_#'
288
        );
289
    }
290
291
    /**
292
     * Append an random string.
293
     *
294
     * EXAMPLE: <code>
295
     * s('')->appendUniqueIdentifier(5, 'ABCDEFGHI'); // e.g.: 'CDEHI'
296
     * </code>
297
     *
298
     * @param int    $length        <p>Length of the random string.</p>
299
     * @param string $possibleChars [optional] <p>Characters string for the random selection.</p>
300
     *
301
     * @return static
302
     *                <p>Object with appended random string.</p>
303
     */
304 4
    public function appendRandomString(int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): self
305
    {
306 4
        $str = $this->utf8::get_random_string($length, $possibleChars);
307
308 4
        return $this->append($str);
309
    }
310
311
    /**
312
     * Returns a new string with $suffix appended.
313
     *
314
     * EXAMPLE: <code>
315
     * </code>
316
     *
317
     * @param CollectionStringy|static ...$suffix <p>The Stringy objects to append.</p>
318
     *
319
     * @psalm-param CollectionStringy<int,static>|static ...$suffix
320
     *
321
     * @psalm-mutation-free
322
     *
323
     * @return static
324
     *                <p>Object with appended $suffix.</p>
325
     */
326 7 View Code Duplication
    public function appendStringy(...$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...
327
    {
328 7
        $suffixStr = '';
329 7
        foreach ($suffix as $suffixTmp) {
330 7
            if ($suffixTmp instanceof CollectionStringy) {
331 1
                $suffixStr .= $suffixTmp->implode('');
332
            } else {
333 7
                $suffixStr .= $suffixTmp->toString();
334
            }
335
        }
336
337 7
        return static::create($this->str . $suffixStr, $this->encoding);
338
    }
339
340
    /**
341
     * Append an unique identifier.
342
     *
343
     * EXAMPLE: <code>
344
     * s('')->appendUniqueIdentifier(); // e.g.: '1f3870be274f6c49b3e31a0c6728957f'
345
     * </code>
346
     *
347
     * @param int|string $entropyExtra [optional] <p>Extra entropy via a string or int value.</p>
348
     * @param bool       $md5          [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
349
     *
350
     * @return static
351
     *                <p>Object with appended unique identifier as md5-hash.</p>
352
     */
353 2
    public function appendUniqueIdentifier($entropyExtra = '', bool $md5 = true): self
354
    {
355 2
        return $this->append(
356 2
            $this->utf8::get_unique_string($entropyExtra, $md5)
357
        );
358
    }
359
360
    /**
361
     * Returns the character at $index, with indexes starting at 0.
362
     *
363
     * EXAMPLE: <code>
364
     * s('fòôbàř')->at(3); // 'b'
365
     * </code>
366
     *
367
     * @param int $index <p>Position of the character.</p>
368
     *
369
     * @psalm-mutation-free
370
     *
371
     * @return static
372
     *                <p>The character at $index.</p>
373
     */
374 24
    public function at(int $index): self
375
    {
376 24
        return static::create($this->utf8::char_at($this->str, $index), $this->encoding);
377
    }
378
379
    /**
380
     * Decode the base64 encoded string.
381
     *
382
     * EXAMPLE: <code>
383
     * </code>
384
     *
385
     * @psalm-mutation-free
386
     *
387
     * @return self
388
     */
389 2
    public function base64Decode(): self
390
    {
391 2
        return static::create(
392 2
            \base64_decode($this->str, true),
393 2
            $this->encoding
394
        );
395
    }
396
397
    /**
398
     * Encode the string to base64.
399
     *
400
     * EXAMPLE: <code>
401
     * </code>
402
     *
403
     * @psalm-mutation-free
404
     *
405
     * @return self
406
     */
407 2
    public function base64Encode(): self
408
    {
409 2
        return static::create(
410 2
            \base64_encode($this->str),
411 2
            $this->encoding
412
        );
413
    }
414
415
    /**
416
     * Creates a hash from the string using the CRYPT_BLOWFISH algorithm.
417
     *
418
     * WARNING: Using this algorithm, will result in the ```$this->str```
419
     *          being truncated to a maximum length of 72 characters.
420
     *
421
     * EXAMPLE: <code>
422
     * </code>
423
     *
424
     * @param array<array-key, int|string> $options [optional] <p>An array of bcrypt hasing options.</p>
425
     *
426
     * @psalm-mutation-free
427
     *
428
     * @return static
429
     */
430 3
    public function bcrypt(array $options = []): self
431
    {
432 3
        return new static(
433 3
            \password_hash(
434 3
                $this->str,
435 3
                \PASSWORD_BCRYPT,
436 3
                $options
437
            ),
438 3
            $this->encoding
439
        );
440
    }
441
442
    /**
443
     * Return part of the string occurring before a specific string.
444
     *
445
     * EXAMPLE: <code>
446
     * </code>
447
     *
448
     * @param string $string <p>The delimiting string.</p>
449
     *
450
     * @psalm-mutation-free
451
     *
452
     * @return static
453
     */
454 4
    public function before(string $string): self
455
    {
456 4
        $strArray = UTF8::str_split_pattern(
457 4
            $this->str,
458 4
            $string,
459 4
            1
460
        );
461
462 4
        return new static(
463 4
            $strArray[0] ?? '',
464 4
            $this->encoding
465
        );
466
    }
467
468
    /**
469
     * Gets the substring before the first occurrence of a separator.
470
     * If no match is found returns new empty Stringy object.
471
     *
472
     * EXAMPLE: <code>
473
     * s('</b></b>')->beforeFirst('b'); // '</'
474
     * </code>
475
     *
476
     * @param string $separator
477
     *
478
     * @psalm-mutation-free
479
     *
480
     * @return static
481
     */
482 2
    public function beforeFirst(string $separator): self
483
    {
484 2
        return static::create(
485 2
            $this->utf8::str_substr_before_first_separator(
486 2
                $this->str,
487 2
                $separator,
488 2
                $this->encoding
489
            )
490
        );
491
    }
492
493
    /**
494
     * Gets the substring before the first occurrence of a separator.
495
     * If no match is found returns new empty Stringy object.
496
     *
497
     * EXAMPLE: <code>
498
     * s('</B></B>')->beforeFirstIgnoreCase('b'); // '</'
499
     * </code>
500
     *
501
     * @param string $separator
502
     *
503
     * @psalm-mutation-free
504
     *
505
     * @return static
506
     */
507 2
    public function beforeFirstIgnoreCase(string $separator): self
508
    {
509 2
        return static::create(
510 2
            $this->utf8::str_isubstr_before_first_separator(
511 2
                $this->str,
512 2
                $separator,
513 2
                $this->encoding
514
            )
515
        );
516
    }
517
518
    /**
519
     * Gets the substring before the last occurrence of a separator.
520
     * If no match is found returns new empty Stringy object.
521
     *
522
     * EXAMPLE: <code>
523
     * s('</b></b>')->beforeLast('b'); // '</b></'
524
     * </code>
525
     *
526
     * @param string $separator
527
     *
528
     * @psalm-mutation-free
529
     *
530
     * @return static
531
     */
532 2
    public function beforeLast(string $separator): self
533
    {
534 2
        return static::create(
535 2
            $this->utf8::str_substr_before_last_separator(
536 2
                $this->str,
537 2
                $separator,
538 2
                $this->encoding
539
            )
540
        );
541
    }
542
543
    /**
544
     * Gets the substring before the last occurrence of a separator.
545
     * If no match is found returns new empty Stringy object.
546
     *
547
     * EXAMPLE: <code>
548
     * s('</B></B>')->beforeLastIgnoreCase('b'); // '</B></'
549
     * </code>
550
     *
551
     * @param string $separator
552
     *
553
     * @psalm-mutation-free
554
     *
555
     * @return static
556
     */
557 2
    public function beforeLastIgnoreCase(string $separator): self
558
    {
559 2
        return static::create(
560 2
            $this->utf8::str_isubstr_before_last_separator(
561 2
                $this->str,
562 2
                $separator,
563 2
                $this->encoding
564
            )
565
        );
566
    }
567
568
    /**
569
     * Returns the substring between $start and $end, if found, or an empty
570
     * string. An optional offset may be supplied from which to begin the
571
     * search for the start string.
572
     *
573
     * EXAMPLE: <code>
574
     * s('{foo} and {bar}')->between('{', '}'); // 'foo'
575
     * </code>
576
     *
577
     * @param string $start  <p>Delimiter marking the start of the substring.</p>
578
     * @param string $end    <p>Delimiter marking the end of the substring.</p>
579
     * @param int    $offset [optional] <p>Index from which to begin the search. Default: 0</p>
580
     *
581
     * @psalm-mutation-free
582
     *
583
     * @return static
584
     *                <p>Object whose $str is a substring between $start and $end.</p>
585
     */
586 48
    public function between(string $start, string $end, int $offset = null): self
587
    {
588 48
        $str = $this->utf8::between(
589 48
            $this->str,
590 48
            $start,
591 48
            $end,
592 48
            (int) $offset,
593 48
            $this->encoding
594
        );
595
596 48
        return static::create($str, $this->encoding);
597
    }
598
599
    /**
600
     * Call a user function.
601
     *
602
     * EXAMPLE: <code>
603
     * S::create('foo bar lall')->callUserFunction(static function ($str) {
604
     *     return UTF8::str_limit($str, 8);
605
     * })->toString(); // "foo bar…"
606
     * </code>
607
     *
608
     * @param callable $function
609
     * @param mixed    ...$parameter
610
     *
611
     * @psalm-mutation-free
612
     *
613
     * @return static
614
     *                <p>Object having a $str changed via $function.</p>
615
     */
616 2
    public function callUserFunction(callable $function, ...$parameter): self
617
    {
618 2
        $str = $function($this->str, ...$parameter);
619
620 2
        return static::create(
621 2
            $str,
622 2
            $this->encoding
623
        );
624
    }
625
626
    /**
627
     * Returns a camelCase version of the string. Trims surrounding spaces,
628
     * capitalizes letters following digits, spaces, dashes and underscores,
629
     * and removes spaces, dashes, as well as underscores.
630
     *
631
     * EXAMPLE: <code>
632
     * s('Camel-Case')->camelize(); // 'camelCase'
633
     * </code>
634
     *
635
     * @psalm-mutation-free
636
     *
637
     * @return static
638
     *                <p>Object with $str in camelCase.</p>
639
     */
640 57
    public function camelize(): self
641
    {
642 57
        return static::create(
643 57
            $this->utf8::str_camelize($this->str, $this->encoding),
644 57
            $this->encoding
645
        );
646
    }
647
648
    /**
649
     * Returns the string with the first letter of each word capitalized,
650
     * except for when the word is a name which shouldn't be capitalized.
651
     *
652
     * EXAMPLE: <code>
653
     * s('jaap de hoop scheffer')->capitalizePersonName(); // 'Jaap de Hoop Scheffer'
654
     * </code>
655
     *
656
     * @psalm-mutation-free
657
     *
658
     * @return static
659
     *                <p>Object with $str capitalized.</p>
660
     */
661 78
    public function capitalizePersonalName(): self
662
    {
663 78
        return static::create(
664 78
            $this->utf8::str_capitalize_name($this->str),
665 78
            $this->encoding
666
        );
667
    }
668
669
    /**
670
     * Returns an array consisting of the characters in the string.
671
     *
672
     * EXAMPLE: <code>
673
     * s('fòôbàř')->chars(); // ['f', 'ò', 'ô', 'b', 'à', 'ř']
674
     * </code>
675
     *
676
     * @psalm-mutation-free
677
     *
678
     * @return string[]
679
     *                  <p>An array of string chars.</p>
680
     */
681 14
    public function chars(): array
682
    {
683
        /** @var string[] */
684 14
        return $this->utf8::str_split($this->str);
685
    }
686
687
    /**
688
     * Splits the string into chunks of Stringy objects.
689
     *
690
     * EXAMPLE: <code>
691
     * s('foobar')->chunk(3); // ['foo', 'bar']
692
     * </code>
693
     *
694
     * @param int $length [optional] <p>Max character length of each array element.</p>
695
     *
696
     * @psalm-mutation-free
697
     *
698
     * @return static[]
699
     *                  <p>An array of Stringy objects.</p>
700
     *
701
     * @psalm-return array<int,static>
702
     */
703 13
    public function chunk(int $length = 1): array
704
    {
705 13
        if ($length < 1) {
706
            throw new \InvalidArgumentException('The chunk length must be greater than zero.');
707
        }
708
709 13
        if ($this->str === '') {
710 2
            return [];
711
        }
712
713 11
        $chunks = $this->utf8::str_split($this->str, $length);
714
715
        /** @noinspection AlterInForeachInspection */
716 11
        foreach ($chunks as $i => &$value) {
717 11
            $value = static::create($value, $this->encoding);
718
        }
719
720
        /** @noinspection PhpSillyAssignmentInspection */
721
        /** @var static[] $chunks */
722 11
        $chunks = $chunks;
0 ignored issues
show
Bug introduced by
Why assign $chunks to itself?

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

This assignement can be removed without consequences.

Loading history...
723
724 11
        return $chunks;
725
    }
726
727
    /**
728
     * Splits the string into chunks of Stringy objects collection.
729
     *
730
     * EXAMPLE: <code>
731
     * </code>
732
     *
733
     * @param int $length [optional] <p>Max character length of each array element.</p>
734
     *
735
     * @psalm-mutation-free
736
     *
737
     * @return CollectionStringy|static[]
738
     *                                    <p>An collection of Stringy objects.</p>
739
     *
740
     * @psalm-return CollectionStringy<int,static>
741
     */
742 7
    public function chunkCollection(int $length = 1): CollectionStringy
743
    {
744
        /**
745
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
746
         */
747 7
        return CollectionStringy::create(
748 7
            $this->chunk($length)
749
        );
750
    }
751
752
    /**
753
     * Trims the string and replaces consecutive whitespace characters with a
754
     * single space. This includes tabs and newline characters, as well as
755
     * multibyte whitespace such as the thin space and ideographic space.
756
     *
757
     * EXAMPLE: <code>
758
     * s('   Ο     συγγραφέας  ')->collapseWhitespace(); // 'Ο συγγραφέας'
759
     * </code>
760
     *
761
     * @psalm-mutation-free
762
     *
763
     * @return static
764
     *                <p>Object with a trimmed $str and condensed whitespace.</p>
765
     */
766 39
    public function collapseWhitespace(): self
767
    {
768 39
        return static::create(
769 39
            $this->utf8::collapse_whitespace($this->str),
770 39
            $this->encoding
771
        );
772
    }
773
774
    /**
775
     * Returns true if the string contains $needle, false otherwise. By default
776
     * the comparison is case-sensitive, but can be made insensitive by setting
777
     * $caseSensitive to false.
778
     *
779
     * EXAMPLE: <code>
780
     * s('Ο συγγραφέας είπε')->contains('συγγραφέας'); // true
781
     * </code>
782
     *
783
     * @param string $needle        <p>Substring to look for.</p>
784
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
785
     *
786
     * @psalm-mutation-free
787
     *
788
     * @return bool
789
     *              <p>Whether or not $str contains $needle.</p>
790
     */
791 63
    public function contains(string $needle, bool $caseSensitive = true): bool
792
    {
793 63
        return $this->utf8::str_contains(
794 63
            $this->str,
795 63
            $needle,
796 63
            $caseSensitive
797
        );
798
    }
799
800
    /**
801
     * Returns true if the string contains all $needles, false otherwise. By
802
     * default the comparison is case-sensitive, but can be made insensitive by
803
     * setting $caseSensitive to false.
804
     *
805
     * EXAMPLE: <code>
806
     * s('foo & bar')->containsAll(['foo', 'bar']); // true
807
     * </code>
808
     *
809
     * @param string[] $needles       <p>SubStrings to look for.</p>
810
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
811
     *
812
     * @psalm-mutation-free
813
     *
814
     * @return bool
815
     *              <p>Whether or not $str contains $needle.</p>
816
     */
817 131
    public function containsAll(array $needles, bool $caseSensitive = true): bool
818
    {
819 131
        return $this->utf8::str_contains_all(
820 131
            $this->str,
821 131
            $needles,
822 131
            $caseSensitive
823
        );
824
    }
825
826
    /**
827
     * Returns true if the string contains any $needles, false otherwise. By
828
     * default the comparison is case-sensitive, but can be made insensitive by
829
     * setting $caseSensitive to false.
830
     *
831
     * EXAMPLE: <code>
832
     * s('str contains foo')->containsAny(['foo', 'bar']); // true
833
     * </code>
834
     *
835
     * @param string[] $needles       <p>SubStrings to look for.</p>
836
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
837
     *
838
     * @psalm-mutation-free
839
     *
840
     * @return bool
841
     *              <p>Whether or not $str contains $needle.</p>
842
     */
843 129
    public function containsAny(array $needles, bool $caseSensitive = true): bool
844
    {
845 129
        return $this->utf8::str_contains_any(
846 129
            $this->str,
847 129
            $needles,
848 129
            $caseSensitive
849
        );
850
    }
851
852
    /**
853
     * Checks if string starts with "BOM" (Byte Order Mark Character) character.
854
     *
855
     * EXAMPLE: <code>s("\xef\xbb\xbf foobar")->containsBom(); // true</code>
856
     *
857
     * @psalm-mutation-free
858
     *
859
     * @return bool
860
     *              <strong>true</strong> if the string has BOM at the start,<br>
861
     *              <strong>false</strong> otherwise
862
     */
863
    public function containsBom(): bool
864
    {
865
        return $this->utf8::string_has_bom($this->str);
866
    }
867
868
    /**
869
     * Returns the length of the string, implementing the countable interface.
870
     *
871
     * EXAMPLE: <code>
872
     * </code>
873
     *
874
     * @psalm-mutation-free
875
     *
876
     * @return int
877
     *             <p>The number of characters in the string, given the encoding.</p>
878
     */
879 3
    public function count(): int
880
    {
881 3
        return $this->length();
882
    }
883
884
    /**
885
     * Returns the number of occurrences of $substring in the given string.
886
     * By default, the comparison is case-sensitive, but can be made insensitive
887
     * by setting $caseSensitive to false.
888
     *
889
     * EXAMPLE: <code>
890
     * s('Ο συγγραφέας είπε')->countSubstr('α'); // 2
891
     * </code>
892
     *
893
     * @param string $substring     <p>The substring to search for.</p>
894
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
895
     *
896
     * @psalm-mutation-free
897
     *
898
     * @return int
899
     */
900 45
    public function countSubstr(string $substring, bool $caseSensitive = true): int
901
    {
902 45
        return $this->utf8::substr_count_simple(
903 45
            $this->str,
904 45
            $substring,
905 45
            $caseSensitive,
906 45
            $this->encoding
907
        );
908
    }
909
910
    /**
911
     * Calculates the crc32 polynomial of a string.
912
     *
913
     * EXAMPLE: <code>
914
     * </code>
915
     *
916
     * @psalm-mutation-free
917
     *
918
     * @return int
919
     */
920 2
    public function crc32(): int
921
    {
922 2
        return \crc32($this->str);
923
    }
924
925
    /**
926
     * Creates a Stringy object and assigns both str and encoding properties
927
     * the supplied values. $str is cast to a string prior to assignment, and if
928
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
929
     * then returns the initialized object. Throws an InvalidArgumentException
930
     * if the first argument is an array or object without a __toString method.
931
     *
932
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
933
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
934
     *
935
     * @throws \InvalidArgumentException
936
     *                                   <p>if an array or object without a
937
     *                                   __toString method is passed as the first argument</p>
938
     *
939
     * @return static
940
     *                <p>A Stringy object.</p>
941
     * @psalm-pure
942
     */
943 3568
    public static function create($str = '', string $encoding = null): self
944
    {
945 3568
        return new static($str, $encoding);
946
    }
947
948
    /**
949
     * One-way string encryption (hashing).
950
     *
951
     * Hash the string using the standard Unix DES-based algorithm or an
952
     * alternative algorithm that may be available on the system.
953
     *
954
     * PS: if you need encrypt / decrypt, please use ```static::encrypt($password)```
955
     *     and ```static::decrypt($password)```
956
     *
957
     * EXAMPLE: <code>
958
     * </code>
959
     *
960
     * @param string $salt <p>A salt string to base the hashing on.</p>
961
     *
962
     * @psalm-mutation-free
963
     *
964
     * @return static
965
     */
966 3
    public function crypt(string $salt): self
967
    {
968 3
        return new static(
969 3
            \crypt(
970 3
                $this->str,
971 3
                $salt
972
            ),
973 3
            $this->encoding
974
        );
975
    }
976
977
    /**
978
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
979
     * inserted before uppercase characters (with the exception of the first
980
     * character of the string), and in place of spaces as well as underscores.
981
     *
982
     * EXAMPLE: <code>
983
     * s('fooBar')->dasherize(); // 'foo-bar'
984
     * </code>
985
     *
986
     * @psalm-mutation-free
987
     *
988
     * @return static
989
     *                <p>Object with a dasherized $str</p>
990
     */
991 57
    public function dasherize(): self
992
    {
993 57
        return static::create(
994 57
            $this->utf8::str_dasherize($this->str),
995 57
            $this->encoding
996
        );
997
    }
998
999
    /**
1000
     * Decrypt the string.
1001
     *
1002
     * EXAMPLE: <code>
1003
     * </code>
1004
     *
1005
     * @param string $password The key for decrypting
1006
     *
1007
     * @psalm-mutation-free
1008
     *
1009
     * @return static
1010
     */
1011 5
    public function decrypt(string $password): self
1012
    {
1013
        /**
1014
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
1015
         */
1016 5
        return new static(
1017 5
            Crypto::decryptWithPassword($this->str, $password),
1018 3
            $this->encoding
1019
        );
1020
    }
1021
1022
    /**
1023
     * Returns a lowercase and trimmed string separated by the given delimiter.
1024
     * Delimiters are inserted before uppercase characters (with the exception
1025
     * of the first character of the string), and in place of spaces, dashes,
1026
     * and underscores. Alpha delimiters are not converted to lowercase.
1027
     *
1028
     * EXAMPLE: <code>
1029
     * s('fooBar')->delimit('::'); // 'foo::bar'
1030
     * </code>
1031
     *
1032
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
1033
     *
1034
     * @psalm-mutation-free
1035
     *
1036
     * @return static
1037
     *                <p>Object with a delimited $str.</p>
1038
     */
1039 90
    public function delimit(string $delimiter): self
1040
    {
1041 90
        return static::create(
1042 90
            $this->utf8::str_delimit($this->str, $delimiter),
1043 90
            $this->encoding
1044
        );
1045
    }
1046
1047
    /**
1048
     * Encode the given string into the given $encoding + set the internal character encoding.
1049
     *
1050
     * EXAMPLE: <code>
1051
     * </code>
1052
     *
1053
     * @param string $new_encoding         <p>The desired character encoding.</p>
1054
     * @param bool   $auto_detect_encoding [optional] <p>Auto-detect the current string-encoding</p>
1055
     *
1056
     * @psalm-mutation-free
1057
     *
1058
     * @return static
1059
     */
1060 2
    public function encode(string $new_encoding, bool $auto_detect_encoding = false): self
1061
    {
1062 2
        if ($auto_detect_encoding) {
1063 1
            $str = $this->utf8::encode(
1064 1
                $new_encoding,
1065 1
                $this->str
1066
            );
1067
        } else {
1068 1
            $str = $this->utf8::encode(
1069 1
                $new_encoding,
1070 1
                $this->str,
1071 1
                false,
1072 1
                $this->encoding
1073
            );
1074
        }
1075
1076 2
        return new static($str, $new_encoding);
1077
    }
1078
1079
    /**
1080
     * Encrypt the string.
1081
     *
1082
     * EXAMPLE: <code>
1083
     * </code>
1084
     *
1085
     * @param string $password <p>The key for encrypting</p>
1086
     *
1087
     * @psalm-mutation-free
1088
     *
1089
     * @return static
1090
     */
1091 4
    public function encrypt(string $password): self
1092
    {
1093
        /**
1094
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
1095
         */
1096 4
        return new static(
1097 4
            Crypto::encryptWithPassword($this->str, $password),
1098 4
            $this->encoding
1099
        );
1100
    }
1101
1102
    /**
1103
     * Returns true if the string ends with $substring, false otherwise. By
1104
     * default, the comparison is case-sensitive, but can be made insensitive
1105
     * by setting $caseSensitive to false.
1106
     *
1107
     * EXAMPLE: <code>
1108
     * s('fòôbàř')->endsWith('bàř', true); // true
1109
     * </code>
1110
     *
1111
     * @param string $substring     <p>The substring to look for.</p>
1112
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1113
     *
1114
     * @psalm-mutation-free
1115
     *
1116
     * @return bool
1117
     *              <p>Whether or not $str ends with $substring.</p>
1118
     */
1119 97
    public function endsWith(string $substring, bool $caseSensitive = true): bool
1120
    {
1121 97
        if ($caseSensitive) {
1122 53
            return $this->utf8::str_ends_with($this->str, $substring);
1123
        }
1124
1125 44
        return $this->utf8::str_iends_with($this->str, $substring);
1126
    }
1127
1128
    /**
1129
     * Returns true if the string ends with any of $substrings, false otherwise.
1130
     * By default, the comparison is case-sensitive, but can be made insensitive
1131
     * by setting $caseSensitive to false.
1132
     *
1133
     * EXAMPLE: <code>
1134
     * s('fòôbàř')->endsWithAny(['bàř', 'baz'], true); // true
1135
     * </code>
1136
     *
1137
     * @param string[] $substrings    <p>Substrings to look for.</p>
1138
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1139
     *
1140
     * @psalm-mutation-free
1141
     *
1142
     * @return bool
1143
     *              <p>Whether or not $str ends with $substring.</p>
1144
     */
1145 33
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
1146
    {
1147 33
        if ($caseSensitive) {
1148 21
            return $this->utf8::str_ends_with_any($this->str, $substrings);
1149
        }
1150
1151 12
        return $this->utf8::str_iends_with_any($this->str, $substrings);
1152
    }
1153
1154
    /**
1155
     * Ensures that the string begins with $substring. If it doesn't, it's
1156
     * prepended.
1157
     *
1158
     * EXAMPLE: <code>
1159
     * s('foobar')->ensureLeft('http://'); // 'http://foobar'
1160
     * </code>
1161
     *
1162
     * @param string $substring <p>The substring to add if not present.</p>
1163
     *
1164
     * @psalm-mutation-free
1165
     *
1166
     * @return static
1167
     *                <p>Object with its $str prefixed by the $substring.</p>
1168
     */
1169 30
    public function ensureLeft(string $substring): self
1170
    {
1171 30
        return static::create(
1172 30
            $this->utf8::str_ensure_left($this->str, $substring),
1173 30
            $this->encoding
1174
        );
1175
    }
1176
1177
    /**
1178
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
1179
     *
1180
     * EXAMPLE: <code>
1181
     * s('foobar')->ensureRight('.com'); // 'foobar.com'
1182
     * </code>
1183
     *
1184
     * @param string $substring <p>The substring to add if not present.</p>
1185
     *
1186
     * @psalm-mutation-free
1187
     *
1188
     * @return static
1189
     *                <p>Object with its $str suffixed by the $substring.</p>
1190
     */
1191 30
    public function ensureRight(string $substring): self
1192
    {
1193 30
        return static::create(
1194 30
            $this->utf8::str_ensure_right($this->str, $substring),
1195 30
            $this->encoding
1196
        );
1197
    }
1198
1199
    /**
1200
     * Create a escape html version of the string via "htmlspecialchars()".
1201
     *
1202
     * EXAMPLE: <code>
1203
     * s('<∂∆ onerror="alert(xss)">')->escape(); // '&lt;∂∆ onerror=&quot;alert(xss)&quot;&gt;'
1204
     * </code>
1205
     *
1206
     * @psalm-mutation-free
1207
     *
1208
     * @return static
1209
     */
1210 12
    public function escape(): self
1211
    {
1212 12
        return static::create(
1213 12
            $this->utf8::htmlspecialchars(
1214 12
                $this->str,
1215 12
                \ENT_QUOTES | \ENT_SUBSTITUTE,
1216 12
                $this->encoding
1217
            ),
1218 12
            $this->encoding
1219
        );
1220
    }
1221
1222
    /**
1223
     * Split a string by a string.
1224
     *
1225
     * EXAMPLE: <code>
1226
     * </code>
1227
     *
1228
     * @param string $delimiter <p>The boundary string</p>
1229
     * @param int    $limit     [optional] <p>The maximum number of elements in the exploded
1230
     *                          collection.</p>
1231
     *
1232
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
1233
     *   element containing the rest of string.
1234
     *   - If the limit parameter is negative, all components except the last -limit are returned.
1235
     *   - If the limit parameter is zero, then this is treated as 1
1236
     *
1237
     * @psalm-mutation-free
1238
     *
1239
     * @return array<int,static>
1240
     */
1241 3
    public function explode(string $delimiter, int $limit = \PHP_INT_MAX): array
1242
    {
1243 3
        if ($this->str === '') {
1244
            return [];
1245
        }
1246
1247 3
        $strings = \explode($delimiter, $this->str, $limit);
1248 3
        if ($strings === false) {
1249
            $strings = [];
1250
        }
1251
1252 3
        return \array_map(
1253
            function ($str) {
1254 3
                return new static($str, $this->encoding);
1255 3
            },
1256 3
            $strings
1257
        );
1258
    }
1259
1260
    /**
1261
     * Split a string by a string.
1262
     *
1263
     * EXAMPLE: <code>
1264
     * </code>
1265
     *
1266
     * @param string $delimiter <p>The boundary string</p>
1267
     * @param int    $limit     [optional] <p>The maximum number of elements in the exploded
1268
     *                          collection.</p>
1269
     *
1270
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
1271
     *   element containing the rest of string.
1272
     *   - If the limit parameter is negative, all components except the last -limit are returned.
1273
     *   - If the limit parameter is zero, then this is treated as 1
1274
     *
1275
     * @psalm-mutation-free
1276
     *
1277
     * @return CollectionStringy|static[]
1278
     *                                    <p>An collection of Stringy objects.</p>
1279
     *
1280
     * @psalm-return CollectionStringy<int,static>
1281
     */
1282 1
    public function explodeCollection(string $delimiter, int $limit = \PHP_INT_MAX): CollectionStringy
1283
    {
1284
        /**
1285
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
1286
         */
1287 1
        return CollectionStringy::create(
1288 1
            $this->explode($delimiter, $limit)
1289
        );
1290
    }
1291
1292
    /**
1293
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
1294
     *
1295
     * EXAMPLE: <code>
1296
     * $sentence = 'This is only a Fork of Stringy, take a look at the new features.';
1297
     * s($sentence)->extractText('Stringy'); // '...Fork of Stringy...'
1298
     * </code>
1299
     *
1300
     * @param string   $search
1301
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
1302
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
1303
     *
1304
     * @psalm-mutation-free
1305
     *
1306
     * @return static
1307
     */
1308 2
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
1309
    {
1310 2
        return static::create(
1311 2
            $this->utf8::extract_text(
1312 2
                $this->str,
1313 2
                $search,
1314 2
                $length,
1315 2
                $replacerForSkippedText,
1316 2
                $this->encoding
1317
            ),
1318 2
            $this->encoding
1319
        );
1320
    }
1321
1322
    /**
1323
     * Returns the first $n characters of the string.
1324
     *
1325
     * EXAMPLE: <code>
1326
     * s('fòôbàř')->first(3); // 'fòô'
1327
     * </code>
1328
     *
1329
     * @param int $n <p>Number of characters to retrieve from the start.</p>
1330
     *
1331
     * @psalm-mutation-free
1332
     *
1333
     * @return static
1334
     *                <p>Object with its $str being the first $n chars.</p>
1335
     */
1336 37
    public function first(int $n): self
1337
    {
1338 37
        return static::create(
1339 37
            $this->utf8::first_char($this->str, $n, $this->encoding),
1340 37
            $this->encoding
1341
        );
1342
    }
1343
1344
    /**
1345
     * Return a formatted string via sprintf + named parameters via array syntax.
1346
     *
1347
     * <p>
1348
     * <br>
1349
     * It will use "sprintf()" so you can use e.g.:
1350
     * <br>
1351
     * <br><pre>s('There are %d monkeys in the %s')->format(5, 'tree');</pre>
1352
     * <br>
1353
     * <br><pre>s('There are %2$d monkeys in the %1$s')->format('tree', 5);</pre>
1354
     * <br>
1355
     * <br>
1356
     * But you can also use named parameter via array syntax e.g.:
1357
     * <br>
1358
     * <br><pre>s('There are %:count monkeys in the %:location')->format(['count' => 5, 'location' => 'tree');</pre>
1359
     * </p>
1360
     *
1361
     * EXAMPLE: <code>
1362
     * $input = 'one: %2$d, %1$s: 2, %:text_three: %3$d';
1363
     * s($input)->format(['text_three' => '%4$s'], 'two', 1, 3, 'three'); // 'One: 1, two: 2, three: 3'
1364
     * </code>
1365
     *
1366
     * @param mixed ...$args [optional]
1367
     *
1368
     * @psalm-mutation-free
1369
     *
1370
     * @return static
1371
     *                <p>A Stringy object produced according to the formatting string
1372
     *                format.</p>
1373
     */
1374 10
    public function format(...$args): self
1375
    {
1376
        // init
1377 10
        $str = $this->str;
1378
1379 10
        if (\strpos($this->str, '%:') !== false) {
1380 8
            $offset = null;
1381 8
            $replacement = null;
1382
            /** @noinspection AlterInForeachInspection */
1383 8
            foreach ($args as $key => &$arg) {
1384 8
                if (!\is_array($arg)) {
1385 4
                    continue;
1386
                }
1387
1388 8
                foreach ($arg as $name => $param) {
1389 8
                    $name = (string) $name;
1390
1391 8
                    if (\strpos($name, '%:') !== 0) {
1392 8
                        $nameTmp = '%:' . $name;
1393
                    } else {
1394
                        $nameTmp = $name;
1395
                    }
1396
1397 8
                    if ($offset === null) {
1398 8
                        $offset = \strpos($str, $nameTmp);
1399
                    } else {
1400 6
                        $offset = \strpos($str, $nameTmp, (int) $offset + \strlen((string) $replacement));
1401
                    }
1402 8
                    if ($offset === false) {
1403 4
                        continue;
1404
                    }
1405
1406 8
                    unset($arg[$name]);
1407
1408 8
                    $str = \substr_replace($str, $param, (int) $offset, \strlen($nameTmp));
1409
                }
1410
1411 8
                unset($args[$key]);
1412
            }
1413
        }
1414
1415 10
        $str = \str_replace('%:', '%%:', $str);
1416
1417 10
        return static::create(
1418 10
            \sprintf($str, ...$args),
1419 10
            $this->encoding
1420
        );
1421
    }
1422
1423
    /**
1424
     * Returns the encoding used by the Stringy object.
1425
     *
1426
     * EXAMPLE: <code>
1427
     * s('fòôbàř', 'UTF-8')->getEncoding(); // 'UTF-8'
1428
     * </code>
1429
     *
1430
     * @psalm-mutation-free
1431
     *
1432
     * @return string
1433
     *                <p>The current value of the $encoding property.</p>
1434
     */
1435 7
    public function getEncoding(): string
1436
    {
1437 7
        return $this->encoding;
1438
    }
1439
1440
    /**
1441
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
1442
     * interface. The ArrayIterator's constructor is passed an array of chars
1443
     * in the multibyte string. This enables the use of foreach with instances
1444
     * of Stringy\Stringy.
1445
     *
1446
     * EXAMPLE: <code>
1447
     * </code>
1448
     *
1449
     * @psalm-mutation-free
1450
     *
1451
     * @return \ArrayIterator
1452
     *                        <p>An iterator for the characters in the string.</p>
1453
     *
1454
     * @psalm-return \ArrayIterator<array-key,string>
1455
     */
1456 3
    public function getIterator(): \ArrayIterator
1457
    {
1458 3
        return new \ArrayIterator($this->chars());
1459
    }
1460
1461
    /**
1462
     * Wrap the string after an exact number of characters.
1463
     *
1464
     * EXAMPLE: <code>
1465
     * </code>
1466
     *
1467
     * @param int    $width <p>Number of characters at which to wrap.</p>
1468
     * @param string $break [optional] <p>Character used to break the string. | Default: "\n"</p>
1469
     *
1470
     * @psalm-mutation-free
1471
     *
1472
     * @return static
1473
     */
1474 2
    public function hardWrap($width, $break = "\n"): self
1475
    {
1476 2
        return $this->lineWrap($width, $break, false);
1477
    }
1478
1479
    /**
1480
     * Returns true if the string contains a lower case char, false otherwise
1481
     *
1482
     * EXAMPLE: <code>
1483
     * s('fòôbàř')->hasLowerCase(); // true
1484
     * </code>
1485
     *
1486
     * @psalm-mutation-free
1487
     *
1488
     * @return bool
1489
     *              <p>Whether or not the string contains a lower case character.</p>
1490
     */
1491 36
    public function hasLowerCase(): bool
1492
    {
1493 36
        return $this->utf8::has_lowercase($this->str);
1494
    }
1495
1496
    /**
1497
     * Returns true if the string contains an upper case char, false otherwise.
1498
     *
1499
     * EXAMPLE: <code>
1500
     * s('fòôbàř')->hasUpperCase(); // false
1501
     * </code>
1502
     *
1503
     * @psalm-mutation-free
1504
     *
1505
     * @return bool
1506
     *              <p>Whether or not the string contains an upper case character.</p>
1507
     */
1508 36
    public function hasUpperCase(): bool
1509
    {
1510 36
        return $this->utf8::has_uppercase($this->str);
1511
    }
1512
1513
    /**
1514
     * Generate a hash value (message digest).
1515
     *
1516
     * EXAMPLE: <code>
1517
     * </code>
1518
     *
1519
     * @see https://php.net/manual/en/function.hash.php
1520
     *
1521
     * @param string $algorithm
1522
     *                          <p>Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4", etc..)</p>
1523
     *
1524
     * @psalm-mutation-free
1525
     *
1526
     * @return static
1527
     */
1528 8
    public function hash($algorithm): self
1529
    {
1530 8
        return static::create(\hash($algorithm, $this->str), $this->encoding);
1531
    }
1532
1533
    /**
1534
     * Decode the string from hex.
1535
     *
1536
     * EXAMPLE: <code>
1537
     * </code>
1538
     *
1539
     * @psalm-mutation-free
1540
     *
1541
     * @return static
1542
     */
1543 2
    public function hexDecode(): self
1544
    {
1545 2
        $string = \preg_replace_callback(
1546 2
            '/\\\\x([0-9A-Fa-f]+)/',
1547
            function (array $matched) {
1548 2
                return (string) $this->utf8::hex_to_chr($matched[1]);
1549 2
            },
1550 2
            $this->str
1551
        );
1552
1553 2
        return static::create(
1554 2
            $string,
1555 2
            $this->encoding
1556
        );
1557
    }
1558
1559
    /**
1560
     * Encode string to hex.
1561
     *
1562
     * EXAMPLE: <code>
1563
     * </code>
1564
     *
1565
     * @psalm-mutation-free
1566
     *
1567
     * @return static
1568
     */
1569 2
    public function hexEncode(): self
1570
    {
1571 2
        $string = \array_reduce(
1572 2
            $this->chars(),
1573
            function (string $str, string $char) {
1574 2
                return $str . $this->utf8::chr_to_hex($char);
1575 2
            },
1576 2
            ''
1577
        );
1578
1579 2
        return static::create(
1580 2
            $string,
1581 2
            $this->encoding
1582
        );
1583
    }
1584
1585
    /**
1586
     * Convert all HTML entities to their applicable characters.
1587
     *
1588
     * EXAMPLE: <code>
1589
     * s('&amp;')->htmlDecode(); // '&'
1590
     * </code>
1591
     *
1592
     * @param int $flags [optional] <p>
1593
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1594
     *                   which document type to use. The default is ENT_COMPAT.
1595
     *                   <table>
1596
     *                   Available <i>flags</i> constants
1597
     *                   <tr valign="top">
1598
     *                   <td>Constant Name</td>
1599
     *                   <td>Description</td>
1600
     *                   </tr>
1601
     *                   <tr valign="top">
1602
     *                   <td><b>ENT_COMPAT</b></td>
1603
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1604
     *                   </tr>
1605
     *                   <tr valign="top">
1606
     *                   <td><b>ENT_QUOTES</b></td>
1607
     *                   <td>Will convert both double and single quotes.</td>
1608
     *                   </tr>
1609
     *                   <tr valign="top">
1610
     *                   <td><b>ENT_NOQUOTES</b></td>
1611
     *                   <td>Will leave both double and single quotes unconverted.</td>
1612
     *                   </tr>
1613
     *                   <tr valign="top">
1614
     *                   <td><b>ENT_HTML401</b></td>
1615
     *                   <td>
1616
     *                   Handle code as HTML 4.01.
1617
     *                   </td>
1618
     *                   </tr>
1619
     *                   <tr valign="top">
1620
     *                   <td><b>ENT_XML1</b></td>
1621
     *                   <td>
1622
     *                   Handle code as XML 1.
1623
     *                   </td>
1624
     *                   </tr>
1625
     *                   <tr valign="top">
1626
     *                   <td><b>ENT_XHTML</b></td>
1627
     *                   <td>
1628
     *                   Handle code as XHTML.
1629
     *                   </td>
1630
     *                   </tr>
1631
     *                   <tr valign="top">
1632
     *                   <td><b>ENT_HTML5</b></td>
1633
     *                   <td>
1634
     *                   Handle code as HTML 5.
1635
     *                   </td>
1636
     *                   </tr>
1637
     *                   </table>
1638
     *                   </p>
1639
     *
1640
     * @psalm-mutation-free
1641
     *
1642
     * @return static
1643
     *                <p>Object with the resulting $str after being html decoded.</p>
1644
     */
1645 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...
1646
    {
1647 15
        return static::create(
1648 15
            $this->utf8::html_entity_decode(
1649 15
                $this->str,
1650 15
                $flags,
1651 15
                $this->encoding
1652
            ),
1653 15
            $this->encoding
1654
        );
1655
    }
1656
1657
    /**
1658
     * Convert all applicable characters to HTML entities.
1659
     *
1660
     * EXAMPLE: <code>
1661
     * s('&')->htmlEncode(); // '&amp;'
1662
     * </code>
1663
     *
1664
     * @param int $flags [optional] <p>
1665
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1666
     *                   which document type to use. The default is ENT_COMPAT.
1667
     *                   <table>
1668
     *                   Available <i>flags</i> constants
1669
     *                   <tr valign="top">
1670
     *                   <td>Constant Name</td>
1671
     *                   <td>Description</td>
1672
     *                   </tr>
1673
     *                   <tr valign="top">
1674
     *                   <td><b>ENT_COMPAT</b></td>
1675
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1676
     *                   </tr>
1677
     *                   <tr valign="top">
1678
     *                   <td><b>ENT_QUOTES</b></td>
1679
     *                   <td>Will convert both double and single quotes.</td>
1680
     *                   </tr>
1681
     *                   <tr valign="top">
1682
     *                   <td><b>ENT_NOQUOTES</b></td>
1683
     *                   <td>Will leave both double and single quotes unconverted.</td>
1684
     *                   </tr>
1685
     *                   <tr valign="top">
1686
     *                   <td><b>ENT_HTML401</b></td>
1687
     *                   <td>
1688
     *                   Handle code as HTML 4.01.
1689
     *                   </td>
1690
     *                   </tr>
1691
     *                   <tr valign="top">
1692
     *                   <td><b>ENT_XML1</b></td>
1693
     *                   <td>
1694
     *                   Handle code as XML 1.
1695
     *                   </td>
1696
     *                   </tr>
1697
     *                   <tr valign="top">
1698
     *                   <td><b>ENT_XHTML</b></td>
1699
     *                   <td>
1700
     *                   Handle code as XHTML.
1701
     *                   </td>
1702
     *                   </tr>
1703
     *                   <tr valign="top">
1704
     *                   <td><b>ENT_HTML5</b></td>
1705
     *                   <td>
1706
     *                   Handle code as HTML 5.
1707
     *                   </td>
1708
     *                   </tr>
1709
     *                   </table>
1710
     *                   </p>
1711
     *
1712
     * @psalm-mutation-free
1713
     *
1714
     * @return static
1715
     *                <p>Object with the resulting $str after being html encoded.</p>
1716
     */
1717 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...
1718
    {
1719 15
        return static::create(
1720 15
            $this->utf8::htmlentities(
1721 15
                $this->str,
1722 15
                $flags,
1723 15
                $this->encoding
1724
            ),
1725 15
            $this->encoding
1726
        );
1727
    }
1728
1729
    /**
1730
     * Capitalizes the first word of the string, replaces underscores with
1731
     * spaces, and strips '_id'.
1732
     *
1733
     * EXAMPLE: <code>
1734
     * s('author_id')->humanize(); // 'Author'
1735
     * </code>
1736
     *
1737
     * @psalm-mutation-free
1738
     *
1739
     * @return static
1740
     *                <p>Object with a humanized $str.</p>
1741
     */
1742 9
    public function humanize(): self
1743
    {
1744 9
        return static::create(
1745 9
            $this->utf8::str_humanize($this->str),
1746 9
            $this->encoding
1747
        );
1748
    }
1749
1750
    /**
1751
     * Determine if the current string exists in another string. By
1752
     * default, the comparison is case-sensitive, but can be made insensitive
1753
     * by setting $caseSensitive to false.
1754
     *
1755
     * EXAMPLE: <code>
1756
     * </code>
1757
     *
1758
     * @param string $str           <p>The string to compare against.</p>
1759
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1760
     *
1761
     * @psalm-mutation-free
1762
     *
1763
     * @return bool
1764
     */
1765 3
    public function in(string $str, bool $caseSensitive = true): bool
1766
    {
1767 3
        if ($caseSensitive) {
1768 2
            return \strpos($str, $this->str) !== false;
1769
        }
1770
1771 1
        return \stripos($str, $this->str) !== false;
1772
    }
1773
1774
    /**
1775
     * Returns the index of the first occurrence of $needle in the string,
1776
     * and false if not found. Accepts an optional offset from which to begin
1777
     * the search.
1778
     *
1779
     * EXAMPLE: <code>
1780
     * s('string')->indexOf('ing'); // 3
1781
     * </code>
1782
     *
1783
     * @param string $needle <p>Substring to look for.</p>
1784
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1785
     *
1786
     * @psalm-mutation-free
1787
     *
1788
     * @return false|int
1789
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1790
     */
1791 31
    public function indexOf(string $needle, int $offset = 0)
1792
    {
1793 31
        return $this->utf8::strpos(
1794 31
            $this->str,
1795 31
            $needle,
1796 31
            $offset,
1797 31
            $this->encoding
1798
        );
1799
    }
1800
1801
    /**
1802
     * Returns the index of the first occurrence of $needle in the string,
1803
     * and false if not found. Accepts an optional offset from which to begin
1804
     * the search.
1805
     *
1806
     * EXAMPLE: <code>
1807
     * s('string')->indexOfIgnoreCase('ING'); // 3
1808
     * </code>
1809
     *
1810
     * @param string $needle <p>Substring to look for.</p>
1811
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1812
     *
1813
     * @psalm-mutation-free
1814
     *
1815
     * @return false|int
1816
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1817
     */
1818 20
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
1819
    {
1820 20
        return $this->utf8::stripos(
1821 20
            $this->str,
1822 20
            $needle,
1823 20
            $offset,
1824 20
            $this->encoding
1825
        );
1826
    }
1827
1828
    /**
1829
     * Returns the index of the last occurrence of $needle in the string,
1830
     * and false if not found. Accepts an optional offset from which to begin
1831
     * the search. Offsets may be negative to count from the last character
1832
     * in the string.
1833
     *
1834
     * EXAMPLE: <code>
1835
     * s('foobarfoo')->indexOfLast('foo'); // 10
1836
     * </code>
1837
     *
1838
     * @param string $needle <p>Substring to look for.</p>
1839
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1840
     *
1841
     * @psalm-mutation-free
1842
     *
1843
     * @return false|int
1844
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1845
     */
1846 31
    public function indexOfLast(string $needle, int $offset = 0)
1847
    {
1848 31
        return $this->utf8::strrpos(
1849 31
            $this->str,
1850 31
            $needle,
1851 31
            $offset,
1852 31
            $this->encoding
1853
        );
1854
    }
1855
1856
    /**
1857
     * Returns the index of the last occurrence of $needle in the string,
1858
     * and false if not found. Accepts an optional offset from which to begin
1859
     * the search. Offsets may be negative to count from the last character
1860
     * in the string.
1861
     *
1862
     * EXAMPLE: <code>
1863
     * s('fooBarFoo')->indexOfLastIgnoreCase('foo'); // 10
1864
     * </code>
1865
     *
1866
     * @param string $needle <p>Substring to look for.</p>
1867
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1868
     *
1869
     * @psalm-mutation-free
1870
     *
1871
     * @return false|int
1872
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1873
     */
1874 20
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
1875
    {
1876 20
        return $this->utf8::strripos(
1877 20
            $this->str,
1878 20
            $needle,
1879 20
            $offset,
1880 20
            $this->encoding
1881
        );
1882
    }
1883
1884
    /**
1885
     * Inserts $substring into the string at the $index provided.
1886
     *
1887
     * EXAMPLE: <code>
1888
     * s('fòôbř')->insert('à', 4); // 'fòôbàř'
1889
     * </code>
1890
     *
1891
     * @param string $substring <p>String to be inserted.</p>
1892
     * @param int    $index     <p>The index at which to insert the substring.</p>
1893
     *
1894
     * @psalm-mutation-free
1895
     *
1896
     * @return static
1897
     *                <p>Object with the resulting $str after the insertion.</p>
1898
     */
1899 24
    public function insert(string $substring, int $index): self
1900
    {
1901 24
        return static::create(
1902 24
            $this->utf8::str_insert(
1903 24
                $this->str,
1904 24
                $substring,
1905 24
                $index,
1906 24
                $this->encoding
1907
            ),
1908 24
            $this->encoding
1909
        );
1910
    }
1911
1912
    /**
1913
     * Returns true if the string contains the $pattern, otherwise false.
1914
     *
1915
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
1916
     * expression wildcards.
1917
     *
1918
     * EXAMPLE: <code>
1919
     * s('Foo\\Bar\\Lall')->is('*\\Bar\\*'); // true
1920
     * </code>
1921
     *
1922
     * @credit Originally from Laravel, thanks Taylor.
1923
     *
1924
     * @param string $pattern <p>The string or pattern to match against.</p>
1925
     *
1926
     * @psalm-mutation-free
1927
     *
1928
     * @return bool
1929
     *              <p>Whether or not we match the provided pattern.</p>
1930
     */
1931 26
    public function is(string $pattern): bool
1932
    {
1933 26
        if ($this->toString() === $pattern) {
1934 2
            return true;
1935
        }
1936
1937 24
        $quotedPattern = \preg_quote($pattern, '/');
1938 24
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
1939
1940 24
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
1941
    }
1942
1943
    /**
1944
     * Returns true if the string contains only alphabetic chars, false otherwise.
1945
     *
1946
     * EXAMPLE: <code>
1947
     * s('丹尼爾')->isAlpha(); // true
1948
     * </code>
1949
     *
1950
     * @psalm-mutation-free
1951
     *
1952
     * @return bool
1953
     *              <p>Whether or not $str contains only alphabetic chars.</p>
1954
     */
1955 30
    public function isAlpha(): bool
1956
    {
1957 30
        return $this->utf8::is_alpha($this->str);
1958
    }
1959
1960
    /**
1961
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
1962
     *
1963
     * EXAMPLE: <code>
1964
     * s('دانيال1')->isAlphanumeric(); // true
1965
     * </code>
1966
     *
1967
     * @psalm-mutation-free
1968
     *
1969
     * @return bool
1970
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
1971
     */
1972 39
    public function isAlphanumeric(): bool
1973
    {
1974 39
        return $this->utf8::is_alphanumeric($this->str);
1975
    }
1976
1977
    /**
1978
     * Checks if a string is 7 bit ASCII.
1979
     *
1980
     * EXAMPLE: <code>s('白')->isAscii; // false</code>
1981
     *
1982
     * @psalm-mutation-free
1983
     *
1984
     * @return bool
1985
     *              <p>
1986
     *              <strong>true</strong> if it is ASCII<br>
1987
     *              <strong>false</strong> otherwise
1988
     *              </p>
1989
     *
1990
     * @noinspection GetSetMethodCorrectnessInspection
1991
     */
1992
    public function isAscii(): bool
1993
    {
1994
        return $this->utf8::is_ascii($this->str);
1995
    }
1996
1997
    /**
1998
     * Returns true if the string is base64 encoded, false otherwise.
1999
     *
2000
     * EXAMPLE: <code>
2001
     * s('Zm9vYmFy')->isBase64(); // true
2002
     * </code>
2003
     *
2004
     * @param bool $emptyStringIsValid
2005
     *
2006
     * @psalm-mutation-free
2007
     *
2008
     * @return bool
2009
     *              <p>Whether or not $str is base64 encoded.</p>
2010
     */
2011 21
    public function isBase64($emptyStringIsValid = true): bool
2012
    {
2013 21
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
2014
    }
2015
2016
    /**
2017
     * Check if the input is binary... (is look like a hack).
2018
     *
2019
     * EXAMPLE: <code>s(01)->isBinary(); // true</code>
2020
     *
2021
     * @psalm-mutation-free
2022
     *
2023
     * @return bool
2024
     */
2025
    public function isBinary(): bool
2026
    {
2027
        return $this->utf8::is_binary($this->str);
2028
    }
2029
2030
    /**
2031
     * Returns true if the string contains only whitespace chars, false otherwise.
2032
     *
2033
     * EXAMPLE: <code>
2034
     * s("\n\t  \v\f")->isBlank(); // true
2035
     * </code>
2036
     *
2037
     * @psalm-mutation-free
2038
     *
2039
     * @return bool
2040
     *              <p>Whether or not $str contains only whitespace characters.</p>
2041
     */
2042 45
    public function isBlank(): bool
2043
    {
2044 45
        return $this->utf8::is_blank($this->str);
2045
    }
2046
2047
    /**
2048
     * Checks if the given string is equal to any "Byte Order Mark".
2049
     *
2050
     * WARNING: Use "s::string_has_bom()" if you will check BOM in a string.
2051
     *
2052
     * EXAMPLE: <code>s->("\xef\xbb\xbf")->isBom(); // true</code>
2053
     *
2054
     * @psalm-mutation-free
2055
     *
2056
     * @return bool
2057
     *              <p><strong>true</strong> if the $utf8_chr is Byte Order Mark, <strong>false</strong> otherwise.</p>
2058
     */
2059
    public function isBom(): bool
2060
    {
2061
        return $this->utf8::is_bom($this->str);
2062
    }
2063
2064
    /**
2065
     * Returns true if the string contains a valid E-Mail address, false otherwise.
2066
     *
2067
     * EXAMPLE: <code>
2068
     * s('[email protected]')->isEmail(); // true
2069
     * </code>
2070
     *
2071
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
2072
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
2073
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
2074
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
2075
     *
2076
     * @psalm-mutation-free
2077
     *
2078
     * @return bool
2079
     *              <p>Whether or not $str contains a valid E-Mail address.</p>
2080
     */
2081 2
    public function isEmail(
2082
        bool $useExampleDomainCheck = false,
2083
        bool $useTypoInDomainCheck = false,
2084
        bool $useTemporaryDomainCheck = false,
2085
        bool $useDnsCheck = false
2086
    ): bool {
2087
        /**
2088
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the email-check class
2089
         */
2090 2
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
2091
    }
2092
2093
    /**
2094
     * Determine whether the string is considered to be empty.
2095
     *
2096
     * A variable is considered empty if it does not exist or if its value equals FALSE.
2097
     *
2098
     * EXAMPLE: <code>
2099
     * s('')->isEmpty(); // true
2100
     * </code>
2101
     *
2102
     * @psalm-mutation-free
2103
     *
2104
     * @return bool
2105
     *              <p>Whether or not $str is empty().</p>
2106
     */
2107 10
    public function isEmpty(): bool
2108
    {
2109 10
        return $this->utf8::is_empty($this->str);
2110
    }
2111
2112
    /**
2113
     * Determine whether the string is equals to $str.
2114
     * Alias for isEqualsCaseSensitive()
2115
     *
2116
     * EXAMPLE: <code>
2117
     * s('foo')->isEquals('foo'); // true
2118
     * </code>
2119
     *
2120
     * @param string|Stringy ...$str
2121
     *
2122
     * @psalm-mutation-free
2123
     *
2124
     * @return bool
2125
     */
2126 13
    public function isEquals(...$str): bool
2127
    {
2128 13
        return $this->isEqualsCaseSensitive(...$str);
2129
    }
2130
2131
    /**
2132
     * Determine whether the string is equals to $str.
2133
     *
2134
     * EXAMPLE: <code>
2135
     * </code>
2136
     *
2137
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
2138
     *
2139
     * @psalm-mutation-free
2140
     *
2141
     * @return bool
2142
     *              <p>Whether or not $str is equals.</p>
2143
     */
2144 3
    public function isEqualsCaseInsensitive(...$str): bool
2145
    {
2146 3
        $strUpper = $this->toUpperCase()->str;
2147
2148 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...
2149
            /**
2150
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
2151
             */
2152 3
            if ($strTmp instanceof self) {
2153
                if ($strUpper !== $strTmp->toUpperCase()->str) {
2154
                    return false;
2155
                }
2156 3
            } elseif (\is_scalar($strTmp)) {
2157 3
                if ($strUpper !== $this->utf8::strtoupper((string) $strTmp, $this->encoding)) {
2158 3
                    return false;
2159
                }
2160
            } else {
2161
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
2162
            }
2163
        }
2164
2165 3
        return true;
2166
    }
2167
2168
    /**
2169
     * Determine whether the string is equals to $str.
2170
     *
2171
     * EXAMPLE: <code>
2172
     * </code>
2173
     *
2174
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
2175
     *
2176
     * @psalm-mutation-free
2177
     *
2178
     * @return bool
2179
     *              <p>Whether or not $str is equals.</p>
2180
     */
2181 14
    public function isEqualsCaseSensitive(...$str): bool
2182
    {
2183 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...
2184
            /**
2185
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
2186
             */
2187 14
            if ($strTmp instanceof self) {
2188 2
                if ($this->str !== $strTmp->str) {
2189 2
                    return false;
2190
                }
2191 12
            } elseif (\is_scalar($strTmp)) {
2192 12
                if ($this->str !== (string) $strTmp) {
2193 12
                    return false;
2194
                }
2195
            } else {
2196
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
2197
            }
2198
        }
2199
2200 3
        return true;
2201
    }
2202
2203
    /**
2204
     * Returns true if the string contains only hexadecimal chars, false otherwise.
2205
     *
2206
     * EXAMPLE: <code>
2207
     * s('A102F')->isHexadecimal(); // true
2208
     * </code>
2209
     *
2210
     * @psalm-mutation-free
2211
     *
2212
     * @return bool
2213
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
2214
     */
2215 39
    public function isHexadecimal(): bool
2216
    {
2217 39
        return $this->utf8::is_hexadecimal($this->str);
2218
    }
2219
2220
    /**
2221
     * Returns true if the string contains HTML-Tags, false otherwise.
2222
     *
2223
     * EXAMPLE: <code>
2224
     * s('<h1>foo</h1>')->isHtml(); // true
2225
     * </code>
2226
     *
2227
     * @psalm-mutation-free
2228
     *
2229
     * @return bool
2230
     *              <p>Whether or not $str contains HTML-Tags.</p>
2231
     */
2232 2
    public function isHtml(): bool
2233
    {
2234 2
        return $this->utf8::is_html($this->str);
2235
    }
2236
2237
    /**
2238
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
2239
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
2240
     * in that an empty string is not considered valid JSON.
2241
     *
2242
     * EXAMPLE: <code>
2243
     * s('{"foo":"bar"}')->isJson(); // true
2244
     * </code>
2245
     *
2246
     * @param bool $onlyArrayOrObjectResultsAreValid
2247
     *
2248
     * @psalm-mutation-free
2249
     *
2250
     * @return bool
2251
     *              <p>Whether or not $str is JSON.</p>
2252
     */
2253 60
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
2254
    {
2255
        /**
2256
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff?
2257
         */
2258 60
        return $this->utf8::is_json(
2259 60
            $this->str,
2260 60
            $onlyArrayOrObjectResultsAreValid
2261
        );
2262
    }
2263
2264
    /**
2265
     * Returns true if the string contains only lower case chars, false otherwise.
2266
     *
2267
     * EXAMPLE: <code>
2268
     * s('fòôbàř')->isLowerCase(); // true
2269
     * </code>
2270
     *
2271
     * @psalm-mutation-free
2272
     *
2273
     * @return bool
2274
     *              <p>Whether or not $str contains only lower case characters.</p>
2275
     */
2276 24
    public function isLowerCase(): bool
2277
    {
2278 24
        return $this->utf8::is_lowercase($this->str);
2279
    }
2280
2281
    /**
2282
     * Determine whether the string is considered to be NOT empty.
2283
     *
2284
     * A variable is considered NOT empty if it does exist or if its value equals TRUE.
2285
     *
2286
     * EXAMPLE: <code>
2287
     * s('')->isNotEmpty(); // false
2288
     * </code>
2289
     *
2290
     * @psalm-mutation-free
2291
     *
2292
     * @return bool
2293
     *              <p>Whether or not $str is empty().</p>
2294
     */
2295 10
    public function isNotEmpty(): bool
2296
    {
2297 10
        return !$this->utf8::is_empty($this->str);
2298
    }
2299
2300
    /**
2301
     * Determine if the string is composed of numeric characters.
2302
     *
2303
     * EXAMPLE: <code>
2304
     * </code>
2305
     *
2306
     * @psalm-mutation-free
2307
     *
2308
     * @return bool
2309
     */
2310 4
    public function isNumeric(): bool
2311
    {
2312 4
        return \is_numeric($this->str);
2313
    }
2314
2315
    /**
2316
     * Determine if the string is composed of printable (non-invisible) characters.
2317
     *
2318
     * EXAMPLE: <code>
2319
     * </code>
2320
     *
2321
     * @psalm-mutation-free
2322
     *
2323
     * @return bool
2324
     */
2325 3
    public function isPrintable(): bool
2326
    {
2327 3
        return $this->utf8::is_printable($this->str);
2328
    }
2329
2330
    /**
2331
     * Determine if the string is composed of punctuation characters.
2332
     *
2333
     * EXAMPLE: <code>
2334
     * </code>
2335
     *
2336
     * @psalm-mutation-free
2337
     *
2338
     * @return bool
2339
     */
2340 3
    public function isPunctuation(): bool
2341
    {
2342 3
        return $this->utf8::is_punctuation($this->str);
2343
    }
2344
2345
    /**
2346
     * Returns true if the string is serialized, false otherwise.
2347
     *
2348
     * EXAMPLE: <code>
2349
     * s('a:1:{s:3:"foo";s:3:"bar";}')->isSerialized(); // true
2350
     * </code>
2351
     *
2352
     * @psalm-mutation-free
2353
     *
2354
     * @return bool
2355
     *              <p>Whether or not $str is serialized.</p>
2356
     */
2357 21
    public function isSerialized(): bool
2358
    {
2359 21
        return $this->utf8::is_serialized($this->str);
2360
    }
2361
2362
    /**
2363
     * Check if two strings are similar.
2364
     *
2365
     * EXAMPLE: <code>
2366
     * </code>
2367
     *
2368
     * @param string $str                     <p>The string to compare against.</p>
2369
     * @param float  $minPercentForSimilarity [optional] <p>The percentage of needed similarity. | Default: 80%</p>
2370
     *
2371
     * @psalm-mutation-free
2372
     *
2373
     * @return bool
2374
     */
2375 2
    public function isSimilar(string $str, float $minPercentForSimilarity = 80.0): bool
2376
    {
2377 2
        return $this->similarity($str) >= $minPercentForSimilarity;
2378
    }
2379
2380
    /**
2381
     * Returns true if the string contains only lower case chars, false
2382
     * otherwise.
2383
     *
2384
     * EXAMPLE: <code>
2385
     * s('FÒÔBÀŘ')->isUpperCase(); // true
2386
     * </code>
2387
     *
2388
     * @psalm-mutation-free
2389
     *
2390
     * @return bool
2391
     *              <p>Whether or not $str contains only lower case characters.</p>
2392
     */
2393 24
    public function isUpperCase(): bool
2394
    {
2395 24
        return $this->utf8::is_uppercase($this->str);
2396
    }
2397
2398
    /**
2399
     * /**
2400
     * Check if $url is an correct url.
2401
     *
2402
     * @param bool $disallow_localhost
2403
     *
2404
     * @psalm-mutation-free
2405
     *
2406
     * @return bool
2407
     */
2408
    public function isUrl(bool $disallow_localhost = false): bool
2409
    {
2410
        return $this->utf8::is_url($this->str, $disallow_localhost);
2411
    }
2412
2413
    /**
2414
     * Check if the string is UTF-16.
2415
     *
2416
     * @psalm-mutation-free
2417
     *
2418
     * @return false|int
2419
     *                   <strong>false</strong> if is't not UTF-16,<br>
2420
     *                   <strong>1</strong> for UTF-16LE,<br>
2421
     *                   <strong>2</strong> for UTF-16BE
2422
     */
2423
    public function isUtf16()
2424
    {
2425
        return $this->utf8::is_utf16($this->str);
2426
    }
2427
2428
    /**
2429
     * Check if the string is UTF-32.
2430
     *
2431
     * @psalm-mutation-free
2432
     *
2433
     * @return false|int
2434
     *                   <strong>false</strong> if is't not UTF-32,<br>
2435
     *                   <strong>1</strong> for UTF-32LE,<br>
2436
     *                   <strong>2</strong> for UTF-32BE
2437
     */
2438
    public function isUtf32()
2439
    {
2440
        return $this->utf8::is_utf32($this->str);
2441
    }
2442
2443
    /**
2444
     * Checks whether the passed input contains only byte sequences that appear valid UTF-8.
2445
     *
2446
     * EXAMPLE: <code>
2447
     * s('Iñtërnâtiônàlizætiøn')->isUtf8(); // true
2448
     * //
2449
     * s("Iñtërnâtiônàlizætiøn\xA0\xA1")->isUtf8(); // false
2450
     * </code>
2451
     *
2452
     * @param bool $strict <p>Check also if the string is not UTF-16 or UTF-32.</p>
2453
     *
2454
     * @psalm-mutation-free
2455
     *
2456
     * @return bool
2457
     */
2458
    public function isUtf8(bool $strict = false): bool
2459
    {
2460
        return $this->utf8::is_utf8($this->str, $strict);
2461
    }
2462
2463
    /**
2464
     * Returns true if the string contains only whitespace chars, false otherwise.
2465
     *
2466
     * EXAMPLE: <code>
2467
     * </code>
2468
     *
2469
     * @psalm-mutation-free
2470
     *
2471
     * @return bool
2472
     *              <p>Whether or not $str contains only whitespace characters.</p>
2473
     */
2474 30
    public function isWhitespace(): bool
2475
    {
2476 30
        return $this->isBlank();
2477
    }
2478
2479
    /**
2480
     * Returns value which can be serialized by json_encode().
2481
     *
2482
     * EXAMPLE: <code>
2483
     * </code>
2484
     *
2485
     * @noinspection ReturnTypeCanBeDeclaredInspection
2486
     *
2487
     * @psalm-mutation-free
2488
     *
2489
     * @return string The current value of the $str property
2490
     */
2491 2
    public function jsonSerialize()
2492
    {
2493 2
        return (string) $this;
2494
    }
2495
2496
    /**
2497
     * Convert the string to kebab-case.
2498
     *
2499
     * EXAMPLE: <code>
2500
     * </code>
2501
     *
2502
     * @psalm-mutation-free
2503
     *
2504
     * @return static
2505
     */
2506 3 View Code Duplication
    public function kebabCase(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2507
    {
2508 3
        $words = \array_map(
2509
            static function (self $word) {
2510 3
                return $word->toLowerCase();
2511 3
            },
2512 3
            $this->words('', true)
2513
        );
2514
2515 3
        return new static(\implode('-', $words), $this->encoding);
2516
    }
2517
2518
    /**
2519
     * Returns the last $n characters of the string.
2520
     *
2521
     * EXAMPLE: <code>
2522
     * s('fòôbàř')->last(3); // 'bàř'
2523
     * </code>
2524
     *
2525
     * @param int $n <p>Number of characters to retrieve from the end.</p>
2526
     *
2527
     * @psalm-mutation-free
2528
     *
2529
     * @return static
2530
     *                <p>Object with its $str being the last $n chars.</p>
2531
     */
2532 36
    public function last(int $n): self
2533
    {
2534 36
        return static::create(
2535 36
            $this->utf8::str_last_char(
2536 36
                $this->str,
2537 36
                $n,
2538 36
                $this->encoding
2539
            ),
2540 36
            $this->encoding
2541
        );
2542
    }
2543
2544
    /**
2545
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2546
     * If no match is found returns new empty Stringy object.
2547
     *
2548
     * EXAMPLE: <code>
2549
     * </code>
2550
     *
2551
     * @param string $needle       <p>The string to look for.</p>
2552
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2553
     *
2554
     * @psalm-mutation-free
2555
     *
2556
     * @return static
2557
     */
2558 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...
2559
    {
2560 4
        return static::create(
2561 4
            $this->utf8::str_substr_last(
2562 4
                $this->str,
2563 4
                $needle,
2564 4
                $beforeNeedle,
2565 4
                $this->encoding
2566
            ),
2567 4
            $this->encoding
2568
        );
2569
    }
2570
2571
    /**
2572
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2573
     * If no match is found returns new empty Stringy object.
2574
     *
2575
     * EXAMPLE: <code>
2576
     * </code>
2577
     *
2578
     * @param string $needle       <p>The string to look for.</p>
2579
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2580
     *
2581
     * @psalm-mutation-free
2582
     *
2583
     * @return static
2584
     */
2585 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...
2586
    {
2587 2
        return static::create(
2588 2
            $this->utf8::str_isubstr_last(
2589 2
                $this->str,
2590 2
                $needle,
2591 2
                $beforeNeedle,
2592 2
                $this->encoding
2593
            ),
2594 2
            $this->encoding
2595
        );
2596
    }
2597
2598
    /**
2599
     * Returns the length of the string.
2600
     *
2601
     * EXAMPLE: <code>
2602
     * s('fòôbàř')->length(); // 6
2603
     * </code>
2604
     *
2605
     * @psalm-mutation-free
2606
     *
2607
     * @return int
2608
     *             <p>The number of characters in $str given the encoding.</p>
2609
     */
2610 17
    public function length(): int
2611
    {
2612 17
        return (int) $this->utf8::strlen($this->str, $this->encoding);
2613
    }
2614
2615
    /**
2616
     * Line-Wrap the string after $limit, but also after the next word.
2617
     *
2618
     * EXAMPLE: <code>
2619
     * </code>
2620
     *
2621
     * @param int         $limit           [optional] <p>The column width.</p>
2622
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2623
     * @param bool        $add_final_break [optional] <p>
2624
     *                                     If this flag is true, then the method will add a $break at the end
2625
     *                                     of the result string.
2626
     *                                     </p>
2627
     * @param string|null $delimiter       [optional] <p>
2628
     *                                     You can change the default behavior, where we split the string by newline.
2629
     *                                     </p>
2630
     *
2631
     * @psalm-mutation-free
2632
     *
2633
     * @return static
2634
     */
2635 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...
2636
        int $limit,
2637
        string $break = "\n",
2638
        bool $add_final_break = true,
2639
        string $delimiter = null
2640
    ): self {
2641 3
        return static::create(
2642 3
            $this->utf8::wordwrap_per_line(
2643 3
                $this->str,
2644 3
                $limit,
2645 3
                $break,
2646 3
                true,
2647 3
                $add_final_break,
2648 3
                $delimiter
2649
            ),
2650 3
            $this->encoding
2651
        );
2652
    }
2653
2654
    /**
2655
     * Line-Wrap the string after $limit, but also after the next word.
2656
     *
2657
     * EXAMPLE: <code>
2658
     * </code>
2659
     *
2660
     * @param int         $limit           [optional] <p>The column width.</p>
2661
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2662
     * @param bool        $add_final_break [optional] <p>
2663
     *                                     If this flag is true, then the method will add a $break at the end
2664
     *                                     of the result string.
2665
     *                                     </p>
2666
     * @param string|null $delimiter       [optional] <p>
2667
     *                                     You can change the default behavior, where we split the string by newline.
2668
     *                                     </p>
2669
     *
2670
     * @psalm-mutation-free
2671
     *
2672
     * @return static
2673
     */
2674 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...
2675
        int $limit,
2676
        string $break = "\n",
2677
        bool $add_final_break = true,
2678
        string $delimiter = null
2679
    ): self {
2680 4
        return static::create(
2681 4
            $this->utf8::wordwrap_per_line(
2682 4
                $this->str,
2683 4
                $limit,
2684 4
                $break,
2685 4
                false,
2686 4
                $add_final_break,
2687 4
                $delimiter
2688
            ),
2689 4
            $this->encoding
2690
        );
2691
    }
2692
2693
    /**
2694
     * Splits on newlines and carriage returns, returning an array of Stringy
2695
     * objects corresponding to the lines in the string.
2696
     *
2697
     * EXAMPLE: <code>
2698
     * s("fòô\r\nbàř\n")->lines(); // ['fòô', 'bàř', '']
2699
     * </code>
2700
     *
2701
     * @psalm-mutation-free
2702
     *
2703
     * @return static[]
2704
     *                  <p>An array of Stringy objects.</p>
2705
     *
2706
     * @psalm-return array<int,static>
2707
     */
2708 51
    public function lines(): array
2709
    {
2710 51
        if ($this->str === '') {
2711 3
            return [static::create('')];
2712
        }
2713
2714 48
        $strings = $this->utf8::str_to_lines($this->str);
2715
        /** @noinspection AlterInForeachInspection */
2716 48
        foreach ($strings as &$str) {
2717 48
            $str = static::create($str, $this->encoding);
2718
        }
2719
2720
        /** @noinspection PhpSillyAssignmentInspection */
2721
        /** @var static[] $strings */
2722 48
        $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...
2723
2724 48
        return $strings;
2725
    }
2726
2727
    /**
2728
     * Splits on newlines and carriage returns, returning an array of Stringy
2729
     * objects corresponding to the lines in the string.
2730
     *
2731
     * EXAMPLE: <code>
2732
     * </code>
2733
     *
2734
     * @psalm-mutation-free
2735
     *
2736
     * @return CollectionStringy|static[]
2737
     *                                    <p>An collection of Stringy objects.</p>
2738
     *
2739
     * @psalm-return CollectionStringy<int,static>
2740
     */
2741 34
    public function linesCollection(): CollectionStringy
2742
    {
2743
        /**
2744
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
2745
         */
2746 34
        return CollectionStringy::create(
2747 34
            $this->lines()
2748
        );
2749
    }
2750
2751
    /**
2752
     * Returns the longest common prefix between the string and $otherStr.
2753
     *
2754
     * EXAMPLE: <code>
2755
     * s('foobar')->longestCommonPrefix('foobaz'); // 'fooba'
2756
     * </code>
2757
     *
2758
     * @param string $otherStr <p>Second string for comparison.</p>
2759
     *
2760
     * @psalm-mutation-free
2761
     *
2762
     * @return static
2763
     *                <p>Object with its $str being the longest common prefix.</p>
2764
     */
2765 30
    public function longestCommonPrefix(string $otherStr): self
2766
    {
2767 30
        return static::create(
2768 30
            $this->utf8::str_longest_common_prefix(
2769 30
                $this->str,
2770 30
                $otherStr,
2771 30
                $this->encoding
2772
            ),
2773 30
            $this->encoding
2774
        );
2775
    }
2776
2777
    /**
2778
     * Returns the longest common substring between the string and $otherStr.
2779
     * In the case of ties, it returns that which occurs first.
2780
     *
2781
     * EXAMPLE: <code>
2782
     * s('foobar')->longestCommonSubstring('boofar'); // 'oo'
2783
     * </code>
2784
     *
2785
     * @param string $otherStr <p>Second string for comparison.</p>
2786
     *
2787
     * @psalm-mutation-free
2788
     *
2789
     * @return static
2790
     *                <p>Object with its $str being the longest common substring.</p>
2791
     */
2792 30
    public function longestCommonSubstring(string $otherStr): self
2793
    {
2794 30
        return static::create(
2795 30
            $this->utf8::str_longest_common_substring(
2796 30
                $this->str,
2797 30
                $otherStr,
2798 30
                $this->encoding
2799
            ),
2800 30
            $this->encoding
2801
        );
2802
    }
2803
2804
    /**
2805
     * Returns the longest common suffix between the string and $otherStr.
2806
     *
2807
     * EXAMPLE: <code>
2808
     * s('fòôbàř')->longestCommonSuffix('fòrbàř'); // 'bàř'
2809
     * </code>
2810
     *
2811
     * @param string $otherStr <p>Second string for comparison.</p>
2812
     *
2813
     * @psalm-mutation-free
2814
     *
2815
     * @return static
2816
     *                <p>Object with its $str being the longest common suffix.</p>
2817
     */
2818 30
    public function longestCommonSuffix(string $otherStr): self
2819
    {
2820 30
        return static::create(
2821 30
            $this->utf8::str_longest_common_suffix(
2822 30
                $this->str,
2823 30
                $otherStr,
2824 30
                $this->encoding
2825
            ),
2826 30
            $this->encoding
2827
        );
2828
    }
2829
2830
    /**
2831
     * Converts the first character of the string to lower case.
2832
     *
2833
     * EXAMPLE: <code>
2834
     * s('Σ Foo')->lowerCaseFirst(); // 'σ Foo'
2835
     * </code>
2836
     *
2837
     * @psalm-mutation-free
2838
     *
2839
     * @return static
2840
     *                <p>Object with the first character of $str being lower case.</p>
2841
     */
2842 16
    public function lowerCaseFirst(): self
2843
    {
2844 16
        return static::create(
2845 16
            $this->utf8::lcfirst($this->str, $this->encoding),
2846 16
            $this->encoding
2847
        );
2848
    }
2849
2850
    /**
2851
     * Determine if the string matches another string regardless of case.
2852
     * Alias for isEqualsCaseInsensitive()
2853
     *
2854
     * EXAMPLE: <code>
2855
     * </code>
2856
     *
2857
     * @psalm-mutation-free
2858
     *
2859
     * @param string|Stringy ...$str
2860
     *                               <p>The string to compare against.</p>
2861
     *
2862
     * @psalm-mutation-free
2863
     *
2864
     * @return bool
2865
     */
2866 3
    public function matchCaseInsensitive(...$str): bool
2867
    {
2868 3
        return $this->isEqualsCaseInsensitive(...$str);
2869
    }
2870
2871
    /**
2872
     * Determine if the string matches another string.
2873
     * Alias for isEqualsCaseSensitive()
2874
     *
2875
     * EXAMPLE: <code>
2876
     * </code>
2877
     *
2878
     * @psalm-mutation-free
2879
     *
2880
     * @param string|Stringy ...$str
2881
     *                               <p>The string to compare against.</p>
2882
     *
2883
     * @psalm-mutation-free
2884
     *
2885
     * @return bool
2886
     */
2887 7
    public function matchCaseSensitive(...$str): bool
2888
    {
2889 7
        return $this->isEqualsCaseSensitive(...$str);
2890
    }
2891
2892
    /**
2893
     * Create a md5 hash from the current string.
2894
     *
2895
     * @psalm-mutation-free
2896
     *
2897
     * @return static
2898
     */
2899 2
    public function md5(): self
2900
    {
2901 2
        return static::create($this->hash('md5'), $this->encoding);
2902
    }
2903
2904
    /**
2905
     * Replace all breaks [<br> | \r\n | \r | \n | ...] into "<br>".
2906
     *
2907
     * EXAMPLE: <code>
2908
     * </code>
2909
     *
2910
     * @return static
2911
     */
2912 1
    public function newLineToHtmlBreak(): self
2913
    {
2914 1
        return $this->removeHtmlBreak('<br>');
2915
    }
2916
2917
    /**
2918
     * Get every nth character of the string.
2919
     *
2920
     * EXAMPLE: <code>
2921
     * </code>
2922
     *
2923
     * @param int $step   <p>The number of characters to step.</p>
2924
     * @param int $offset [optional] <p>The string offset to start at.</p>
2925
     *
2926
     * @psalm-mutation-free
2927
     *
2928
     * @return static
2929
     */
2930 4
    public function nth(int $step, int $offset = 0): self
2931
    {
2932 4
        $length = $step - 1;
2933 4
        $substring = $this->substr($offset)->toString();
2934
2935 4
        if ($substring === '') {
2936
            return new static('', $this->encoding);
2937
        }
2938
2939 4
        \preg_match_all(
2940 4
            "/(?:^|(?:.|\p{L}|\w){" . $length . "})(.|\p{L}|\w)/u",
2941 4
            $substring,
2942 4
            $matches
2943
        );
2944
2945 4
        return new static(\implode('', $matches[1] ?? []), $this->encoding);
2946
    }
2947
2948
    /**
2949
     * Returns whether or not a character exists at an index. Offsets may be
2950
     * negative to count from the last character in the string. Implements
2951
     * part of the ArrayAccess interface.
2952
     *
2953
     * EXAMPLE: <code>
2954
     * </code>
2955
     *
2956
     * @param int $offset <p>The index to check.</p>
2957
     *
2958
     * @psalm-mutation-free
2959
     *
2960
     * @return bool
2961
     *              <p>Whether or not the index exists.</p>
2962
     */
2963 18
    public function offsetExists($offset): bool
2964
    {
2965 18
        return $this->utf8::str_offset_exists(
2966 18
            $this->str,
2967 18
            $offset,
2968 18
            $this->encoding
2969
        );
2970
    }
2971
2972
    /**
2973
     * Returns the character at the given index. Offsets may be negative to
2974
     * count from the last character in the string. Implements part of the
2975
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
2976
     * does not exist.
2977
     *
2978
     * EXAMPLE: <code>
2979
     * </code>
2980
     *
2981
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
2982
     *
2983
     * @throws \OutOfBoundsException
2984
     *                               <p>If the positive or negative offset does not exist.</p>
2985
     *
2986
     * @return string
2987
     *                <p>The character at the specified index.</p>
2988
     *
2989
     * @psalm-mutation-free
2990
     */
2991 6
    public function offsetGet($offset): string
2992
    {
2993 6
        return $this->utf8::str_offset_get($this->str, $offset, $this->encoding);
2994
    }
2995
2996
    /**
2997
     * Implements part of the ArrayAccess interface, but throws an exception
2998
     * when called. This maintains the immutability of Stringy objects.
2999
     *
3000
     * EXAMPLE: <code>
3001
     * </code>
3002
     *
3003
     * @param int   $offset <p>The index of the character.</p>
3004
     * @param mixed $value  <p>Value to set.</p>
3005
     *
3006
     * @throws \Exception
3007
     *                    <p>When called.</p>
3008
     *
3009
     * @return void
3010
     */
3011 3
    public function offsetSet($offset, $value)
3012
    {
3013
        // Stringy is immutable, cannot directly set char
3014
        /** @noinspection ThrowRawExceptionInspection */
3015 3
        throw new \Exception('Stringy object is immutable, cannot modify char');
3016
    }
3017
3018
    /**
3019
     * Implements part of the ArrayAccess interface, but throws an exception
3020
     * when called. This maintains the immutability of Stringy objects.
3021
     *
3022
     * EXAMPLE: <code>
3023
     * </code>
3024
     *
3025
     * @param int $offset <p>The index of the character.</p>
3026
     *
3027
     * @throws \Exception
3028
     *                    <p>When called.</p>
3029
     *
3030
     * @return void
3031
     */
3032 3
    public function offsetUnset($offset)
3033
    {
3034
        // Don't allow directly modifying the string
3035
        /** @noinspection ThrowRawExceptionInspection */
3036 3
        throw new \Exception('Stringy object is immutable, cannot unset char');
3037
    }
3038
3039
    /**
3040
     * Pads the string to a given length with $padStr. If length is less than
3041
     * or equal to the length of the string, no padding takes places. The
3042
     * default string used for padding is a space, and the default type (one of
3043
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
3044
     * if $padType isn't one of those 3 values.
3045
     *
3046
     * EXAMPLE: <code>
3047
     * s('fòôbàř')->pad(9, '-/', 'left'); // '-/-fòôbàř'
3048
     * </code>
3049
     *
3050
     * @param int    $length  <p>Desired string length after padding.</p>
3051
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
3052
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
3053
     *
3054
     * @throws \InvalidArgumentException
3055
     *                                   <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
3056
     *
3057
     * @return static
3058
     *                <p>Object with a padded $str.</p>
3059
     *
3060
     * @psalm-mutation-free
3061
     */
3062 39
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
3063
    {
3064 39
        return static::create(
3065 39
            $this->utf8::str_pad(
3066 39
                $this->str,
3067 39
                $length,
3068 39
                $padStr,
3069 39
                $padType,
3070 39
                $this->encoding
3071
            )
3072
        );
3073
    }
3074
3075
    /**
3076
     * Returns a new string of a given length such that both sides of the
3077
     * string are padded. Alias for pad() with a $padType of 'both'.
3078
     *
3079
     * EXAMPLE: <code>
3080
     * s('foo bar')->padBoth(9, ' '); // ' foo bar '
3081
     * </code>
3082
     *
3083
     * @param int    $length <p>Desired string length after padding.</p>
3084
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
3085
     *
3086
     * @psalm-mutation-free
3087
     *
3088
     * @return static
3089
     *                <p>String with padding applied.</p>
3090
     */
3091 33
    public function padBoth(int $length, string $padStr = ' '): self
3092
    {
3093 33
        return static::create(
3094 33
            $this->utf8::str_pad_both(
3095 33
                $this->str,
3096 33
                $length,
3097 33
                $padStr,
3098 33
                $this->encoding
3099
            )
3100
        );
3101
    }
3102
3103
    /**
3104
     * Returns a new string of a given length such that the beginning of the
3105
     * string is padded. Alias for pad() with a $padType of 'left'.
3106
     *
3107
     * EXAMPLE: <code>
3108
     * s('foo bar')->padLeft(9, ' '); // '  foo bar'
3109
     * </code>
3110
     *
3111
     * @param int    $length <p>Desired string length after padding.</p>
3112
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
3113
     *
3114
     * @psalm-mutation-free
3115
     *
3116
     * @return static
3117
     *                <p>String with left padding.</p>
3118
     */
3119 21
    public function padLeft(int $length, string $padStr = ' '): self
3120
    {
3121 21
        return static::create(
3122 21
            $this->utf8::str_pad_left(
3123 21
                $this->str,
3124 21
                $length,
3125 21
                $padStr,
3126 21
                $this->encoding
3127
            )
3128
        );
3129
    }
3130
3131
    /**
3132
     * Returns a new string of a given length such that the end of the string
3133
     * is padded. Alias for pad() with a $padType of 'right'.
3134
     *
3135
     * EXAMPLE: <code>
3136
     * s('foo bar')->padRight(10, '_*'); // 'foo bar_*_'
3137
     * </code>
3138
     *
3139
     * @param int    $length <p>Desired string length after padding.</p>
3140
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
3141
     *
3142
     * @psalm-mutation-free
3143
     *
3144
     * @return static
3145
     *                <p>String with right padding.</p>
3146
     */
3147 21
    public function padRight(int $length, string $padStr = ' '): self
3148
    {
3149 21
        return static::create(
3150 21
            $this->utf8::str_pad_right(
3151 21
                $this->str,
3152 21
                $length,
3153 21
                $padStr,
3154 21
                $this->encoding
3155
            )
3156
        );
3157
    }
3158
3159
    /**
3160
     * Convert the string to PascalCase.
3161
     * Alias for studlyCase()
3162
     *
3163
     * EXAMPLE: <code>
3164
     * </code>
3165
     *
3166
     * @psalm-mutation-free
3167
     *
3168
     * @return static
3169
     */
3170 3
    public function pascalCase(): self
3171
    {
3172 3
        return $this->studlyCase();
3173
    }
3174
3175
    /**
3176
     * Returns a new string starting with $prefix.
3177
     *
3178
     * EXAMPLE: <code>
3179
     * s('bàř')->prepend('fòô'); // 'fòôbàř'
3180
     * </code>
3181
     *
3182
     * @param string ...$prefix <p>The string to append.</p>
3183
     *
3184
     * @psalm-mutation-free
3185
     *
3186
     * @return static
3187
     *                <p>Object with appended $prefix.</p>
3188
     */
3189 8 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...
3190
    {
3191 8
        if (\count($prefix) <= 1) {
3192
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
3193 6
            $prefix = $prefix[0];
3194
        } else {
3195
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
3196 2
            $prefix = \implode('', $prefix);
3197
        }
3198
3199 8
        return static::create($prefix . $this->str, $this->encoding);
3200
    }
3201
3202
    /**
3203
     * Returns a new string starting with $prefix.
3204
     *
3205
     * EXAMPLE: <code>
3206
     * </code>
3207
     *
3208
     * @param CollectionStringy|static ...$prefix <p>The Stringy objects to append.</p>
3209
     *
3210
     * @psalm-param CollectionStringy<int,static>|static ...$prefix
3211
     *
3212
     * @psalm-mutation-free
3213
     *
3214
     * @return static
3215
     *                <p>Object with appended $prefix.</p>
3216
     */
3217 1 View Code Duplication
    public function prependStringy(...$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...
3218
    {
3219 1
        $prefixStr = '';
3220 1
        foreach ($prefix as $prefixTmp) {
3221 1
            if ($prefixTmp instanceof CollectionStringy) {
3222 1
                $prefixStr .= $prefixTmp->implode('');
3223
            } else {
3224 1
                $prefixStr .= $prefixTmp->toString();
3225
            }
3226
        }
3227
3228 1
        return static::create($prefixStr . $this->str, $this->encoding);
3229
    }
3230
3231
    /**
3232
     * Replaces all occurrences of $pattern in $str by $replacement.
3233
     *
3234
     * EXAMPLE: <code>
3235
     * s('fòô ')->regexReplace('f[òô]+\s', 'bàř'); // 'bàř'
3236
     * s('fò')->regexReplace('(ò)', '\\1ô'); // 'fòô'
3237
     * </code>
3238
     *
3239
     * @param string $pattern     <p>The regular expression pattern.</p>
3240
     * @param string $replacement <p>The string to replace with.</p>
3241
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
3242
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
3243
     *
3244
     * @psalm-mutation-free
3245
     *
3246
     * @return static
3247
     *                <p>Object with the result2ing $str after the replacements.</p>
3248
     */
3249 29
    public function regexReplace(
3250
        string $pattern,
3251
        string $replacement,
3252
        string $options = '',
3253
        string $delimiter = '/'
3254
    ): self {
3255 29
        return static::create(
3256 29
            $this->utf8::regex_replace(
3257 29
                $this->str,
3258 29
                $pattern,
3259 29
                $replacement,
3260 29
                $options,
3261 29
                $delimiter
3262
            ),
3263 29
            $this->encoding
3264
        );
3265
    }
3266
3267
    /**
3268
     * Remove html via "strip_tags()" from the string.
3269
     *
3270
     * EXAMPLE: <code>
3271
     * s('řàb <ô>òf\', ô<br/>foo <a href="#">lall</a>')->removeHtml('<br><br/>'); // 'řàb òf\', ô<br/>foo lall'
3272
     * </code>
3273
     *
3274
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
3275
     *                              not be stripped. Default: null
3276
     *                              </p>
3277
     *
3278
     * @psalm-mutation-free
3279
     *
3280
     * @return static
3281
     */
3282 12
    public function removeHtml(string $allowableTags = ''): self
3283
    {
3284 12
        return static::create(
3285 12
            $this->utf8::remove_html($this->str, $allowableTags),
3286 12
            $this->encoding
3287
        );
3288
    }
3289
3290
    /**
3291
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
3292
     *
3293
     * EXAMPLE: <code>
3294
     * s('řàb <ô>òf\', ô<br/>foo <a href="#">lall</a>')->removeHtmlBreak(''); // 'řàb <ô>òf\', ô< foo <a href="#">lall</a>'
3295
     * </code>
3296
     *
3297
     * @param string $replacement [optional] <p>Default is a empty string.</p>
3298
     *
3299
     * @psalm-mutation-free
3300
     *
3301
     * @return static
3302
     */
3303 13
    public function removeHtmlBreak(string $replacement = ''): self
3304
    {
3305 13
        return static::create(
3306 13
            $this->utf8::remove_html_breaks($this->str, $replacement),
3307 13
            $this->encoding
3308
        );
3309
    }
3310
3311
    /**
3312
     * Returns a new string with the prefix $substring removed, if present.
3313
     *
3314
     * EXAMPLE: <code>
3315
     * s('fòôbàř')->removeLeft('fòô'); // 'bàř'
3316
     * </code>
3317
     *
3318
     * @param string $substring <p>The prefix to remove.</p>
3319
     *
3320
     * @psalm-mutation-free
3321
     *
3322
     * @return static
3323
     *                <p>Object having a $str without the prefix $substring.</p>
3324
     */
3325 36
    public function removeLeft(string $substring): self
3326
    {
3327 36
        return static::create(
3328 36
            $this->utf8::remove_left($this->str, $substring, $this->encoding),
3329 36
            $this->encoding
3330
        );
3331
    }
3332
3333
    /**
3334
     * Returns a new string with the suffix $substring removed, if present.
3335
     *
3336
     * EXAMPLE: <code>
3337
     * s('fòôbàř')->removeRight('bàř'); // 'fòô'
3338
     * </code>
3339
     *
3340
     * @param string $substring <p>The suffix to remove.</p>
3341
     *
3342
     * @psalm-mutation-free
3343
     *
3344
     * @return static
3345
     *                <p>Object having a $str without the suffix $substring.</p>
3346
     */
3347 36
    public function removeRight(string $substring): self
3348
    {
3349 36
        return static::create(
3350 36
            $this->utf8::remove_right($this->str, $substring, $this->encoding),
3351 36
            $this->encoding
3352
        );
3353
    }
3354
3355
    /**
3356
     * Try to remove all XSS-attacks from the string.
3357
     *
3358
     * EXAMPLE: <code>
3359
     * s('<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>')->removeXss(); // '<IMG >'
3360
     * </code>
3361
     *
3362
     * @psalm-mutation-free
3363
     *
3364
     * @return static
3365
     */
3366 12
    public function removeXss(): self
3367
    {
3368
        /**
3369
         * @var AntiXSS|null
3370
         *
3371
         * @psalm-suppress ImpureStaticVariable
3372
         */
3373 12
        static $antiXss = null;
3374
3375 12
        if ($antiXss === null) {
3376 1
            $antiXss = new AntiXSS();
3377
        }
3378
3379
        /**
3380
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the anti-xss class
3381
         */
3382 12
        $str = $antiXss->xss_clean($this->str);
3383
3384 12
        return static::create($str, $this->encoding);
3385
    }
3386
3387
    /**
3388
     * Returns a repeated string given a multiplier.
3389
     *
3390
     * EXAMPLE: <code>
3391
     * s('α')->repeat(3); // 'ααα'
3392
     * </code>
3393
     *
3394
     * @param int $multiplier <p>The number of times to repeat the string.</p>
3395
     *
3396
     * @psalm-mutation-free
3397
     *
3398
     * @return static
3399
     *                <p>Object with a repeated str.</p>
3400
     */
3401 21
    public function repeat(int $multiplier): self
3402
    {
3403 21
        return static::create(
3404 21
            \str_repeat($this->str, $multiplier),
3405 21
            $this->encoding
3406
        );
3407
    }
3408
3409
    /**
3410
     * Replaces all occurrences of $search in $str by $replacement.
3411
     *
3412
     * EXAMPLE: <code>
3413
     * s('fòô bàř fòô bàř')->replace('fòô ', ''); // 'bàř bàř'
3414
     * </code>
3415
     *
3416
     * @param string $search        <p>The needle to search for.</p>
3417
     * @param string $replacement   <p>The string to replace with.</p>
3418
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3419
     *
3420
     * @psalm-mutation-free
3421
     *
3422
     * @return static
3423
     *                <p>Object with the resulting $str after the replacements.</p>
3424
     */
3425 76
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
3426
    {
3427 76
        if ($search === '' && $replacement === '') {
3428 16
            return static::create($this->str, $this->encoding);
3429
        }
3430
3431 60
        if ($this->str === '' && $search === '') {
3432 2
            return static::create($replacement, $this->encoding);
3433
        }
3434
3435 58
        if ($caseSensitive) {
3436 48
            return static::create(
3437 48
                \str_replace($search, $replacement, $this->str),
3438 48
                $this->encoding
3439
            );
3440
        }
3441
3442 10
        return static::create(
3443 10
            $this->utf8::str_ireplace($search, $replacement, $this->str),
3444 10
            $this->encoding
3445
        );
3446
    }
3447
3448
    /**
3449
     * Replaces all occurrences of $search in $str by $replacement.
3450
     *
3451
     * EXAMPLE: <code>
3452
     * s('fòô bàř lall bàř')->replaceAll(['fòÔ ', 'lall'], '', false); // 'bàř bàř'
3453
     * </code>
3454
     *
3455
     * @param string[]        $search        <p>The elements to search for.</p>
3456
     * @param string|string[] $replacement   <p>The string to replace with.</p>
3457
     * @param bool            $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3458
     *
3459
     * @psalm-mutation-free
3460
     *
3461
     * @return static
3462
     *                <p>Object with the resulting $str after the replacements.</p>
3463
     */
3464 61
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
3465
    {
3466 61
        if ($caseSensitive) {
3467 47
            return static::create(
3468 47
                \str_replace($search, $replacement, $this->str),
3469 47
                $this->encoding
3470
            );
3471
        }
3472
3473 14
        return static::create(
3474 14
            $this->utf8::str_ireplace($search, $replacement, $this->str),
3475 14
            $this->encoding
3476
        );
3477
    }
3478
3479
    /**
3480
     * Replaces all occurrences of $search from the beginning of string with $replacement.
3481
     *
3482
     * EXAMPLE: <code>
3483
     * s('fòô bàř fòô bàř')->replaceBeginning('fòô', ''); // ' bàř bàř'
3484
     * </code>
3485
     *
3486
     * @param string $search      <p>The string to search for.</p>
3487
     * @param string $replacement <p>The replacement.</p>
3488
     *
3489
     * @psalm-mutation-free
3490
     *
3491
     * @return static
3492
     *                <p>Object with the resulting $str after the replacements.</p>
3493
     */
3494 32
    public function replaceBeginning(string $search, string $replacement): self
3495
    {
3496 32
        return static::create(
3497 32
            $this->utf8::str_replace_beginning($this->str, $search, $replacement),
3498 32
            $this->encoding
3499
        );
3500
    }
3501
3502
    /**
3503
     * Replaces all occurrences of $search from the ending of string with $replacement.
3504
     *
3505
     * EXAMPLE: <code>
3506
     * s('fòô bàř fòô bàř')->replaceEnding('bàř', ''); // 'fòô bàř fòô '
3507
     * </code>
3508
     *
3509
     * @param string $search      <p>The string to search for.</p>
3510
     * @param string $replacement <p>The replacement.</p>
3511
     *
3512
     * @psalm-mutation-free
3513
     *
3514
     * @return static
3515
     *                <p>Object with the resulting $str after the replacements.</p>
3516
     */
3517 32
    public function replaceEnding(string $search, string $replacement): self
3518
    {
3519 32
        return static::create(
3520 32
            $this->utf8::str_replace_ending($this->str, $search, $replacement),
3521 32
            $this->encoding
3522
        );
3523
    }
3524
3525
    /**
3526
     * Replaces first occurrences of $search from the beginning of string with $replacement.
3527
     *
3528
     * EXAMPLE: <code>
3529
     * </code>
3530
     *
3531
     * @param string $search      <p>The string to search for.</p>
3532
     * @param string $replacement <p>The replacement.</p>
3533
     *
3534
     * @psalm-mutation-free
3535
     *
3536
     * @return static
3537
     *                <p>Object with the resulting $str after the replacements.</p>
3538
     */
3539 32
    public function replaceFirst(string $search, string $replacement): self
3540
    {
3541 32
        return static::create(
3542 32
            $this->utf8::str_replace_first($search, $replacement, $this->str),
3543 32
            $this->encoding
3544
        );
3545
    }
3546
3547
    /**
3548
     * Replaces last occurrences of $search from the ending of string with $replacement.
3549
     *
3550
     * EXAMPLE: <code>
3551
     * </code>
3552
     *
3553
     * @param string $search      <p>The string to search for.</p>
3554
     * @param string $replacement <p>The replacement.</p>
3555
     *
3556
     * @psalm-mutation-free
3557
     *
3558
     * @return static
3559
     *                <p>Object with the resulting $str after the replacements.</p>
3560
     */
3561 30
    public function replaceLast(string $search, string $replacement): self
3562
    {
3563 30
        return static::create(
3564 30
            $this->utf8::str_replace_last($search, $replacement, $this->str),
3565 30
            $this->encoding
3566
        );
3567
    }
3568
3569
    /**
3570
     * Returns a reversed string. A multibyte version of strrev().
3571
     *
3572
     * EXAMPLE: <code>
3573
     * s('fòôbàř')->reverse(); // 'řàbôòf'
3574
     * </code>
3575
     *
3576
     * @psalm-mutation-free
3577
     *
3578
     * @return static
3579
     *                <p>Object with a reversed $str.</p>
3580
     */
3581 15
    public function reverse(): self
3582
    {
3583 15
        return static::create($this->utf8::strrev($this->str), $this->encoding);
3584
    }
3585
3586
    /**
3587
     * Truncates the string to a given length, while ensuring that it does not
3588
     * split words. If $substring is provided, and truncating occurs, the
3589
     * string is further truncated so that the substring may be appended without
3590
     * exceeding the desired length.
3591
     *
3592
     * EXAMPLE: <code>
3593
     * s('What are your plans today?')->safeTruncate(22, '...'); // 'What are your plans...'
3594
     * </code>
3595
     *
3596
     * @param int    $length                          <p>Desired length of the truncated string.</p>
3597
     * @param string $substring                       [optional] <p>The substring to append if it can fit. Default: ''</p>
3598
     * @param bool   $ignoreDoNotSplitWordsForOneWord
3599
     *
3600
     * @psalm-mutation-free
3601
     *
3602
     * @return static
3603
     *                <p>Object with the resulting $str after truncating.</p>
3604
     */
3605 68
    public function safeTruncate(
3606
        int $length,
3607
        string $substring = '',
3608
        bool $ignoreDoNotSplitWordsForOneWord = true
3609
    ): self {
3610 68
        return static::create(
3611 68
            $this->utf8::str_truncate_safe(
3612 68
                $this->str,
3613 68
                $length,
3614 68
                $substring,
3615 68
                $this->encoding,
3616 68
                $ignoreDoNotSplitWordsForOneWord
3617
            ),
3618 68
            $this->encoding
3619
        );
3620
    }
3621
3622
    /**
3623
     * Set the internal character encoding.
3624
     *
3625
     * EXAMPLE: <code>
3626
     * </code>
3627
     *
3628
     * @param string $new_encoding <p>The desired character encoding.</p>
3629
     *
3630
     * @psalm-mutation-free
3631
     *
3632
     * @return static
3633
     */
3634 1
    public function setInternalEncoding(string $new_encoding): self
3635
    {
3636 1
        return new static($this->str, $new_encoding);
3637
    }
3638
3639
    /**
3640
     * Create a sha1 hash from the current string.
3641
     *
3642
     * EXAMPLE: <code>
3643
     * </code>
3644
     *
3645
     * @psalm-mutation-free
3646
     *
3647
     * @return static
3648
     */
3649 2
    public function sha1(): self
3650
    {
3651 2
        return static::create($this->hash('sha1'), $this->encoding);
3652
    }
3653
3654
    /**
3655
     * Create a sha256 hash from the current string.
3656
     *
3657
     * EXAMPLE: <code>
3658
     * </code>
3659
     *
3660
     * @psalm-mutation-free
3661
     *
3662
     * @return static
3663
     */
3664 2
    public function sha256(): self
3665
    {
3666 2
        return static::create($this->hash('sha256'), $this->encoding);
3667
    }
3668
3669
    /**
3670
     * Create a sha512 hash from the current string.
3671
     *
3672
     * EXAMPLE: <code>
3673
     * </code>
3674
     *
3675
     * @psalm-mutation-free
3676
     *
3677
     * @return static
3678
     */
3679 2
    public function sha512(): self
3680
    {
3681 2
        return static::create($this->hash('sha512'), $this->encoding);
3682
    }
3683
3684
    /**
3685
     * Shorten the string after $length, but also after the next word.
3686
     *
3687
     * EXAMPLE: <code>
3688
     * s('this is a test')->shortenAfterWord(2, '...'); // 'this...'
3689
     * </code>
3690
     *
3691
     * @param int    $length   <p>The given length.</p>
3692
     * @param string $strAddOn [optional] <p>Default: '…'</p>
3693
     *
3694
     * @psalm-mutation-free
3695
     *
3696
     * @return static
3697
     */
3698 8
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
3699
    {
3700 8
        return static::create(
3701 8
            $this->utf8::str_limit_after_word($this->str, $length, $strAddOn),
3702 8
            $this->encoding
3703
        );
3704
    }
3705
3706
    /**
3707
     * A multibyte string shuffle function. It returns a string with its
3708
     * characters in random order.
3709
     *
3710
     * EXAMPLE: <code>
3711
     * s('fòôbàř')->shuffle(); // 'àôřbòf'
3712
     * </code>
3713
     *
3714
     * @return static
3715
     *                <p>Object with a shuffled $str.</p>
3716
     */
3717 9
    public function shuffle(): self
3718
    {
3719 9
        return static::create($this->utf8::str_shuffle($this->str), $this->encoding);
3720
    }
3721
3722
    /**
3723
     * Calculate the similarity between two strings.
3724
     *
3725
     * EXAMPLE: <code>
3726
     * </code>
3727
     *
3728
     * @param string $str <p>The delimiting string.</p>
3729
     *
3730
     * @psalm-mutation-free
3731
     *
3732
     * @return float
3733
     */
3734 2
    public function similarity(string $str): float
3735
    {
3736 2
        \similar_text($this->str, $str, $percent);
3737
3738 2
        return $percent;
3739
    }
3740
3741
    /**
3742
     * Returns the substring beginning at $start, and up to, but not including
3743
     * the index specified by $end. If $end is omitted, the function extracts
3744
     * the remaining string. If $end is negative, it is computed from the end
3745
     * of the string.
3746
     *
3747
     * EXAMPLE: <code>
3748
     * s('fòôbàř')->slice(3, -1); // 'bà'
3749
     * </code>
3750
     *
3751
     * @param int $start <p>Initial index from which to begin extraction.</p>
3752
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
3753
     *
3754
     * @psalm-mutation-free
3755
     *
3756
     * @return static
3757
     *                <p>Object with its $str being the extracted substring.</p>
3758
     */
3759 50
    public function slice(int $start, int $end = null): self
3760
    {
3761 50
        return static::create(
3762 50
            $this->utf8::str_slice($this->str, $start, $end, $this->encoding),
3763 50
            $this->encoding
3764
        );
3765
    }
3766
3767
    /**
3768
     * Converts the string into an URL slug. This includes replacing non-ASCII
3769
     * characters with their closest ASCII equivalents, removing remaining
3770
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
3771
     * $separator. The separator defaults to a single dash, and the string
3772
     * is also converted to lowercase. The language of the source string can
3773
     * also be supplied for language-specific transliteration.
3774
     *
3775
     * EXAMPLE: <code>
3776
     * s('Using strings like fòô bàř')->slugify(); // 'using-strings-like-foo-bar'
3777
     * </code>
3778
     *
3779
     * @param string                $separator             [optional] <p>The string used to replace whitespace.</p>
3780
     * @param string                $language              [optional] <p>Language of the source string.</p>
3781
     * @param array<string, string> $replacements          [optional] <p>A map of replaceable strings.</p>
3782
     * @param bool                  $replace_extra_symbols [optional]  <p>Add some more replacements e.g. "£" with "
3783
     *                                                     pound ".</p>
3784
     * @param bool                  $use_str_to_lower      [optional] <p>Use "string to lower" for the input.</p>
3785
     * @param bool                  $use_transliterate     [optional]  <p>Use ASCII::to_transliterate() for unknown
3786
     *                                                     chars.</p>
3787
     *
3788
     * @psalm-mutation-free
3789
     *
3790
     * @return static
3791
     *                <p>Object whose $str has been converted to an URL slug.</p>
3792
     *
3793
     * @noinspection PhpTooManyParametersInspection
3794
     */
3795 17
    public function slugify(
3796
        string $separator = '-',
3797
        string $language = 'en',
3798
        array $replacements = [],
3799
        bool $replace_extra_symbols = true,
3800
        bool $use_str_to_lower = true,
3801
        bool $use_transliterate = false
3802
    ): self {
3803 17
        return static::create(
3804 17
            $this->ascii::to_slugify(
3805 17
                $this->str,
3806 17
                $separator,
3807 17
                $language,
3808 17
                $replacements,
3809 17
                $replace_extra_symbols,
3810 17
                $use_str_to_lower,
3811 17
                $use_transliterate
3812
            ),
3813 17
            $this->encoding
3814
        );
3815
    }
3816
3817
    /**
3818
     * Convert the string to snake_case.
3819
     *
3820
     * EXAMPLE: <code>
3821
     * </code>
3822
     *
3823
     * @psalm-mutation-free
3824
     *
3825
     * @return static
3826
     */
3827 3 View Code Duplication
    public function snakeCase(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3828
    {
3829 3
        $words = \array_map(
3830
            static function (self $word) {
3831 3
                return $word->toLowerCase();
3832 3
            },
3833 3
            $this->words('', true)
3834
        );
3835
3836 3
        return new static(\implode('_', $words), $this->encoding);
3837
    }
3838
3839
    /**
3840
     * Convert a string to snake_case.
3841
     *
3842
     * EXAMPLE: <code>
3843
     * s('foo1 Bar')->snakeize(); // 'foo_1_bar'
3844
     * </code>
3845
     *
3846
     * @psalm-mutation-free
3847
     *
3848
     * @return static
3849
     *                <p>Object with $str in snake_case.</p>
3850
     */
3851 40
    public function snakeize(): self
3852
    {
3853 40
        return static::create(
3854 40
            $this->utf8::str_snakeize($this->str, $this->encoding),
3855 40
            $this->encoding
3856
        );
3857
    }
3858
3859
    /**
3860
     * Wrap the string after the first whitespace character after a given number
3861
     * of characters.
3862
     *
3863
     * EXAMPLE: <code>
3864
     * </code>
3865
     *
3866
     * @param int    $width <p>Number of characters at which to wrap.</p>
3867
     * @param string $break [optional] <p>Character used to break the string. | Default "\n"</p>
3868
     *
3869
     * @psalm-mutation-free
3870
     *
3871
     * @return static
3872
     */
3873 2
    public function softWrap(int $width, string $break = "\n"): self
3874
    {
3875 2
        return $this->lineWrapAfterWord($width, $break, false);
3876
    }
3877
3878
    /**
3879
     * Splits the string with the provided regular expression, returning an
3880
     * array of Stringy objects. An optional integer $limit will truncate the
3881
     * results.
3882
     *
3883
     * EXAMPLE: <code>
3884
     * s('foo,bar,baz')->split(',', 2); // ['foo', 'bar']
3885
     * </code>
3886
     *
3887
     * @param string $pattern <p>The regex with which to split the string.</p>
3888
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no
3889
     *                        limit</p>
3890
     *
3891
     * @psalm-mutation-free
3892
     *
3893
     * @return static[]
3894
     *                  <p>An array of Stringy objects.</p>
3895
     *
3896
     * @psalm-return array<int,static>
3897
     */
3898 51
    public function split(string $pattern, int $limit = null): array
3899
    {
3900 51
        if ($this->str === '') {
3901
            return [];
3902
        }
3903
3904 51
        if ($limit === null) {
3905 7
            $limit = -1;
3906
        }
3907
3908 51
        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
3909
        /** @noinspection AlterInForeachInspection */
3910 51
        foreach ($array as $i => &$value) {
3911 45
            $value = static::create($value, $this->encoding);
3912
        }
3913
3914
        /** @noinspection PhpSillyAssignmentInspection */
3915
        /** @var static[] $array */
3916 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...
3917
3918 51
        return $array;
3919
    }
3920
3921
    /**
3922
     * Splits the string with the provided regular expression, returning an
3923
     * collection of Stringy objects. An optional integer $limit will truncate the
3924
     * results.
3925
     *
3926
     * EXAMPLE: <code>
3927
     * </code>
3928
     *
3929
     * @param string $pattern <p>The regex with which to split the string.</p>
3930
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no
3931
     *                        limit</p>
3932
     *
3933
     * @psalm-mutation-free
3934
     *
3935
     * @return CollectionStringy|static[]
3936
     *                                    <p>An collection of Stringy objects.</p>
3937
     *
3938
     * @psalm-return CollectionStringy<int,static>
3939
     */
3940 35
    public function splitCollection(string $pattern, int $limit = null): CollectionStringy
3941
    {
3942
        /**
3943
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3944
         */
3945 35
        return CollectionStringy::create(
3946 35
            $this->split($pattern, $limit)
3947
        );
3948
    }
3949
3950
    /**
3951
     * Returns true if the string begins with $substring, false otherwise. By
3952
     * default, the comparison is case-sensitive, but can be made insensitive
3953
     * by setting $caseSensitive to false.
3954
     *
3955
     * EXAMPLE: <code>
3956
     * s('FÒÔbàřbaz')->startsWith('fòôbàř', false); // true
3957
     * </code>
3958
     *
3959
     * @param string $substring     <p>The substring to look for.</p>
3960
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3961
     *
3962
     * @psalm-mutation-free
3963
     *
3964
     * @return bool
3965
     *              <p>Whether or not $str starts with $substring.</p>
3966
     */
3967 99
    public function startsWith(string $substring, bool $caseSensitive = true): bool
3968
    {
3969 99
        if ($caseSensitive) {
3970 53
            return $this->utf8::str_starts_with($this->str, $substring);
3971
        }
3972
3973 46
        return $this->utf8::str_istarts_with($this->str, $substring);
3974
    }
3975
3976
    /**
3977
     * Returns true if the string begins with any of $substrings, false otherwise.
3978
     * By default the comparison is case-sensitive, but can be made insensitive by
3979
     * setting $caseSensitive to false.
3980
     *
3981
     * EXAMPLE: <code>
3982
     * s('FÒÔbàřbaz')->startsWithAny(['fòô', 'bàř'], false); // true
3983
     * </code>
3984
     *
3985
     * @param string[] $substrings    <p>Substrings to look for.</p>
3986
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3987
     *
3988
     * @psalm-mutation-free
3989
     *
3990
     * @return bool
3991
     *              <p>Whether or not $str starts with $substring.</p>
3992
     */
3993 35
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
3994
    {
3995 35
        if ($caseSensitive) {
3996 23
            return $this->utf8::str_starts_with_any($this->str, $substrings);
3997
        }
3998
3999 12
        return $this->utf8::str_istarts_with_any($this->str, $substrings);
4000
    }
4001
4002
    /**
4003
     * Remove one or more strings from the string.
4004
     *
4005
     * EXAMPLE: <code>
4006
     * </code>
4007
     *
4008
     * @param string|string[] $search One or more strings to be removed
4009
     *
4010
     * @psalm-mutation-free
4011
     *
4012
     * @return static
4013
     */
4014 3
    public function strip($search): self
4015
    {
4016 3
        if (\is_array($search)) {
4017 1
            return $this->replaceAll($search, '');
4018
        }
4019
4020 2
        return $this->replace($search, '');
4021
    }
4022
4023
    /**
4024
     * Strip all whitespace characters. This includes tabs and newline characters,
4025
     * as well as multibyte whitespace such as the thin space and ideographic space.
4026
     *
4027
     * EXAMPLE: <code>
4028
     * s('   Ο     συγγραφέας  ')->stripWhitespace(); // 'Οσυγγραφέας'
4029
     * </code>
4030
     *
4031
     * @psalm-mutation-free
4032
     *
4033
     * @return static
4034
     */
4035 36
    public function stripWhitespace(): self
4036
    {
4037 36
        return static::create(
4038 36
            $this->utf8::strip_whitespace($this->str),
4039 36
            $this->encoding
4040
        );
4041
    }
4042
4043
    /**
4044
     * Remove css media-queries.
4045
     *
4046
     * EXAMPLE: <code>
4047
     * s('test @media (min-width:660px){ .des-cla #mv-tiles{width:480px} } test ')->stripeCssMediaQueries(); // 'test  test '
4048
     * </code>
4049
     *
4050
     * @psalm-mutation-free
4051
     *
4052
     * @return static
4053
     */
4054 2
    public function stripeCssMediaQueries(): self
4055
    {
4056 2
        return static::create(
4057 2
            $this->utf8::css_stripe_media_queries($this->str),
4058 2
            $this->encoding
4059
        );
4060
    }
4061
4062
    /**
4063
     * Remove empty html-tag.
4064
     *
4065
     * EXAMPLE: <code>
4066
     * s('foo<h1></h1>bar')->stripeEmptyHtmlTags(); // 'foobar'
4067
     * </code>
4068
     *
4069
     * @psalm-mutation-free
4070
     *
4071
     * @return static
4072
     */
4073 2
    public function stripeEmptyHtmlTags(): self
4074
    {
4075 2
        return static::create(
4076 2
            $this->utf8::html_stripe_empty_tags($this->str),
4077 2
            $this->encoding
4078
        );
4079
    }
4080
4081
    /**
4082
     * Convert the string to StudlyCase.
4083
     *
4084
     * EXAMPLE: <code>
4085
     * </code>
4086
     *
4087
     * @psalm-mutation-free
4088
     *
4089
     * @return static
4090
     */
4091 6
    public function studlyCase(): self
4092
    {
4093 6
        $words = \array_map(
4094
            static function (self $word) {
4095 6
                return $word->substr(0, 1)
4096 6
                    ->toUpperCase()
4097 6
                    ->appendStringy($word->substr(1));
4098 6
            },
4099 6
            $this->words('', true)
4100
        );
4101
4102 6
        return new static(\implode('', $words), $this->encoding);
4103
    }
4104
4105
    /**
4106
     * Returns the substring beginning at $start with the specified $length.
4107
     * It differs from the $this->utf8::substr() function in that providing a $length of
4108
     * null will return the rest of the string, rather than an empty string.
4109
     *
4110
     * EXAMPLE: <code>
4111
     * </code>
4112
     *
4113
     * @param int $start  <p>Position of the first character to use.</p>
4114
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
4115
     *
4116
     * @psalm-mutation-free
4117
     *
4118
     * @return static
4119
     *                <p>Object with its $str being the substring.</p>
4120
     */
4121 40
    public function substr(int $start, int $length = null): self
4122
    {
4123 40
        return static::create(
4124 40
            $this->utf8::substr(
4125 40
                $this->str,
4126 40
                $start,
4127 40
                $length,
4128 40
                $this->encoding
4129
            ),
4130 40
            $this->encoding
4131
        );
4132
    }
4133
4134
    /**
4135
     * Return part of the string.
4136
     * Alias for substr()
4137
     *
4138
     * EXAMPLE: <code>
4139
     * s('fòôbàř')->substring(2, 3); // 'ôbà'
4140
     * </code>
4141
     *
4142
     * @param int $start  <p>Starting position of the substring.</p>
4143
     * @param int $length [optional] <p>Length of substring.</p>
4144
     *
4145
     * @psalm-mutation-free
4146
     *
4147
     * @return static
4148
     */
4149 3
    public function substring(int $start, int $length = null): self
4150
    {
4151 3
        if ($length === null) {
4152 2
            return $this->substr($start);
4153
        }
4154
4155 3
        return $this->substr($start, $length);
4156
    }
4157
4158
    /**
4159
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
4160
     * If no match is found returns new empty Stringy object.
4161
     *
4162
     * EXAMPLE: <code>
4163
     * </code>
4164
     *
4165
     * @param string $needle       <p>The string to look for.</p>
4166
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
4167
     *
4168
     * @psalm-mutation-free
4169
     *
4170
     * @return static
4171
     */
4172 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...
4173
    {
4174 4
        return static::create(
4175 4
            $this->utf8::str_substr_first(
4176 4
                $this->str,
4177 4
                $needle,
4178 4
                $beforeNeedle,
4179 4
                $this->encoding
4180
            ),
4181 4
            $this->encoding
4182
        );
4183
    }
4184
4185
    /**
4186
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
4187
     * If no match is found returns new empty Stringy object.
4188
     *
4189
     * EXAMPLE: <code>
4190
     * </code>
4191
     *
4192
     * @param string $needle       <p>The string to look for.</p>
4193
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
4194
     *
4195
     * @psalm-mutation-free
4196
     *
4197
     * @return static
4198
     */
4199 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...
4200
    {
4201 4
        return static::create(
4202 4
            $this->utf8::str_isubstr_first(
4203 4
                $this->str,
4204 4
                $needle,
4205 4
                $beforeNeedle,
4206 4
                $this->encoding
4207
            ),
4208 4
            $this->encoding
4209
        );
4210
    }
4211
4212
    /**
4213
     * Surrounds $str with the given substring.
4214
     *
4215
     * EXAMPLE: <code>
4216
     * s(' ͜ ')->surround('ʘ'); // 'ʘ ͜ ʘ'
4217
     * </code>
4218
     *
4219
     * @param string $substring <p>The substring to add to both sides.</P>
4220
     *
4221
     * @psalm-mutation-free
4222
     *
4223
     * @return static
4224
     *                <p>Object whose $str had the substring both prepended and appended.</p>
4225
     */
4226 15
    public function surround(string $substring): self
4227
    {
4228 15
        return static::create(
4229 15
            $substring . $this->str . $substring,
4230 15
            $this->encoding
4231
        );
4232
    }
4233
4234
    /**
4235
     * Returns a case swapped version of the string.
4236
     *
4237
     * EXAMPLE: <code>
4238
     * s('Ντανιλ')->swapCase(); // 'νΤΑΝΙΛ'
4239
     * </code>
4240
     *
4241
     * @psalm-mutation-free
4242
     *
4243
     * @return static
4244
     *                <p>Object whose $str has each character's case swapped.</P>
4245
     */
4246 15
    public function swapCase(): self
4247
    {
4248 15
        return static::create(
4249 15
            $this->utf8::swapCase($this->str, $this->encoding),
4250 15
            $this->encoding
4251
        );
4252
    }
4253
4254
    /**
4255
     * Returns a string with smart quotes, ellipsis characters, and dashes from
4256
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
4257
     * equivalents.
4258
     *
4259
     * EXAMPLE: <code>
4260
     * s('“I see…”')->tidy(); // '"I see..."'
4261
     * </code>
4262
     *
4263
     * @psalm-mutation-free
4264
     *
4265
     * @return static
4266
     *                <p>Object whose $str has those characters removed.</p>
4267
     */
4268 12
    public function tidy(): self
4269
    {
4270 12
        return static::create(
4271 12
            $this->ascii::normalize_msword($this->str),
4272 12
            $this->encoding
4273
        );
4274
    }
4275
4276
    /**
4277
     * Returns a trimmed string with the first letter of each word capitalized.
4278
     * Also accepts an array, $ignore, allowing you to list words not to be
4279
     * capitalized.
4280
     *
4281
     * EXAMPLE: <code>
4282
     * $ignore = ['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the'];
4283
     * s('i like to watch television')->titleize($ignore); // 'I Like to Watch Television'
4284
     * </code>
4285
     *
4286
     * @param array|string[]|null $ignore            [optional] <p>An array of words not to capitalize or null.
4287
     *                                               Default: null</p>
4288
     * @param string|null         $word_define_chars [optional] <p>An string of chars that will be used as whitespace
4289
     *                                               separator === words.</p>
4290
     * @param string|null         $language          [optional] <p>Language of the source string.</p>
4291
     *
4292
     * @psalm-mutation-free
4293
     *
4294
     * @return static
4295
     *                <p>Object with a titleized $str.</p>
4296
     */
4297 23
    public function titleize(
4298
        array $ignore = null,
4299
        string $word_define_chars = null,
4300
        string $language = null
4301
    ): self {
4302 23
        return static::create(
4303 23
            $this->utf8::str_titleize(
4304 23
                $this->str,
4305 23
                $ignore,
4306 23
                $this->encoding,
4307 23
                false,
4308 23
                $language,
4309 23
                false,
4310 23
                true,
4311 23
                $word_define_chars
4312
            ),
4313 23
            $this->encoding
4314
        );
4315
    }
4316
4317
    /**
4318
     * Returns a trimmed string in proper title case: Also accepts an array, $ignore, allowing you to list words not to
4319
     * be capitalized.
4320
     *
4321
     * EXAMPLE: <code>
4322
     * </code>
4323
     *
4324
     * Adapted from John Gruber's script.
4325
     *
4326
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
4327
     *
4328
     * @param string[] $ignore <p>An array of words not to capitalize.</p>
4329
     *
4330
     * @psalm-mutation-free
4331
     *
4332
     * @return static
4333
     *                <p>Object with a titleized $str</p>
4334
     */
4335 70
    public function titleizeForHumans(array $ignore = []): self
4336
    {
4337 70
        return static::create(
4338 70
            $this->utf8::str_titleize_for_humans(
4339 70
                $this->str,
4340 70
                $ignore,
4341 70
                $this->encoding
4342
            ),
4343 70
            $this->encoding
4344
        );
4345
    }
4346
4347
    /**
4348
     * Returns an ASCII version of the string. A set of non-ASCII characters are
4349
     * replaced with their closest ASCII counterparts, and the rest are removed
4350
     * by default. The language or locale of the source string can be supplied
4351
     * for language-specific transliteration in any of the following formats:
4352
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
4353
     * to "aeoeue" rather than "aou" as in other languages.
4354
     *
4355
     * EXAMPLE: <code>
4356
     * s('fòôbàř')->toAscii(); // 'foobar'
4357
     * </code>
4358
     *
4359
     * @param string $language          [optional] <p>Language of the source string.</p>
4360
     * @param bool   $removeUnsupported [optional] <p>Whether or not to remove the
4361
     *                                  unsupported characters.</p>
4362
     *
4363
     * @psalm-mutation-free
4364
     *
4365
     * @return static
4366
     *                <p>Object whose $str contains only ASCII characters.</p>
4367
     */
4368 23
    public function toAscii(string $language = 'en', bool $removeUnsupported = true): self
4369
    {
4370 23
        return static::create(
4371 23
            $this->ascii::to_ascii(
4372 23
                $this->str,
4373 23
                $language,
4374 23
                $removeUnsupported
4375
            ),
4376 23
            $this->encoding
4377
        );
4378
    }
4379
4380
    /**
4381
     * Returns a boolean representation of the given logical string value.
4382
     * For example, <strong>'true', '1', 'on' and 'yes'</strong> will return true. <strong>'false', '0',
4383
     * 'off', and 'no'</strong> will return false. In all instances, case is ignored.
4384
     * For other numeric strings, their sign will determine the return value.
4385
     * In addition, blank strings consisting of only whitespace will return
4386
     * false. For all other strings, the return value is a result of a
4387
     * boolean cast.
4388
     *
4389
     * EXAMPLE: <code>
4390
     * s('OFF')->toBoolean(); // false
4391
     * </code>
4392
     *
4393
     * @psalm-mutation-free
4394
     *
4395
     * @return bool
4396
     *              <p>A boolean value for the string.</p>
4397
     */
4398 45
    public function toBoolean(): bool
4399
    {
4400
        /**
4401
         * @psalm-suppress ArgumentTypeCoercion -> maybe the string looks like an int ;)
4402
         * @phpstan-ignore-next-line
4403
         */
4404 45
        return $this->utf8::to_boolean($this->str);
4405
    }
4406
4407
    /**
4408
     * Converts all characters in the string to lowercase.
4409
     *
4410
     * EXAMPLE: <code>
4411
     * s('FÒÔBÀŘ')->toLowerCase(); // 'fòôbàř'
4412
     * </code>
4413
     *
4414
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
4415
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
4416
     *
4417
     * @psalm-mutation-free
4418
     *
4419
     * @return static
4420
     *                <p>Object with all characters of $str being lowercase.</p>
4421
     */
4422 23 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...
4423
    {
4424 23
        return static::create(
4425 23
            $this->utf8::strtolower(
4426 23
                $this->str,
4427 23
                $this->encoding,
4428 23
                false,
4429 23
                $lang,
4430 23
                $tryToKeepStringLength
4431
            ),
4432 23
            $this->encoding
4433
        );
4434
    }
4435
4436
    /**
4437
     * Converts each tab in the string to some number of spaces, as defined by
4438
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
4439
     *
4440
     * EXAMPLE: <code>
4441
     * s(' String speech = "Hi"')->toSpaces(); // '    String speech = "Hi"'
4442
     * </code>
4443
     *
4444
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
4445
     *
4446
     * @psalm-mutation-free
4447
     *
4448
     * @return static
4449
     *                <p>Object whose $str has had tabs switched to spaces.</p>
4450
     */
4451 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...
4452
    {
4453 18
        if ($tabLength === 4) {
4454 9
            $tab = '    ';
4455 9
        } elseif ($tabLength === 2) {
4456 3
            $tab = '  ';
4457
        } else {
4458 6
            $tab = \str_repeat(' ', $tabLength);
4459
        }
4460
4461 18
        return static::create(
4462 18
            \str_replace("\t", $tab, $this->str),
4463 18
            $this->encoding
4464
        );
4465
    }
4466
4467
    /**
4468
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
4469
     * string.
4470
     *
4471
     * EXAMPLE: <code>
4472
     * s('fòôbàř')->toString(); // 'fòôbàř'
4473
     * </code>
4474
     *
4475
     * @psalm-mutation-free
4476
     *
4477
     * @return string
4478
     */
4479 2200
    public function toString(): string
4480
    {
4481 2200
        return (string) $this->str;
4482
    }
4483
4484
    /**
4485
     * Converts each occurrence of some consecutive number of spaces, as
4486
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
4487
     * are converted to a tab.
4488
     *
4489
     * EXAMPLE: <code>
4490
     * s('    fòô    bàř')->toTabs(); // '   fòô bàř'
4491
     * </code>
4492
     *
4493
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
4494
     *
4495
     * @psalm-mutation-free
4496
     *
4497
     * @return static
4498
     *                <p>Object whose $str has had spaces switched to tabs.</p>
4499
     */
4500 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...
4501
    {
4502 15
        if ($tabLength === 4) {
4503 9
            $tab = '    ';
4504 6
        } elseif ($tabLength === 2) {
4505 3
            $tab = '  ';
4506
        } else {
4507 3
            $tab = \str_repeat(' ', $tabLength);
4508
        }
4509
4510 15
        return static::create(
4511 15
            \str_replace($tab, "\t", $this->str),
4512 15
            $this->encoding
4513
        );
4514
    }
4515
4516
    /**
4517
     * Converts the first character of each word in the string to uppercase
4518
     * and all other chars to lowercase.
4519
     *
4520
     * EXAMPLE: <code>
4521
     * s('fòô bàř')->toTitleCase(); // 'Fòô Bàř'
4522
     * </code>
4523
     *
4524
     * @psalm-mutation-free
4525
     *
4526
     * @return static
4527
     *                <p>Object with all characters of $str being title-cased.</p>
4528
     */
4529 15
    public function toTitleCase(): self
4530
    {
4531 15
        return static::create(
4532 15
            $this->utf8::titlecase($this->str, $this->encoding),
4533 15
            $this->encoding
4534
        );
4535
    }
4536
4537
    /**
4538
     * Returns an ASCII version of the string. A set of non-ASCII characters are
4539
     * replaced with their closest ASCII counterparts, and the rest are removed
4540
     * unless instructed otherwise.
4541
     *
4542
     * EXAMPLE: <code>
4543
     * </code>
4544
     *
4545
     * @param bool   $strict  [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad
4546
     *                        performance | Default: false</p>
4547
     * @param string $unknown [optional] <p>Character use if character unknown. (default is ?)</p>
4548
     *
4549
     * @psalm-mutation-free
4550
     *
4551
     * @return static
4552
     *                <p>Object whose $str contains only ASCII characters.</p>
4553
     */
4554 34
    public function toTransliterate(bool $strict = false, string $unknown = '?'): self
4555
    {
4556 34
        return static::create(
4557 34
            $this->ascii::to_transliterate($this->str, $unknown, $strict),
4558 34
            $this->encoding
4559
        );
4560
    }
4561
4562
    /**
4563
     * Converts all characters in the string to uppercase.
4564
     *
4565
     * EXAMPLE: <code>
4566
     * s('fòôbàř')->toUpperCase(); // 'FÒÔBÀŘ'
4567
     * </code>
4568
     *
4569
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
4570
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
4571
     *
4572
     * @psalm-mutation-free
4573
     *
4574
     * @return static
4575
     *                <p>Object with all characters of $str being uppercase.</p>
4576
     */
4577 26 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...
4578
    {
4579 26
        return static::create(
4580 26
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
4581 26
            $this->encoding
4582
        );
4583
    }
4584
4585
    /**
4586
     * Returns a string with whitespace removed from the start and end of the
4587
     * string. Supports the removal of unicode whitespace. Accepts an optional
4588
     * string of characters to strip instead of the defaults.
4589
     *
4590
     * EXAMPLE: <code>
4591
     * s('  fòôbàř  ')->trim(); // 'fòôbàř'
4592
     * </code>
4593
     *
4594
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
4595
     *
4596
     * @psalm-mutation-free
4597
     *
4598
     * @return static
4599
     *                <p>Object with a trimmed $str.</p>
4600
     */
4601 36
    public function trim(string $chars = null): self
4602
    {
4603 36
        return static::create(
4604 36
            $this->utf8::trim($this->str, $chars),
4605 36
            $this->encoding
4606
        );
4607
    }
4608
4609
    /**
4610
     * Returns a string with whitespace removed from the start of the string.
4611
     * Supports the removal of unicode whitespace. Accepts an optional
4612
     * string of characters to strip instead of the defaults.
4613
     *
4614
     * EXAMPLE: <code>
4615
     * s('  fòôbàř  ')->trimLeft(); // 'fòôbàř  '
4616
     * </code>
4617
     *
4618
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
4619
     *
4620
     * @psalm-mutation-free
4621
     *
4622
     * @return static
4623
     *                <p>Object with a trimmed $str.</p>
4624
     */
4625 39
    public function trimLeft(string $chars = null): self
4626
    {
4627 39
        return static::create(
4628 39
            $this->utf8::ltrim($this->str, $chars),
4629 39
            $this->encoding
4630
        );
4631
    }
4632
4633
    /**
4634
     * Returns a string with whitespace removed from the end of the string.
4635
     * Supports the removal of unicode whitespace. Accepts an optional
4636
     * string of characters to strip instead of the defaults.
4637
     *
4638
     * EXAMPLE: <code>
4639
     * s('  fòôbàř  ')->trimRight(); // '  fòôbàř'
4640
     * </code>
4641
     *
4642
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
4643
     *
4644
     * @psalm-mutation-free
4645
     *
4646
     * @return static
4647
     *                <p>Object with a trimmed $str.</p>
4648
     */
4649 39
    public function trimRight(string $chars = null): self
4650
    {
4651 39
        return static::create(
4652 39
            $this->utf8::rtrim($this->str, $chars),
4653 39
            $this->encoding
4654
        );
4655
    }
4656
4657
    /**
4658
     * Truncates the string to a given length. If $substring is provided, and
4659
     * truncating occurs, the string is further truncated so that the substring
4660
     * may be appended without exceeding the desired length.
4661
     *
4662
     * EXAMPLE: <code>
4663
     * s('What are your plans today?')->truncate(19, '...'); // 'What are your pl...'
4664
     * </code>
4665
     *
4666
     * @param int    $length    <p>Desired length of the truncated string.</p>
4667
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
4668
     *
4669
     * @psalm-mutation-free
4670
     *
4671
     * @return static
4672
     *                <p>Object with the resulting $str after truncating.</p>
4673
     */
4674 66
    public function truncate(int $length, string $substring = ''): self
4675
    {
4676 66
        return static::create(
4677 66
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
4678 66
            $this->encoding
4679
        );
4680
    }
4681
4682
    /**
4683
     * Returns a lowercase and trimmed string separated by underscores.
4684
     * Underscores are inserted before uppercase characters (with the exception
4685
     * of the first character of the string), and in place of spaces as well as
4686
     * dashes.
4687
     *
4688
     * EXAMPLE: <code>
4689
     * s('TestUCase')->underscored(); // 'test_u_case'
4690
     * </code>
4691
     *
4692
     * @psalm-mutation-free
4693
     *
4694
     * @return static
4695
     *                <p>Object with an underscored $str.</p>
4696
     */
4697 48
    public function underscored(): self
4698
    {
4699 48
        return $this->delimit('_');
4700
    }
4701
4702
    /**
4703
     * Returns an UpperCamelCase version of the supplied string. It trims
4704
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
4705
     * and underscores, and removes spaces, dashes, underscores.
4706
     *
4707
     * EXAMPLE: <code>
4708
     * s('Upper Camel-Case')->upperCamelize(); // 'UpperCamelCase'
4709
     * </code>
4710
     *
4711
     * @psalm-mutation-free
4712
     *
4713
     * @return static
4714
     *                <p>Object with $str in UpperCamelCase.</p>
4715
     */
4716 39
    public function upperCamelize(): self
4717
    {
4718 39
        return static::create(
4719 39
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
4720 39
            $this->encoding
4721
        );
4722
    }
4723
4724
    /**
4725
     * Converts the first character of the supplied string to upper case.
4726
     *
4727
     * EXAMPLE: <code>
4728
     * s('σ foo')->upperCaseFirst(); // 'Σ foo'
4729
     * </code>
4730
     *
4731
     * @psalm-mutation-free
4732
     *
4733
     * @return static
4734
     *                <p>Object with the first character of $str being upper case.</p>
4735
     */
4736 18
    public function upperCaseFirst(): self
4737
    {
4738 18
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
4739
    }
4740
4741
    /**
4742
     * Simple url-decoding.
4743
     *
4744
     * e.g:
4745
     * 'test+test' => 'test test'
4746
     *
4747
     * EXAMPLE: <code>
4748
     * </code>
4749
     *
4750
     * @psalm-mutation-free
4751
     *
4752
     * @return static
4753
     */
4754 1
    public function urlDecode(): self
4755
    {
4756 1
        return static::create(\urldecode($this->str));
4757
    }
4758
4759
    /**
4760
     * Multi url-decoding + decode HTML entity + fix urlencoded-win1252-chars.
4761
     *
4762
     * e.g:
4763
     * 'test+test'                     => 'test test'
4764
     * 'D&#252;sseldorf'               => 'Düsseldorf'
4765
     * 'D%FCsseldorf'                  => 'Düsseldorf'
4766
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
4767
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
4768
     * 'Düsseldorf'                   => 'Düsseldorf'
4769
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
4770
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
4771
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
4772
     *
4773
     * EXAMPLE: <code>
4774
     * </code>
4775
     *
4776
     * @psalm-mutation-free
4777
     *
4778
     * @return static
4779
     */
4780 1
    public function urlDecodeMulti(): self
4781
    {
4782 1
        return static::create($this->utf8::urldecode($this->str));
4783
    }
4784
4785
    /**
4786
     * Simple url-decoding.
4787
     *
4788
     * e.g:
4789
     * 'test+test' => 'test+test
4790
     *
4791
     * EXAMPLE: <code>
4792
     * </code>
4793
     *
4794
     * @psalm-mutation-free
4795
     *
4796
     * @return static
4797
     */
4798 1
    public function urlDecodeRaw(): self
4799
    {
4800 1
        return static::create(\rawurldecode($this->str));
4801
    }
4802
4803
    /**
4804
     * Multi url-decoding + decode HTML entity + fix urlencoded-win1252-chars.
4805
     *
4806
     * e.g:
4807
     * 'test+test'                     => 'test+test'
4808
     * 'D&#252;sseldorf'               => 'Düsseldorf'
4809
     * 'D%FCsseldorf'                  => 'Düsseldorf'
4810
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
4811
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
4812
     * 'Düsseldorf'                   => 'Düsseldorf'
4813
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
4814
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
4815
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
4816
     *
4817
     * EXAMPLE: <code>
4818
     * </code>
4819
     *
4820
     * @psalm-mutation-free
4821
     *
4822
     * @return static
4823
     */
4824 1
    public function urlDecodeRawMulti(): self
4825
    {
4826 1
        return static::create($this->utf8::rawurldecode($this->str));
4827
    }
4828
4829
    /**
4830
     * Simple url-encoding.
4831
     *
4832
     * e.g:
4833
     * 'test test' => 'test+test'
4834
     *
4835
     * EXAMPLE: <code>
4836
     * </code>
4837
     *
4838
     * @psalm-mutation-free
4839
     *
4840
     * @return static
4841
     */
4842 1
    public function urlEncode(): self
4843
    {
4844 1
        return static::create(\urlencode($this->str));
4845
    }
4846
4847
    /**
4848
     * Simple url-encoding.
4849
     *
4850
     * e.g:
4851
     * 'test test' => 'test%20test'
4852
     *
4853
     * EXAMPLE: <code>
4854
     * </code>
4855
     *
4856
     * @psalm-mutation-free
4857
     *
4858
     * @return static
4859
     */
4860 1
    public function urlEncodeRaw(): self
4861
    {
4862 1
        return static::create(\rawurlencode($this->str));
4863
    }
4864
4865
    /**
4866
     * Converts the string into an URL slug. This includes replacing non-ASCII
4867
     * characters with their closest ASCII equivalents, removing remaining
4868
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
4869
     * $separator. The separator defaults to a single dash, and the string
4870
     * is also converted to lowercase.
4871
     *
4872
     * EXAMPLE: <code>
4873
     * s('Using strings like fòô bàř - 1$')->urlify(); // 'using-strings-like-foo-bar-1-dollar'
4874
     * </code>
4875
     *
4876
     * @param string                $separator    [optional] <p>The string used to replace whitespace. Default: '-'</p>
4877
     * @param string                $language     [optional] <p>The language for the url. Default: 'en'</p>
4878
     * @param array<string, string> $replacements [optional] <p>A map of replaceable strings.</p>
4879
     * @param bool                  $strToLower   [optional] <p>string to lower. Default: true</p>
4880
     *
4881
     * @psalm-mutation-free
4882
     *
4883
     * @return static
4884
     *                <p>Object whose $str has been converted to an URL slug.</p>
4885
     *
4886
     * @psalm-suppress ImpureMethodCall :/
4887
     */
4888 32
    public function urlify(
4889
        string $separator = '-',
4890
        string $language = 'en',
4891
        array $replacements = [],
4892
        bool $strToLower = true
4893
    ): self {
4894
        // init
4895 32
        $str = $this->str;
4896
4897 32
        foreach ($replacements as $from => $to) {
4898 32
            $str = \str_replace($from, $to, $str);
4899
        }
4900
4901 32
        return static::create(
4902 32
            URLify::slug(
4903 32
                $str,
4904 32
                $language,
4905 32
                $separator,
4906 32
                $strToLower
4907
            ),
4908 32
            $this->encoding
4909
        );
4910
    }
4911
4912
    /**
4913
     * Converts the string into an valid UTF-8 string.
4914
     *
4915
     * EXAMPLE: <code>
4916
     * s('Düsseldorf')->utf8ify(); // 'Düsseldorf'
4917
     * </code>
4918
     *
4919
     * @psalm-mutation-free
4920
     *
4921
     * @return static
4922
     */
4923 2
    public function utf8ify(): self
4924
    {
4925 2
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
4926
    }
4927
4928
    /**
4929
     * Convert a string into an array of words.
4930
     *
4931
     * EXAMPLE: <code>
4932
     * </code>
4933
     *
4934
     * @param string   $char_list           [optional] <p>Additional chars for the definition of "words".</p>
4935
     * @param bool     $remove_empty_values [optional] <p>Remove empty values.</p>
4936
     * @param int|null $remove_short_values [optional] <p>The min. string length or null to disable</p>
4937
     *
4938
     * @psalm-mutation-free
4939
     *
4940
     * @return static[]
4941
     *
4942
     * @psalm-return array<int,static>
4943
     */
4944 14
    public function words(
4945
        string $char_list = '',
4946
        bool $remove_empty_values = false,
4947
        int $remove_short_values = null
4948
    ): array {
4949 14
        if ($remove_short_values === null) {
4950 14
            $strings = $this->utf8::str_to_words(
4951 14
                $this->str,
4952 14
                $char_list,
4953 14
                $remove_empty_values
4954
            );
4955
        } else {
4956 2
            $strings = $this->utf8::str_to_words(
4957 2
                $this->str,
4958 2
                $char_list,
4959 2
                $remove_empty_values,
4960 2
                $remove_short_values
4961
            );
4962
        }
4963
4964
        /** @noinspection AlterInForeachInspection */
4965 14
        foreach ($strings as &$string) {
4966 14
            $string = static::create($string);
4967
        }
4968
4969
        /** @noinspection PhpSillyAssignmentInspection */
4970
        /** @var static[] $strings */
4971 14
        $strings = $strings;
0 ignored issues
show
Bug introduced by
Why assign $strings to itself?

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

This assignement can be removed without consequences.

Loading history...
4972
4973 14
        return $strings;
4974
    }
4975
4976
    /**
4977
     * Convert a string into an collection of words.
4978
     *
4979
     * EXAMPLE: <code>
4980
     * S::create('中文空白 oöäü#s')->wordsCollection('#', true)->toStrings(); // ['中文空白', 'oöäü#s']
4981
     * </code>
4982
     *
4983
     * @param string   $char_list           [optional] <p>Additional chars for the definition of "words".</p>
4984
     * @param bool     $remove_empty_values [optional] <p>Remove empty values.</p>
4985
     * @param int|null $remove_short_values [optional] <p>The min. string length or null to disable</p>
4986
     *
4987
     * @psalm-mutation-free
4988
     *
4989
     * @return CollectionStringy|static[]
4990
     *                                    <p>An collection of Stringy objects.</p>
4991
     *
4992
     * @psalm-return CollectionStringy<int,static>
4993
     */
4994 2
    public function wordsCollection(
4995
        string $char_list = '',
4996
        bool $remove_empty_values = false,
4997
        int $remove_short_values = null
4998
    ): CollectionStringy {
4999
        /**
5000
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
5001
         */
5002 2
        return CollectionStringy::create(
5003 2
            $this->words(
5004 2
                $char_list,
5005 2
                $remove_empty_values,
5006 2
                $remove_short_values
5007
            )
5008
        );
5009
    }
5010
5011
    /**
5012
     * Surrounds $str with the given substring.
5013
     *
5014
     * EXAMPLE: <code>
5015
     * </code>
5016
     *
5017
     * @param string $substring <p>The substring to add to both sides.</P>
5018
     *
5019
     * @psalm-mutation-free
5020
     *
5021
     * @return static
5022
     *                <p>Object whose $str had the substring both prepended and appended.</p>
5023
     */
5024 10
    public function wrap(string $substring): self
5025
    {
5026 10
        return $this->surround($substring);
5027
    }
5028
5029
    /**
5030
     * Returns the replacements for the toAscii() method.
5031
     *
5032
     * @noinspection PhpUnused
5033
     *
5034
     * @psalm-mutation-free
5035
     *
5036
     * @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...
5037
     *                       <p>An array of replacements.</p>
5038
     *
5039
     * @deprecated   this is only here for backward-compatibly reasons
5040
     */
5041 1
    protected function charsArray(): array
5042
    {
5043 1
        return $this->ascii::charsArrayWithMultiLanguageValues();
5044
    }
5045
5046
    /**
5047
     * Returns true if $str matches the supplied pattern, false otherwise.
5048
     *
5049
     * @param string $pattern <p>Regex pattern to match against.</p>
5050
     *
5051
     * @psalm-mutation-free
5052
     *
5053
     * @return bool
5054
     *              <p>Whether or not $str matches the pattern.</p>
5055
     */
5056 24
    protected function matchesPattern(string $pattern): bool
5057
    {
5058 24
        return $this->utf8::str_matches_pattern($this->str, $pattern);
5059
    }
5060
}
5061