Completed
Push — master ( 42e39c...8668a1 )
by Lars
03:41 queued 01:29
created

Stringy::isEqualsCaseSensitive()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 21

Duplication

Lines 16
Ratio 76.19 %

Code Coverage

Tests 9
CRAP Score 6.0359

Importance

Changes 0
Metric Value
cc 6
nc 6
nop 1
dl 16
loc 21
ccs 9
cts 10
cp 0.9
crap 6.0359
rs 8.9617
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
     * Returns a camelCase version of the string. Trims surrounding spaces,
601
     * capitalizes letters following digits, spaces, dashes and underscores,
602
     * and removes spaces, dashes, as well as underscores.
603
     *
604
     * EXAMPLE: <code>
605
     * s('Camel-Case')->camelize(); // 'camelCase'
606
     * </code>
607
     *
608
     * @psalm-mutation-free
609
     *
610
     * @return static
611
     *                <p>Object with $str in camelCase.</p>
612
     */
613 57
    public function camelize(): self
614
    {
615 57
        return static::create(
616 57
            $this->utf8::str_camelize($this->str, $this->encoding),
617 57
            $this->encoding
618
        );
619
    }
620
621
    /**
622
     * Returns the string with the first letter of each word capitalized,
623
     * except for when the word is a name which shouldn't be capitalized.
624
     *
625
     * EXAMPLE: <code>
626
     * s('jaap de hoop scheffer')->capitalizePersonName(); // 'Jaap de Hoop Scheffer'
627
     * </code>
628
     *
629
     * @psalm-mutation-free
630
     *
631
     * @return static
632
     *                <p>Object with $str capitalized.</p>
633
     */
634 78
    public function capitalizePersonalName(): self
635
    {
636 78
        return static::create(
637 78
            $this->utf8::str_capitalize_name($this->str),
638 78
            $this->encoding
639
        );
640
    }
641
642
    /**
643
     * Returns an array consisting of the characters in the string.
644
     *
645
     * EXAMPLE: <code>
646
     * s('fòôbàř')->chars(); // ['f', 'ò', 'ô', 'b', 'à', 'ř']
647
     * </code>
648
     *
649
     * @psalm-mutation-free
650
     *
651
     * @return string[]
652
     *                  <p>An array of string chars.</p>
653
     */
654 14
    public function chars(): array
655
    {
656
        /** @var string[] */
657 14
        return $this->utf8::str_split($this->str);
658
    }
659
660
    /**
661
     * Splits the string into chunks of Stringy objects.
662
     *
663
     * EXAMPLE: <code>
664
     * s('foobar')->chunk(3); // ['foo', 'bar']
665
     * </code>
666
     *
667
     * @param int $length [optional] <p>Max character length of each array element.</p>
668
     *
669
     * @psalm-mutation-free
670
     *
671
     * @return static[]
672
     *                  <p>An array of Stringy objects.</p>
673
     *
674
     * @psalm-return array<int,static>
675
     */
676 13
    public function chunk(int $length = 1): array
677
    {
678 13
        if ($length < 1) {
679
            throw new \InvalidArgumentException('The chunk length must be greater than zero.');
680
        }
681
682 13
        if ($this->str === '') {
683 2
            return [];
684
        }
685
686 11
        $chunks = $this->utf8::str_split($this->str, $length);
687
688
        /** @noinspection AlterInForeachInspection */
689 11
        foreach ($chunks as $i => &$value) {
690 11
            $value = static::create($value, $this->encoding);
691
        }
692
693
        /** @noinspection PhpSillyAssignmentInspection */
694
        /** @var static[] $chunks */
695 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...
696
697 11
        return $chunks;
698
    }
699
700
    /**
701
     * Splits the string into chunks of Stringy objects collection.
702
     *
703
     * EXAMPLE: <code>
704
     * </code>
705
     *
706
     * @param int $length [optional] <p>Max character length of each array element.</p>
707
     *
708
     * @psalm-mutation-free
709
     *
710
     * @return CollectionStringy|static[]
711
     *                                    <p>An collection of Stringy objects.</p>
712
     *
713
     * @psalm-return CollectionStringy<int,static>
714
     */
715 7
    public function chunkCollection(int $length = 1): CollectionStringy
716
    {
717
        /**
718
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
719
         */
720 7
        return CollectionStringy::create(
721 7
            $this->chunk($length)
722
        );
723
    }
724
725
    /**
726
     * Trims the string and replaces consecutive whitespace characters with a
727
     * single space. This includes tabs and newline characters, as well as
728
     * multibyte whitespace such as the thin space and ideographic space.
729
     *
730
     * EXAMPLE: <code>
731
     * s('   Ο     συγγραφέας  ')->collapseWhitespace(); // 'Ο συγγραφέας'
732
     * </code>
733
     *
734
     * @psalm-mutation-free
735
     *
736
     * @return static
737
     *                <p>Object with a trimmed $str and condensed whitespace.</p>
738
     */
739 39
    public function collapseWhitespace(): self
740
    {
741 39
        return static::create(
742 39
            $this->utf8::collapse_whitespace($this->str),
743 39
            $this->encoding
744
        );
745
    }
746
747
    /**
748
     * Returns true if the string contains $needle, false otherwise. By default
749
     * the comparison is case-sensitive, but can be made insensitive by setting
750
     * $caseSensitive to false.
751
     *
752
     * EXAMPLE: <code>
753
     * s('Ο συγγραφέας είπε')->contains('συγγραφέας'); // true
754
     * </code>
755
     *
756
     * @param string $needle        <p>Substring to look for.</p>
757
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
758
     *
759
     * @psalm-mutation-free
760
     *
761
     * @return bool
762
     *              <p>Whether or not $str contains $needle.</p>
763
     */
764 63
    public function contains(string $needle, bool $caseSensitive = true): bool
765
    {
766 63
        return $this->utf8::str_contains(
767 63
            $this->str,
768 63
            $needle,
769 63
            $caseSensitive
770
        );
771
    }
772
773
    /**
774
     * Returns true if the string contains all $needles, false otherwise. By
775
     * default the comparison is case-sensitive, but can be made insensitive by
776
     * setting $caseSensitive to false.
777
     *
778
     * EXAMPLE: <code>
779
     * s('foo & bar')->containsAll(['foo', 'bar']); // true
780
     * </code>
781
     *
782
     * @param string[] $needles       <p>SubStrings to look for.</p>
783
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
784
     *
785
     * @psalm-mutation-free
786
     *
787
     * @return bool
788
     *              <p>Whether or not $str contains $needle.</p>
789
     */
790 131
    public function containsAll(array $needles, bool $caseSensitive = true): bool
791
    {
792 131
        return $this->utf8::str_contains_all(
793 131
            $this->str,
794 131
            $needles,
795 131
            $caseSensitive
796
        );
797
    }
798
799
    /**
800
     * Returns true if the string contains any $needles, false otherwise. By
801
     * default the comparison is case-sensitive, but can be made insensitive by
802
     * setting $caseSensitive to false.
803
     *
804
     * EXAMPLE: <code>
805
     * s('str contains foo')->containsAny(['foo', 'bar']); // true
806
     * </code>
807
     *
808
     * @param string[] $needles       <p>SubStrings to look for.</p>
809
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
810
     *
811
     * @psalm-mutation-free
812
     *
813
     * @return bool
814
     *              <p>Whether or not $str contains $needle.</p>
815
     */
816 129
    public function containsAny(array $needles, bool $caseSensitive = true): bool
817
    {
818 129
        return $this->utf8::str_contains_any(
819 129
            $this->str,
820 129
            $needles,
821 129
            $caseSensitive
822
        );
823
    }
824
825
    /**
826
     * Returns the length of the string, implementing the countable interface.
827
     *
828
     * EXAMPLE: <code>
829
     * </code>
830
     *
831
     * @psalm-mutation-free
832
     *
833
     * @return int
834
     *             <p>The number of characters in the string, given the encoding.</p>
835
     */
836 3
    public function count(): int
837
    {
838 3
        return $this->length();
839
    }
840
841
    /**
842
     * Returns the number of occurrences of $substring in the given string.
843
     * By default, the comparison is case-sensitive, but can be made insensitive
844
     * by setting $caseSensitive to false.
845
     *
846
     * EXAMPLE: <code>
847
     * s('Ο συγγραφέας είπε')->countSubstr('α'); // 2
848
     * </code>
849
     *
850
     * @param string $substring     <p>The substring to search for.</p>
851
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
852
     *
853
     * @psalm-mutation-free
854
     *
855
     * @return int
856
     */
857 45
    public function countSubstr(string $substring, bool $caseSensitive = true): int
858
    {
859 45
        return $this->utf8::substr_count_simple(
860 45
            $this->str,
861 45
            $substring,
862 45
            $caseSensitive,
863 45
            $this->encoding
864
        );
865
    }
866
867
    /**
868
     * Calculates the crc32 polynomial of a string.
869
     *
870
     * EXAMPLE: <code>
871
     * </code>
872
     *
873
     * @psalm-mutation-free
874
     *
875
     * @return int
876
     */
877 2
    public function crc32(): int
878
    {
879 2
        return \crc32($this->str);
880
    }
881
882
    /**
883
     * Creates a Stringy object and assigns both str and encoding properties
884
     * the supplied values. $str is cast to a string prior to assignment, and if
885
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
886
     * then returns the initialized object. Throws an InvalidArgumentException
887
     * if the first argument is an array or object without a __toString method.
888
     *
889
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
890
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
891
     *
892
     * @throws \InvalidArgumentException
893
     *                                   <p>if an array or object without a
894
     *                                   __toString method is passed as the first argument</p>
895
     *
896
     * @return static
897
     *                <p>A Stringy object.</p>
898
     * @psalm-pure
899
     */
900 3568
    public static function create($str = '', string $encoding = null): self
901
    {
902 3568
        return new static($str, $encoding);
903
    }
904
905
    /**
906
     * One-way string encryption (hashing).
907
     *
908
     * Hash the string using the standard Unix DES-based algorithm or an
909
     * alternative algorithm that may be available on the system.
910
     *
911
     * PS: if you need encrypt / decrypt, please use ```static::encrypt($password)```
912
     *     and ```static::decrypt($password)```
913
     *
914
     * EXAMPLE: <code>
915
     * </code>
916
     *
917
     * @param string $salt <p>A salt string to base the hashing on.</p>
918
     *
919
     * @psalm-mutation-free
920
     *
921
     * @return static
922
     */
923 3
    public function crypt(string $salt): self
924
    {
925 3
        return new static(
926 3
            \crypt(
927 3
                $this->str,
928 3
                $salt
929
            ),
930 3
            $this->encoding
931
        );
932
    }
933
934
    /**
935
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
936
     * inserted before uppercase characters (with the exception of the first
937
     * character of the string), and in place of spaces as well as underscores.
938
     *
939
     * EXAMPLE: <code>
940
     * s('fooBar')->dasherize(); // 'foo-bar'
941
     * </code>
942
     *
943
     * @psalm-mutation-free
944
     *
945
     * @return static
946
     *                <p>Object with a dasherized $str</p>
947
     */
948 57
    public function dasherize(): self
949
    {
950 57
        return static::create(
951 57
            $this->utf8::str_dasherize($this->str),
952 57
            $this->encoding
953
        );
954
    }
955
956
    /**
957
     * Call a user function.
958
     *
959
     * EXAMPLE: <code>
960
     * S::create('foo bar lall')->callUserFunction(static function ($str) {
961
     *     return UTF8::str_limit($str, 8);
962
     * })->toString(); // "foo bar…"
963
     * </code>
964
     *
965
     * @param callable $function
966
     * @param mixed    ...$parameter
967
     *
968
     * @psalm-mutation-free
969
     *
970
     * @return static
971
     *                <p>Object having a $str changed via $function.</p>
972
     */
973 2
    public function callUserFunction(callable $function, ...$parameter): self
974
    {
975 2
        $str = $function($this->str, ...$parameter);
976
977 2
        return static::create(
978 2
            $str,
979 2
            $this->encoding
980
        );
981
    }
982
983
    /**
984
     * Decrypt the string.
985
     *
986
     * EXAMPLE: <code>
987
     * </code>
988
     *
989
     * @param string $password The key for decrypting
990
     *
991
     * @psalm-mutation-free
992
     *
993
     * @return static
994
     */
995 5
    public function decrypt(string $password): self
996
    {
997
        /**
998
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
999
         */
1000 5
        return new static(
1001 5
            Crypto::decryptWithPassword($this->str, $password),
1002 3
            $this->encoding
1003
        );
1004
    }
1005
1006
    /**
1007
     * Returns a lowercase and trimmed string separated by the given delimiter.
1008
     * Delimiters are inserted before uppercase characters (with the exception
1009
     * of the first character of the string), and in place of spaces, dashes,
1010
     * and underscores. Alpha delimiters are not converted to lowercase.
1011
     *
1012
     * EXAMPLE: <code>
1013
     * s('fooBar')->delimit('::'); // 'foo::bar'
1014
     * </code>
1015
     *
1016
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
1017
     *
1018
     * @psalm-mutation-free
1019
     *
1020
     * @return static
1021
     *                <p>Object with a delimited $str.</p>
1022
     */
1023 90
    public function delimit(string $delimiter): self
1024
    {
1025 90
        return static::create(
1026 90
            $this->utf8::str_delimit($this->str, $delimiter),
1027 90
            $this->encoding
1028
        );
1029
    }
1030
1031
    /**
1032
     * Encode the given string into the given $encoding + set the internal character encoding.
1033
     *
1034
     * EXAMPLE: <code>
1035
     * </code>
1036
     *
1037
     * @param string $new_encoding         <p>The desired character encoding.</p>
1038
     * @param bool   $auto_detect_encoding [optional] <p>Auto-detect the current string-encoding</p>
1039
     *
1040
     * @psalm-mutation-free
1041
     *
1042
     * @return static
1043
     */
1044 2
    public function encode(string $new_encoding, bool $auto_detect_encoding = false): self
1045
    {
1046 2
        if ($auto_detect_encoding) {
1047 1
            $str = $this->utf8::encode(
1048 1
                $new_encoding,
1049 1
                $this->str
1050
            );
1051
        } else {
1052 1
            $str = $this->utf8::encode(
1053 1
                $new_encoding,
1054 1
                $this->str,
1055 1
                false,
1056 1
                $this->encoding
1057
            );
1058
        }
1059
1060 2
        return new static($str, $new_encoding);
1061
    }
1062
1063
    /**
1064
     * Encrypt the string.
1065
     *
1066
     * EXAMPLE: <code>
1067
     * </code>
1068
     *
1069
     * @param string $password <p>The key for encrypting</p>
1070
     *
1071
     * @psalm-mutation-free
1072
     *
1073
     * @return static
1074
     */
1075 4
    public function encrypt(string $password): self
1076
    {
1077
        /**
1078
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff
1079
         */
1080 4
        return new static(
1081 4
            Crypto::encryptWithPassword($this->str, $password),
1082 4
            $this->encoding
1083
        );
1084
    }
1085
1086
    /**
1087
     * Returns true if the string ends with $substring, false otherwise. By
1088
     * default, the comparison is case-sensitive, but can be made insensitive
1089
     * by setting $caseSensitive to false.
1090
     *
1091
     * EXAMPLE: <code>
1092
     * s('fòôbàř')->endsWith('bàř', true); // true
1093
     * </code>
1094
     *
1095
     * @param string $substring     <p>The substring to look for.</p>
1096
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1097
     *
1098
     * @psalm-mutation-free
1099
     *
1100
     * @return bool
1101
     *              <p>Whether or not $str ends with $substring.</p>
1102
     */
1103 97
    public function endsWith(string $substring, bool $caseSensitive = true): bool
1104
    {
1105 97
        if ($caseSensitive) {
1106 53
            return $this->utf8::str_ends_with($this->str, $substring);
1107
        }
1108
1109 44
        return $this->utf8::str_iends_with($this->str, $substring);
1110
    }
1111
1112
    /**
1113
     * Returns true if the string ends with any of $substrings, false otherwise.
1114
     * By default, the comparison is case-sensitive, but can be made insensitive
1115
     * by setting $caseSensitive to false.
1116
     *
1117
     * EXAMPLE: <code>
1118
     * s('fòôbàř')->endsWithAny(['bàř', 'baz'], true); // true
1119
     * </code>
1120
     *
1121
     * @param string[] $substrings    <p>Substrings to look for.</p>
1122
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1123
     *
1124
     * @psalm-mutation-free
1125
     *
1126
     * @return bool
1127
     *              <p>Whether or not $str ends with $substring.</p>
1128
     */
1129 33
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
1130
    {
1131 33
        if ($caseSensitive) {
1132 21
            return $this->utf8::str_ends_with_any($this->str, $substrings);
1133
        }
1134
1135 12
        return $this->utf8::str_iends_with_any($this->str, $substrings);
1136
    }
1137
1138
    /**
1139
     * Ensures that the string begins with $substring. If it doesn't, it's
1140
     * prepended.
1141
     *
1142
     * EXAMPLE: <code>
1143
     * s('foobar')->ensureLeft('http://'); // 'http://foobar'
1144
     * </code>
1145
     *
1146
     * @param string $substring <p>The substring to add if not present.</p>
1147
     *
1148
     * @psalm-mutation-free
1149
     *
1150
     * @return static
1151
     *                <p>Object with its $str prefixed by the $substring.</p>
1152
     */
1153 30
    public function ensureLeft(string $substring): self
1154
    {
1155 30
        return static::create(
1156 30
            $this->utf8::str_ensure_left($this->str, $substring),
1157 30
            $this->encoding
1158
        );
1159
    }
1160
1161
    /**
1162
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
1163
     *
1164
     * EXAMPLE: <code>
1165
     * s('foobar')->ensureRight('.com'); // 'foobar.com'
1166
     * </code>
1167
     *
1168
     * @param string $substring <p>The substring to add if not present.</p>
1169
     *
1170
     * @psalm-mutation-free
1171
     *
1172
     * @return static
1173
     *                <p>Object with its $str suffixed by the $substring.</p>
1174
     */
1175 30
    public function ensureRight(string $substring): self
1176
    {
1177 30
        return static::create(
1178 30
            $this->utf8::str_ensure_right($this->str, $substring),
1179 30
            $this->encoding
1180
        );
1181
    }
1182
1183
    /**
1184
     * Create a escape html version of the string via "htmlspecialchars()".
1185
     *
1186
     * EXAMPLE: <code>
1187
     * s('<∂∆ onerror="alert(xss)">')->escape(); // '&lt;∂∆ onerror=&quot;alert(xss)&quot;&gt;'
1188
     * </code>
1189
     *
1190
     * @psalm-mutation-free
1191
     *
1192
     * @return static
1193
     */
1194 12
    public function escape(): self
1195
    {
1196 12
        return static::create(
1197 12
            $this->utf8::htmlspecialchars(
1198 12
                $this->str,
1199 12
                \ENT_QUOTES | \ENT_SUBSTITUTE,
1200 12
                $this->encoding
1201
            ),
1202 12
            $this->encoding
1203
        );
1204
    }
1205
1206
    /**
1207
     * Split a string by a string.
1208
     *
1209
     * EXAMPLE: <code>
1210
     * </code>
1211
     *
1212
     * @param string $delimiter <p>The boundary string</p>
1213
     * @param int    $limit     [optional] <p>The maximum number of elements in the exploded
1214
     *                          collection.</p>
1215
     *
1216
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
1217
     *   element containing the rest of string.
1218
     *   - If the limit parameter is negative, all components except the last -limit are returned.
1219
     *   - If the limit parameter is zero, then this is treated as 1
1220
     *
1221
     * @psalm-mutation-free
1222
     *
1223
     * @return array<int,static>
1224
     */
1225 3
    public function explode(string $delimiter, int $limit = \PHP_INT_MAX): array
1226
    {
1227 3
        if ($this->str === '') {
1228
            return [];
1229
        }
1230
1231 3
        $strings = \explode($delimiter, $this->str, $limit);
1232 3
        if ($strings === false) {
1233
            $strings = [];
1234
        }
1235
1236 3
        return \array_map(
1237
            function ($str) {
1238 3
                return new static($str, $this->encoding);
1239 3
            },
1240 3
            $strings
1241
        );
1242
    }
1243
1244
    /**
1245
     * Split a string by a string.
1246
     *
1247
     * EXAMPLE: <code>
1248
     * </code>
1249
     *
1250
     * @param string $delimiter <p>The boundary string</p>
1251
     * @param int    $limit     [optional] <p>The maximum number of elements in the exploded
1252
     *                          collection.</p>
1253
     *
1254
     *   - If limit is set and positive, the returned collection will contain a maximum of limit elements with the last
1255
     *   element containing the rest of string.
1256
     *   - If the limit parameter is negative, all components except the last -limit are returned.
1257
     *   - If the limit parameter is zero, then this is treated as 1
1258
     *
1259
     * @psalm-mutation-free
1260
     *
1261
     * @return CollectionStringy|static[]
1262
     *                                    <p>An collection of Stringy objects.</p>
1263
     *
1264
     * @psalm-return CollectionStringy<int,static>
1265
     */
1266 1
    public function explodeCollection(string $delimiter, int $limit = \PHP_INT_MAX): CollectionStringy
1267
    {
1268
        /**
1269
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
1270
         */
1271 1
        return CollectionStringy::create(
1272 1
            $this->explode($delimiter, $limit)
1273
        );
1274
    }
1275
1276
    /**
1277
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
1278
     *
1279
     * EXAMPLE: <code>
1280
     * $sentence = 'This is only a Fork of Stringy, take a look at the new features.';
1281
     * s($sentence)->extractText('Stringy'); // '...Fork of Stringy...'
1282
     * </code>
1283
     *
1284
     * @param string   $search
1285
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
1286
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
1287
     *
1288
     * @psalm-mutation-free
1289
     *
1290
     * @return static
1291
     */
1292 2
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
1293
    {
1294 2
        return static::create(
1295 2
            $this->utf8::extract_text(
1296 2
                $this->str,
1297 2
                $search,
1298 2
                $length,
1299 2
                $replacerForSkippedText,
1300 2
                $this->encoding
1301
            ),
1302 2
            $this->encoding
1303
        );
1304
    }
1305
1306
    /**
1307
     * Returns the first $n characters of the string.
1308
     *
1309
     * EXAMPLE: <code>
1310
     * s('fòôbàř')->first(3); // 'fòô'
1311
     * </code>
1312
     *
1313
     * @param int $n <p>Number of characters to retrieve from the start.</p>
1314
     *
1315
     * @psalm-mutation-free
1316
     *
1317
     * @return static
1318
     *                <p>Object with its $str being the first $n chars.</p>
1319
     */
1320 37
    public function first(int $n): self
1321
    {
1322 37
        return static::create(
1323 37
            $this->utf8::first_char($this->str, $n, $this->encoding),
1324 37
            $this->encoding
1325
        );
1326
    }
1327
1328
    /**
1329
     * Return a formatted string via sprintf + named parameters via array syntax.
1330
     *
1331
     * <p>
1332
     * <br>
1333
     * It will use "sprintf()" so you can use e.g.:
1334
     * <br>
1335
     * <br><pre>s('There are %d monkeys in the %s')->format(5, 'tree');</pre>
1336
     * <br>
1337
     * <br><pre>s('There are %2$d monkeys in the %1$s')->format('tree', 5);</pre>
1338
     * <br>
1339
     * <br>
1340
     * But you can also use named parameter via array syntax e.g.:
1341
     * <br>
1342
     * <br><pre>s('There are %:count monkeys in the %:location')->format(['count' => 5, 'location' => 'tree');</pre>
1343
     * </p>
1344
     *
1345
     * EXAMPLE: <code>
1346
     * $input = 'one: %2$d, %1$s: 2, %:text_three: %3$d';
1347
     * s($input)->format(['text_three' => '%4$s'], 'two', 1, 3, 'three'); // 'One: 1, two: 2, three: 3'
1348
     * </code>
1349
     *
1350
     * @param mixed ...$args [optional]
1351
     *
1352
     * @psalm-mutation-free
1353
     *
1354
     * @return static
1355
     *                <p>A Stringy object produced according to the formatting string
1356
     *                format.</p>
1357
     */
1358 10
    public function format(...$args): self
1359
    {
1360
        // init
1361 10
        $str = $this->str;
1362
1363 10
        if (\strpos($this->str, '%:') !== false) {
1364 8
            $offset = null;
1365 8
            $replacement = null;
1366
            /** @noinspection AlterInForeachInspection */
1367 8
            foreach ($args as $key => &$arg) {
1368 8
                if (!\is_array($arg)) {
1369 4
                    continue;
1370
                }
1371
1372 8
                foreach ($arg as $name => $param) {
1373 8
                    $name = (string) $name;
1374
1375 8
                    if (\strpos($name, '%:') !== 0) {
1376 8
                        $nameTmp = '%:' . $name;
1377
                    } else {
1378
                        $nameTmp = $name;
1379
                    }
1380
1381 8
                    if ($offset === null) {
1382 8
                        $offset = \strpos($str, $nameTmp);
1383
                    } else {
1384 6
                        $offset = \strpos($str, $nameTmp, (int) $offset + \strlen((string) $replacement));
1385
                    }
1386 8
                    if ($offset === false) {
1387 4
                        continue;
1388
                    }
1389
1390 8
                    unset($arg[$name]);
1391
1392 8
                    $str = \substr_replace($str, $param, (int) $offset, \strlen($nameTmp));
1393
                }
1394
1395 8
                unset($args[$key]);
1396
            }
1397
        }
1398
1399 10
        $str = \str_replace('%:', '%%:', $str);
1400
1401 10
        return static::create(
1402 10
            \sprintf($str, ...$args),
1403 10
            $this->encoding
1404
        );
1405
    }
1406
1407
    /**
1408
     * Returns the encoding used by the Stringy object.
1409
     *
1410
     * EXAMPLE: <code>
1411
     * s('fòôbàř', 'UTF-8')->getEncoding(); // 'UTF-8'
1412
     * </code>
1413
     *
1414
     * @psalm-mutation-free
1415
     *
1416
     * @return string
1417
     *                <p>The current value of the $encoding property.</p>
1418
     */
1419 7
    public function getEncoding(): string
1420
    {
1421 7
        return $this->encoding;
1422
    }
1423
1424
    /**
1425
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
1426
     * interface. The ArrayIterator's constructor is passed an array of chars
1427
     * in the multibyte string. This enables the use of foreach with instances
1428
     * of Stringy\Stringy.
1429
     *
1430
     * EXAMPLE: <code>
1431
     * </code>
1432
     *
1433
     * @psalm-mutation-free
1434
     *
1435
     * @return \ArrayIterator
1436
     *                        <p>An iterator for the characters in the string.</p>
1437
     *
1438
     * @psalm-return \ArrayIterator<array-key,string>
1439
     */
1440 3
    public function getIterator(): \ArrayIterator
1441
    {
1442 3
        return new \ArrayIterator($this->chars());
1443
    }
1444
1445
    /**
1446
     * Wrap the string after an exact number of characters.
1447
     *
1448
     * EXAMPLE: <code>
1449
     * </code>
1450
     *
1451
     * @param int    $width <p>Number of characters at which to wrap.</p>
1452
     * @param string $break [optional] <p>Character used to break the string. | Default: "\n"</p>
1453
     *
1454
     * @psalm-mutation-free
1455
     *
1456
     * @return static
1457
     */
1458 2
    public function hardWrap($width, $break = "\n"): self
1459
    {
1460 2
        return $this->lineWrap($width, $break, false);
1461
    }
1462
1463
    /**
1464
     * Returns true if the string contains a lower case char, false otherwise
1465
     *
1466
     * EXAMPLE: <code>
1467
     * s('fòôbàř')->hasLowerCase(); // true
1468
     * </code>
1469
     *
1470
     * @psalm-mutation-free
1471
     *
1472
     * @return bool
1473
     *              <p>Whether or not the string contains a lower case character.</p>
1474
     */
1475 36
    public function hasLowerCase(): bool
1476
    {
1477 36
        return $this->utf8::has_lowercase($this->str);
1478
    }
1479
1480
    /**
1481
     * Returns true if the string contains an upper case char, false otherwise.
1482
     *
1483
     * EXAMPLE: <code>
1484
     * s('fòôbàř')->hasUpperCase(); // false
1485
     * </code>
1486
     *
1487
     * @psalm-mutation-free
1488
     *
1489
     * @return bool
1490
     *              <p>Whether or not the string contains an upper case character.</p>
1491
     */
1492 36
    public function hasUpperCase(): bool
1493
    {
1494 36
        return $this->utf8::has_uppercase($this->str);
1495
    }
1496
1497
    /**
1498
     * Generate a hash value (message digest).
1499
     *
1500
     * EXAMPLE: <code>
1501
     * </code>
1502
     *
1503
     * @see https://php.net/manual/en/function.hash.php
1504
     *
1505
     * @param string $algorithm
1506
     *                          <p>Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4", etc..)</p>
1507
     *
1508
     * @psalm-mutation-free
1509
     *
1510
     * @return static
1511
     */
1512 8
    public function hash($algorithm): self
1513
    {
1514 8
        return static::create(\hash($algorithm, $this->str), $this->encoding);
1515
    }
1516
1517
    /**
1518
     * Decode the string from hex.
1519
     *
1520
     * EXAMPLE: <code>
1521
     * </code>
1522
     *
1523
     * @psalm-mutation-free
1524
     *
1525
     * @return static
1526
     */
1527 2
    public function hexDecode(): self
1528
    {
1529 2
        $string = \preg_replace_callback(
1530 2
            '/\\\\x([0-9A-Fa-f]+)/',
1531
            function (array $matched) {
1532 2
                return (string) $this->utf8::hex_to_chr($matched[1]);
1533 2
            },
1534 2
            $this->str
1535
        );
1536
1537 2
        return static::create(
1538 2
            $string,
1539 2
            $this->encoding
1540
        );
1541
    }
1542
1543
    /**
1544
     * Encode string to hex.
1545
     *
1546
     * EXAMPLE: <code>
1547
     * </code>
1548
     *
1549
     * @psalm-mutation-free
1550
     *
1551
     * @return static
1552
     */
1553 2
    public function hexEncode(): self
1554
    {
1555 2
        $string = \array_reduce(
1556 2
            $this->chars(),
1557
            function (string $str, string $char) {
1558 2
                return $str . $this->utf8::chr_to_hex($char);
1559 2
            },
1560 2
            ''
1561
        );
1562
1563 2
        return static::create(
1564 2
            $string,
1565 2
            $this->encoding
1566
        );
1567
    }
1568
1569
    /**
1570
     * Convert all HTML entities to their applicable characters.
1571
     *
1572
     * EXAMPLE: <code>
1573
     * s('&amp;')->htmlDecode(); // '&'
1574
     * </code>
1575
     *
1576
     * @param int $flags [optional] <p>
1577
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1578
     *                   which document type to use. The default is ENT_COMPAT.
1579
     *                   <table>
1580
     *                   Available <i>flags</i> constants
1581
     *                   <tr valign="top">
1582
     *                   <td>Constant Name</td>
1583
     *                   <td>Description</td>
1584
     *                   </tr>
1585
     *                   <tr valign="top">
1586
     *                   <td><b>ENT_COMPAT</b></td>
1587
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1588
     *                   </tr>
1589
     *                   <tr valign="top">
1590
     *                   <td><b>ENT_QUOTES</b></td>
1591
     *                   <td>Will convert both double and single quotes.</td>
1592
     *                   </tr>
1593
     *                   <tr valign="top">
1594
     *                   <td><b>ENT_NOQUOTES</b></td>
1595
     *                   <td>Will leave both double and single quotes unconverted.</td>
1596
     *                   </tr>
1597
     *                   <tr valign="top">
1598
     *                   <td><b>ENT_HTML401</b></td>
1599
     *                   <td>
1600
     *                   Handle code as HTML 4.01.
1601
     *                   </td>
1602
     *                   </tr>
1603
     *                   <tr valign="top">
1604
     *                   <td><b>ENT_XML1</b></td>
1605
     *                   <td>
1606
     *                   Handle code as XML 1.
1607
     *                   </td>
1608
     *                   </tr>
1609
     *                   <tr valign="top">
1610
     *                   <td><b>ENT_XHTML</b></td>
1611
     *                   <td>
1612
     *                   Handle code as XHTML.
1613
     *                   </td>
1614
     *                   </tr>
1615
     *                   <tr valign="top">
1616
     *                   <td><b>ENT_HTML5</b></td>
1617
     *                   <td>
1618
     *                   Handle code as HTML 5.
1619
     *                   </td>
1620
     *                   </tr>
1621
     *                   </table>
1622
     *                   </p>
1623
     *
1624
     * @psalm-mutation-free
1625
     *
1626
     * @return static
1627
     *                <p>Object with the resulting $str after being html decoded.</p>
1628
     */
1629 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...
1630
    {
1631 15
        return static::create(
1632 15
            $this->utf8::html_entity_decode(
1633 15
                $this->str,
1634 15
                $flags,
1635 15
                $this->encoding
1636
            ),
1637 15
            $this->encoding
1638
        );
1639
    }
1640
1641
    /**
1642
     * Convert all applicable characters to HTML entities.
1643
     *
1644
     * EXAMPLE: <code>
1645
     * s('&')->htmlEncode(); // '&amp;'
1646
     * </code>
1647
     *
1648
     * @param int $flags [optional] <p>
1649
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
1650
     *                   which document type to use. The default is ENT_COMPAT.
1651
     *                   <table>
1652
     *                   Available <i>flags</i> constants
1653
     *                   <tr valign="top">
1654
     *                   <td>Constant Name</td>
1655
     *                   <td>Description</td>
1656
     *                   </tr>
1657
     *                   <tr valign="top">
1658
     *                   <td><b>ENT_COMPAT</b></td>
1659
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
1660
     *                   </tr>
1661
     *                   <tr valign="top">
1662
     *                   <td><b>ENT_QUOTES</b></td>
1663
     *                   <td>Will convert both double and single quotes.</td>
1664
     *                   </tr>
1665
     *                   <tr valign="top">
1666
     *                   <td><b>ENT_NOQUOTES</b></td>
1667
     *                   <td>Will leave both double and single quotes unconverted.</td>
1668
     *                   </tr>
1669
     *                   <tr valign="top">
1670
     *                   <td><b>ENT_HTML401</b></td>
1671
     *                   <td>
1672
     *                   Handle code as HTML 4.01.
1673
     *                   </td>
1674
     *                   </tr>
1675
     *                   <tr valign="top">
1676
     *                   <td><b>ENT_XML1</b></td>
1677
     *                   <td>
1678
     *                   Handle code as XML 1.
1679
     *                   </td>
1680
     *                   </tr>
1681
     *                   <tr valign="top">
1682
     *                   <td><b>ENT_XHTML</b></td>
1683
     *                   <td>
1684
     *                   Handle code as XHTML.
1685
     *                   </td>
1686
     *                   </tr>
1687
     *                   <tr valign="top">
1688
     *                   <td><b>ENT_HTML5</b></td>
1689
     *                   <td>
1690
     *                   Handle code as HTML 5.
1691
     *                   </td>
1692
     *                   </tr>
1693
     *                   </table>
1694
     *                   </p>
1695
     *
1696
     * @psalm-mutation-free
1697
     *
1698
     * @return static
1699
     *                <p>Object with the resulting $str after being html encoded.</p>
1700
     */
1701 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...
1702
    {
1703 15
        return static::create(
1704 15
            $this->utf8::htmlentities(
1705 15
                $this->str,
1706 15
                $flags,
1707 15
                $this->encoding
1708
            ),
1709 15
            $this->encoding
1710
        );
1711
    }
1712
1713
    /**
1714
     * Capitalizes the first word of the string, replaces underscores with
1715
     * spaces, and strips '_id'.
1716
     *
1717
     * EXAMPLE: <code>
1718
     * s('author_id')->humanize(); // 'Author'
1719
     * </code>
1720
     *
1721
     * @psalm-mutation-free
1722
     *
1723
     * @return static
1724
     *                <p>Object with a humanized $str.</p>
1725
     */
1726 9
    public function humanize(): self
1727
    {
1728 9
        return static::create(
1729 9
            $this->utf8::str_humanize($this->str),
1730 9
            $this->encoding
1731
        );
1732
    }
1733
1734
    /**
1735
     * Determine if the current string exists in another string. By
1736
     * default, the comparison is case-sensitive, but can be made insensitive
1737
     * by setting $caseSensitive to false.
1738
     *
1739
     * EXAMPLE: <code>
1740
     * </code>
1741
     *
1742
     * @param string $str           <p>The string to compare against.</p>
1743
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1744
     *
1745
     * @psalm-mutation-free
1746
     *
1747
     * @return bool
1748
     */
1749 3
    public function in(string $str, bool $caseSensitive = true): bool
1750
    {
1751 3
        if ($caseSensitive) {
1752 2
            return \strpos($str, $this->str) !== false;
1753
        }
1754
1755 1
        return \stripos($str, $this->str) !== false;
1756
    }
1757
1758
    /**
1759
     * Returns the index of the first occurrence of $needle in the string,
1760
     * and false if not found. Accepts an optional offset from which to begin
1761
     * the search.
1762
     *
1763
     * EXAMPLE: <code>
1764
     * s('string')->indexOf('ing'); // 3
1765
     * </code>
1766
     *
1767
     * @param string $needle <p>Substring to look for.</p>
1768
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1769
     *
1770
     * @psalm-mutation-free
1771
     *
1772
     * @return false|int
1773
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1774
     */
1775 31
    public function indexOf(string $needle, int $offset = 0)
1776
    {
1777 31
        return $this->utf8::strpos(
1778 31
            $this->str,
1779 31
            $needle,
1780 31
            $offset,
1781 31
            $this->encoding
1782
        );
1783
    }
1784
1785
    /**
1786
     * Returns the index of the first occurrence of $needle in the string,
1787
     * and false if not found. Accepts an optional offset from which to begin
1788
     * the search.
1789
     *
1790
     * EXAMPLE: <code>
1791
     * s('string')->indexOfIgnoreCase('ING'); // 3
1792
     * </code>
1793
     *
1794
     * @param string $needle <p>Substring to look for.</p>
1795
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1796
     *
1797
     * @psalm-mutation-free
1798
     *
1799
     * @return false|int
1800
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1801
     */
1802 20
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
1803
    {
1804 20
        return $this->utf8::stripos(
1805 20
            $this->str,
1806 20
            $needle,
1807 20
            $offset,
1808 20
            $this->encoding
1809
        );
1810
    }
1811
1812
    /**
1813
     * Returns the index of the last occurrence of $needle in the string,
1814
     * and false if not found. Accepts an optional offset from which to begin
1815
     * the search. Offsets may be negative to count from the last character
1816
     * in the string.
1817
     *
1818
     * EXAMPLE: <code>
1819
     * s('foobarfoo')->indexOfLast('foo'); // 10
1820
     * </code>
1821
     *
1822
     * @param string $needle <p>Substring to look for.</p>
1823
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1824
     *
1825
     * @psalm-mutation-free
1826
     *
1827
     * @return false|int
1828
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1829
     */
1830 31
    public function indexOfLast(string $needle, int $offset = 0)
1831
    {
1832 31
        return $this->utf8::strrpos(
1833 31
            $this->str,
1834 31
            $needle,
1835 31
            $offset,
1836 31
            $this->encoding
1837
        );
1838
    }
1839
1840
    /**
1841
     * Returns the index of the last occurrence of $needle in the string,
1842
     * and false if not found. Accepts an optional offset from which to begin
1843
     * the search. Offsets may be negative to count from the last character
1844
     * in the string.
1845
     *
1846
     * EXAMPLE: <code>
1847
     * s('fooBarFoo')->indexOfLastIgnoreCase('foo'); // 10
1848
     * </code>
1849
     *
1850
     * @param string $needle <p>Substring to look for.</p>
1851
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
1852
     *
1853
     * @psalm-mutation-free
1854
     *
1855
     * @return false|int
1856
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
1857
     */
1858 20
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
1859
    {
1860 20
        return $this->utf8::strripos(
1861 20
            $this->str,
1862 20
            $needle,
1863 20
            $offset,
1864 20
            $this->encoding
1865
        );
1866
    }
1867
1868
    /**
1869
     * Inserts $substring into the string at the $index provided.
1870
     *
1871
     * EXAMPLE: <code>
1872
     * s('fòôbř')->insert('à', 4); // 'fòôbàř'
1873
     * </code>
1874
     *
1875
     * @param string $substring <p>String to be inserted.</p>
1876
     * @param int    $index     <p>The index at which to insert the substring.</p>
1877
     *
1878
     * @psalm-mutation-free
1879
     *
1880
     * @return static
1881
     *                <p>Object with the resulting $str after the insertion.</p>
1882
     */
1883 24
    public function insert(string $substring, int $index): self
1884
    {
1885 24
        return static::create(
1886 24
            $this->utf8::str_insert(
1887 24
                $this->str,
1888 24
                $substring,
1889 24
                $index,
1890 24
                $this->encoding
1891
            ),
1892 24
            $this->encoding
1893
        );
1894
    }
1895
1896
    /**
1897
     * Returns true if the string contains the $pattern, otherwise false.
1898
     *
1899
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
1900
     * expression wildcards.
1901
     *
1902
     * EXAMPLE: <code>
1903
     * s('Foo\\Bar\\Lall')->is('*\\Bar\\*'); // true
1904
     * </code>
1905
     *
1906
     * @credit Originally from Laravel, thanks Taylor.
1907
     *
1908
     * @param string $pattern <p>The string or pattern to match against.</p>
1909
     *
1910
     * @psalm-mutation-free
1911
     *
1912
     * @return bool
1913
     *              <p>Whether or not we match the provided pattern.</p>
1914
     */
1915 26
    public function is(string $pattern): bool
1916
    {
1917 26
        if ($this->toString() === $pattern) {
1918 2
            return true;
1919
        }
1920
1921 24
        $quotedPattern = \preg_quote($pattern, '/');
1922 24
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
1923
1924 24
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
1925
    }
1926
1927
    /**
1928
     * Returns true if the string contains only alphabetic chars, false otherwise.
1929
     *
1930
     * EXAMPLE: <code>
1931
     * s('丹尼爾')->isAlpha(); // true
1932
     * </code>
1933
     *
1934
     * @psalm-mutation-free
1935
     *
1936
     * @return bool
1937
     *              <p>Whether or not $str contains only alphabetic chars.</p>
1938
     */
1939 30
    public function isAlpha(): bool
1940
    {
1941 30
        return $this->utf8::is_alpha($this->str);
1942
    }
1943
1944
    /**
1945
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
1946
     *
1947
     * EXAMPLE: <code>
1948
     * s('دانيال1')->isAlphanumeric(); // true
1949
     * </code>
1950
     *
1951
     * @psalm-mutation-free
1952
     *
1953
     * @return bool
1954
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
1955
     */
1956 39
    public function isAlphanumeric(): bool
1957
    {
1958 39
        return $this->utf8::is_alphanumeric($this->str);
1959
    }
1960
1961
    /**
1962
     * Returns true if the string is base64 encoded, false otherwise.
1963
     *
1964
     * EXAMPLE: <code>
1965
     * s('Zm9vYmFy')->isBase64(); // true
1966
     * </code>
1967
     *
1968
     * @param bool $emptyStringIsValid
1969
     *
1970
     * @psalm-mutation-free
1971
     *
1972
     * @return bool
1973
     *              <p>Whether or not $str is base64 encoded.</p>
1974
     */
1975 21
    public function isBase64($emptyStringIsValid = true): bool
1976
    {
1977 21
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
1978
    }
1979
1980
    /**
1981
     * Returns true if the string contains only whitespace chars, false otherwise.
1982
     *
1983
     * EXAMPLE: <code>
1984
     * s("\n\t  \v\f")->isBlank(); // true
1985
     * </code>
1986
     *
1987
     * @psalm-mutation-free
1988
     *
1989
     * @return bool
1990
     *              <p>Whether or not $str contains only whitespace characters.</p>
1991
     */
1992 45
    public function isBlank(): bool
1993
    {
1994 45
        return $this->utf8::is_blank($this->str);
1995
    }
1996
1997
    /**
1998
     * Returns true if the string contains a valid E-Mail address, false otherwise.
1999
     *
2000
     * EXAMPLE: <code>
2001
     * s('[email protected]')->isEmail(); // true
2002
     * </code>
2003
     *
2004
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
2005
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
2006
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
2007
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
2008
     *
2009
     * @psalm-mutation-free
2010
     *
2011
     * @return bool
2012
     *              <p>Whether or not $str contains a valid E-Mail address.</p>
2013
     */
2014 2
    public function isEmail(
2015
        bool $useExampleDomainCheck = false,
2016
        bool $useTypoInDomainCheck = false,
2017
        bool $useTemporaryDomainCheck = false,
2018
        bool $useDnsCheck = false
2019
    ): bool {
2020
        /**
2021
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the email-check class
2022
         */
2023 2
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
2024
    }
2025
2026
    /**
2027
     * Determine whether the string is considered to be empty.
2028
     *
2029
     * A variable is considered empty if it does not exist or if its value equals FALSE.
2030
     *
2031
     * EXAMPLE: <code>
2032
     * s('')->isEmpty(); // true
2033
     * </code>
2034
     *
2035
     * @psalm-mutation-free
2036
     *
2037
     * @return bool
2038
     *              <p>Whether or not $str is empty().</p>
2039
     */
2040 10
    public function isEmpty(): bool
2041
    {
2042 10
        return $this->utf8::is_empty($this->str);
2043
    }
2044
2045
    /**
2046
     * Determine whether the string is equals to $str.
2047
     * Alias for isEqualsCaseSensitive()
2048
     *
2049
     * EXAMPLE: <code>
2050
     * s('foo')->isEquals('foo'); // true
2051
     * </code>
2052
     *
2053
     * @param string|Stringy ...$str
2054
     *
2055
     * @psalm-mutation-free
2056
     *
2057
     * @return bool
2058
     */
2059 13
    public function isEquals(...$str): bool
2060
    {
2061 13
        return $this->isEqualsCaseSensitive(...$str);
2062
    }
2063
2064
    /**
2065
     * Determine whether the string is equals to $str.
2066
     *
2067
     * EXAMPLE: <code>
2068
     * </code>
2069
     *
2070
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
2071
     *
2072
     * @psalm-mutation-free
2073
     *
2074
     * @return bool
2075
     *              <p>Whether or not $str is equals.</p>
2076
     */
2077 3
    public function isEqualsCaseInsensitive(...$str): bool
2078
    {
2079 3
        $strUpper = $this->toUpperCase()->str;
2080
2081 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...
2082
            /**
2083
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
2084
             */
2085 3
            if ($strTmp instanceof self) {
2086
                if ($strUpper !== $strTmp->toUpperCase()->str) {
2087
                    return false;
2088
                }
2089 3
            } elseif (\is_scalar($strTmp)) {
2090 3
                if ($strUpper !== $this->utf8::strtoupper((string) $strTmp, $this->encoding)) {
2091 3
                    return false;
2092
                }
2093
            } else {
2094
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
2095
            }
2096
        }
2097
2098 3
        return true;
2099
    }
2100
2101
    /**
2102
     * Determine whether the string is equals to $str.
2103
     *
2104
     * EXAMPLE: <code>
2105
     * </code>
2106
     *
2107
     * @param float|int|string|Stringy ...$str <p>The string to compare.</p>
2108
     *
2109
     * @psalm-mutation-free
2110
     *
2111
     * @return bool
2112
     *              <p>Whether or not $str is equals.</p>
2113
     */
2114 14
    public function isEqualsCaseSensitive(...$str): bool
2115
    {
2116 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...
2117
            /**
2118
             * @psalm-suppress RedundantConditionGivenDocblockType - wait for union-types :)
2119
             */
2120 14
            if ($strTmp instanceof self) {
2121 2
                if ($this->str !== $strTmp->str) {
2122 2
                    return false;
2123
                }
2124 12
            } elseif (\is_scalar($strTmp)) {
2125 12
                if ($this->str !== (string) $strTmp) {
2126 12
                    return false;
2127
                }
2128
            } else {
2129
                throw new \InvalidArgumentException('expected: int|float|string|Stringy -> given: ' . \print_r($strTmp, true) . ' [' . \gettype($strTmp) . ']');
2130
            }
2131
        }
2132
2133 3
        return true;
2134
    }
2135
2136
    /**
2137
     * Returns true if the string contains only hexadecimal chars, false otherwise.
2138
     *
2139
     * EXAMPLE: <code>
2140
     * s('A102F')->isHexadecimal(); // true
2141
     * </code>
2142
     *
2143
     * @psalm-mutation-free
2144
     *
2145
     * @return bool
2146
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
2147
     */
2148 39
    public function isHexadecimal(): bool
2149
    {
2150 39
        return $this->utf8::is_hexadecimal($this->str);
2151
    }
2152
2153
    /**
2154
     * Returns true if the string contains HTML-Tags, false otherwise.
2155
     *
2156
     * EXAMPLE: <code>
2157
     * s('<h1>foo</h1>')->isHtml(); // true
2158
     * </code>
2159
     *
2160
     * @psalm-mutation-free
2161
     *
2162
     * @return bool
2163
     *              <p>Whether or not $str contains HTML-Tags.</p>
2164
     */
2165 2
    public function isHtml(): bool
2166
    {
2167 2
        return $this->utf8::is_html($this->str);
2168
    }
2169
2170
    /**
2171
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
2172
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
2173
     * in that an empty string is not considered valid JSON.
2174
     *
2175
     * EXAMPLE: <code>
2176
     * s('{"foo":"bar"}')->isJson(); // true
2177
     * </code>
2178
     *
2179
     * @param bool $onlyArrayOrObjectResultsAreValid
2180
     *
2181
     * @psalm-mutation-free
2182
     *
2183
     * @return bool
2184
     *              <p>Whether or not $str is JSON.</p>
2185
     */
2186 60
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
2187
    {
2188
        /**
2189
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to vendor stuff?
2190
         */
2191 60
        return $this->utf8::is_json(
2192 60
            $this->str,
2193 60
            $onlyArrayOrObjectResultsAreValid
2194
        );
2195
    }
2196
2197
    /**
2198
     * Returns true if the string contains only lower case chars, false otherwise.
2199
     *
2200
     * EXAMPLE: <code>
2201
     * s('fòôbàř')->isLowerCase(); // true
2202
     * </code>
2203
     *
2204
     * @psalm-mutation-free
2205
     *
2206
     * @return bool
2207
     *              <p>Whether or not $str contains only lower case characters.</p>
2208
     */
2209 24
    public function isLowerCase(): bool
2210
    {
2211 24
        return $this->utf8::is_lowercase($this->str);
2212
    }
2213
2214
    /**
2215
     * Determine whether the string is considered to be NOT empty.
2216
     *
2217
     * A variable is considered NOT empty if it does exist or if its value equals TRUE.
2218
     *
2219
     * EXAMPLE: <code>
2220
     * s('')->isNotEmpty(); // false
2221
     * </code>
2222
     *
2223
     * @psalm-mutation-free
2224
     *
2225
     * @return bool
2226
     *              <p>Whether or not $str is empty().</p>
2227
     */
2228 10
    public function isNotEmpty(): bool
2229
    {
2230 10
        return !$this->utf8::is_empty($this->str);
2231
    }
2232
2233
    /**
2234
     * Determine if the string is composed of numeric characters.
2235
     *
2236
     * EXAMPLE: <code>
2237
     * </code>
2238
     *
2239
     * @psalm-mutation-free
2240
     *
2241
     * @return bool
2242
     */
2243 4
    public function isNumeric(): bool
2244
    {
2245 4
        return \is_numeric($this->str);
2246
    }
2247
2248
    /**
2249
     * Determine if the string is composed of printable (non-invisible) characters.
2250
     *
2251
     * EXAMPLE: <code>
2252
     * </code>
2253
     *
2254
     * @psalm-mutation-free
2255
     *
2256
     * @return bool
2257
     */
2258 3
    public function isPrintable(): bool
2259
    {
2260 3
        return $this->utf8::is_printable($this->str);
2261
    }
2262
2263
    /**
2264
     * Determine if the string is composed of punctuation characters.
2265
     *
2266
     * EXAMPLE: <code>
2267
     * </code>
2268
     *
2269
     * @psalm-mutation-free
2270
     *
2271
     * @return bool
2272
     */
2273 3
    public function isPunctuation(): bool
2274
    {
2275 3
        return $this->utf8::is_punctuation($this->str);
2276
    }
2277
2278
    /**
2279
     * Returns true if the string is serialized, false otherwise.
2280
     *
2281
     * EXAMPLE: <code>
2282
     * s('a:1:{s:3:"foo";s:3:"bar";}')->isSerialized(); // true
2283
     * </code>
2284
     *
2285
     * @psalm-mutation-free
2286
     *
2287
     * @return bool
2288
     *              <p>Whether or not $str is serialized.</p>
2289
     */
2290 21
    public function isSerialized(): bool
2291
    {
2292 21
        return $this->utf8::is_serialized($this->str);
2293
    }
2294
2295
    /**
2296
     * Check if two strings are similar.
2297
     *
2298
     * EXAMPLE: <code>
2299
     * </code>
2300
     *
2301
     * @param string $str                     <p>The string to compare against.</p>
2302
     * @param float  $minPercentForSimilarity [optional] <p>The percentage of needed similarity. | Default: 80%</p>
2303
     *
2304
     * @psalm-mutation-free
2305
     *
2306
     * @return bool
2307
     */
2308 2
    public function isSimilar(string $str, float $minPercentForSimilarity = 80.0): bool
2309
    {
2310 2
        return $this->similarity($str) >= $minPercentForSimilarity;
2311
    }
2312
2313
    /**
2314
     * Returns true if the string contains only lower case chars, false
2315
     * otherwise.
2316
     *
2317
     * EXAMPLE: <code>
2318
     * s('FÒÔBÀŘ')->isUpperCase(); // true
2319
     * </code>
2320
     *
2321
     * @psalm-mutation-free
2322
     *
2323
     * @return bool
2324
     *              <p>Whether or not $str contains only lower case characters.</p>
2325
     */
2326 24
    public function isUpperCase(): bool
2327
    {
2328 24
        return $this->utf8::is_uppercase($this->str);
2329
    }
2330
2331
    /**
2332
     * Returns true if the string contains only whitespace chars, false otherwise.
2333
     *
2334
     * EXAMPLE: <code>
2335
     * </code>
2336
     *
2337
     * @psalm-mutation-free
2338
     *
2339
     * @return bool
2340
     *              <p>Whether or not $str contains only whitespace characters.</p>
2341
     */
2342 30
    public function isWhitespace(): bool
2343
    {
2344 30
        return $this->isBlank();
2345
    }
2346
2347
    /**
2348
     * Returns value which can be serialized by json_encode().
2349
     *
2350
     * EXAMPLE: <code>
2351
     * </code>
2352
     *
2353
     * @noinspection ReturnTypeCanBeDeclaredInspection
2354
     *
2355
     * @psalm-mutation-free
2356
     *
2357
     * @return string The current value of the $str property
2358
     */
2359 2
    public function jsonSerialize()
2360
    {
2361 2
        return (string) $this;
2362
    }
2363
2364
    /**
2365
     * Convert the string to kebab-case.
2366
     *
2367
     * EXAMPLE: <code>
2368
     * </code>
2369
     *
2370
     * @psalm-mutation-free
2371
     *
2372
     * @return static
2373
     */
2374 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...
2375
    {
2376 3
        $words = \array_map(
2377
            static function (self $word) {
2378 3
                return $word->toLowerCase();
2379 3
            },
2380 3
            $this->words('', true)
2381
        );
2382
2383 3
        return new static(\implode('-', $words), $this->encoding);
2384
    }
2385
2386
    /**
2387
     * Returns the last $n characters of the string.
2388
     *
2389
     * EXAMPLE: <code>
2390
     * s('fòôbàř')->last(3); // 'bàř'
2391
     * </code>
2392
     *
2393
     * @param int $n <p>Number of characters to retrieve from the end.</p>
2394
     *
2395
     * @psalm-mutation-free
2396
     *
2397
     * @return static
2398
     *                <p>Object with its $str being the last $n chars.</p>
2399
     */
2400 36
    public function last(int $n): self
2401
    {
2402 36
        return static::create(
2403 36
            $this->utf8::str_last_char(
2404 36
                $this->str,
2405 36
                $n,
2406 36
                $this->encoding
2407
            ),
2408 36
            $this->encoding
2409
        );
2410
    }
2411
2412
    /**
2413
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2414
     * If no match is found returns new empty Stringy object.
2415
     *
2416
     * EXAMPLE: <code>
2417
     * </code>
2418
     *
2419
     * @param string $needle       <p>The string to look for.</p>
2420
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2421
     *
2422
     * @psalm-mutation-free
2423
     *
2424
     * @return static
2425
     */
2426 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...
2427
    {
2428 4
        return static::create(
2429 4
            $this->utf8::str_substr_last(
2430 4
                $this->str,
2431 4
                $needle,
2432 4
                $beforeNeedle,
2433 4
                $this->encoding
2434
            ),
2435 4
            $this->encoding
2436
        );
2437
    }
2438
2439
    /**
2440
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
2441
     * If no match is found returns new empty Stringy object.
2442
     *
2443
     * EXAMPLE: <code>
2444
     * </code>
2445
     *
2446
     * @param string $needle       <p>The string to look for.</p>
2447
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2448
     *
2449
     * @psalm-mutation-free
2450
     *
2451
     * @return static
2452
     */
2453 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...
2454
    {
2455 2
        return static::create(
2456 2
            $this->utf8::str_isubstr_last(
2457 2
                $this->str,
2458 2
                $needle,
2459 2
                $beforeNeedle,
2460 2
                $this->encoding
2461
            ),
2462 2
            $this->encoding
2463
        );
2464
    }
2465
2466
    /**
2467
     * Returns the length of the string.
2468
     *
2469
     * EXAMPLE: <code>
2470
     * s('fòôbàř')->length(); // 6
2471
     * </code>
2472
     *
2473
     * @psalm-mutation-free
2474
     *
2475
     * @return int
2476
     *             <p>The number of characters in $str given the encoding.</p>
2477
     */
2478 17
    public function length(): int
2479
    {
2480 17
        return (int) $this->utf8::strlen($this->str, $this->encoding);
2481
    }
2482
2483
    /**
2484
     * Line-Wrap the string after $limit, but also after the next word.
2485
     *
2486
     * EXAMPLE: <code>
2487
     * </code>
2488
     *
2489
     * @param int         $limit           [optional] <p>The column width.</p>
2490
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2491
     * @param bool        $add_final_break [optional] <p>
2492
     *                                     If this flag is true, then the method will add a $break at the end
2493
     *                                     of the result string.
2494
     *                                     </p>
2495
     * @param string|null $delimiter       [optional] <p>
2496
     *                                     You can change the default behavior, where we split the string by newline.
2497
     *                                     </p>
2498
     *
2499
     * @psalm-mutation-free
2500
     *
2501
     * @return static
2502
     */
2503 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...
2504
        int $limit,
2505
        string $break = "\n",
2506
        bool $add_final_break = true,
2507
        string $delimiter = null
2508
    ): self {
2509 3
        return static::create(
2510 3
            $this->utf8::wordwrap_per_line(
2511 3
                $this->str,
2512 3
                $limit,
2513 3
                $break,
2514 3
                true,
2515 3
                $add_final_break,
2516 3
                $delimiter
2517
            ),
2518 3
            $this->encoding
2519
        );
2520
    }
2521
2522
    /**
2523
     * Line-Wrap the string after $limit, but also after the next word.
2524
     *
2525
     * EXAMPLE: <code>
2526
     * </code>
2527
     *
2528
     * @param int         $limit           [optional] <p>The column width.</p>
2529
     * @param string      $break           [optional] <p>The line is broken using the optional break parameter.</p>
2530
     * @param bool        $add_final_break [optional] <p>
2531
     *                                     If this flag is true, then the method will add a $break at the end
2532
     *                                     of the result string.
2533
     *                                     </p>
2534
     * @param string|null $delimiter       [optional] <p>
2535
     *                                     You can change the default behavior, where we split the string by newline.
2536
     *                                     </p>
2537
     *
2538
     * @psalm-mutation-free
2539
     *
2540
     * @return static
2541
     */
2542 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...
2543
        int $limit,
2544
        string $break = "\n",
2545
        bool $add_final_break = true,
2546
        string $delimiter = null
2547
    ): self {
2548 4
        return static::create(
2549 4
            $this->utf8::wordwrap_per_line(
2550 4
                $this->str,
2551 4
                $limit,
2552 4
                $break,
2553 4
                false,
2554 4
                $add_final_break,
2555 4
                $delimiter
2556
            ),
2557 4
            $this->encoding
2558
        );
2559
    }
2560
2561
    /**
2562
     * Splits on newlines and carriage returns, returning an array of Stringy
2563
     * objects corresponding to the lines in the string.
2564
     *
2565
     * EXAMPLE: <code>
2566
     * s("fòô\r\nbàř\n")->lines(); // ['fòô', 'bàř', '']
2567
     * </code>
2568
     *
2569
     * @psalm-mutation-free
2570
     *
2571
     * @return static[]
2572
     *                  <p>An array of Stringy objects.</p>
2573
     *
2574
     * @psalm-return array<int,static>
2575
     */
2576 51
    public function lines(): array
2577
    {
2578 51
        if ($this->str === '') {
2579 3
            return [static::create('')];
2580
        }
2581
2582 48
        $strings = $this->utf8::str_to_lines($this->str);
2583
        /** @noinspection AlterInForeachInspection */
2584 48
        foreach ($strings as &$str) {
2585 48
            $str = static::create($str, $this->encoding);
2586
        }
2587
2588
        /** @noinspection PhpSillyAssignmentInspection */
2589
        /** @var static[] $strings */
2590 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...
2591
2592 48
        return $strings;
2593
    }
2594
2595
    /**
2596
     * Splits on newlines and carriage returns, returning an array of Stringy
2597
     * objects corresponding to the lines in the string.
2598
     *
2599
     * EXAMPLE: <code>
2600
     * </code>
2601
     *
2602
     * @psalm-mutation-free
2603
     *
2604
     * @return CollectionStringy|static[]
2605
     *                                    <p>An collection of Stringy objects.</p>
2606
     *
2607
     * @psalm-return CollectionStringy<int,static>
2608
     */
2609 34
    public function linesCollection(): CollectionStringy
2610
    {
2611
        /**
2612
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
2613
         */
2614 34
        return CollectionStringy::create(
2615 34
            $this->lines()
2616
        );
2617
    }
2618
2619
    /**
2620
     * Returns the longest common prefix between the string and $otherStr.
2621
     *
2622
     * EXAMPLE: <code>
2623
     * s('foobar')->longestCommonPrefix('foobaz'); // 'fooba'
2624
     * </code>
2625
     *
2626
     * @param string $otherStr <p>Second string for comparison.</p>
2627
     *
2628
     * @psalm-mutation-free
2629
     *
2630
     * @return static
2631
     *                <p>Object with its $str being the longest common prefix.</p>
2632
     */
2633 30
    public function longestCommonPrefix(string $otherStr): self
2634
    {
2635 30
        return static::create(
2636 30
            $this->utf8::str_longest_common_prefix(
2637 30
                $this->str,
2638 30
                $otherStr,
2639 30
                $this->encoding
2640
            ),
2641 30
            $this->encoding
2642
        );
2643
    }
2644
2645
    /**
2646
     * Returns the longest common substring between the string and $otherStr.
2647
     * In the case of ties, it returns that which occurs first.
2648
     *
2649
     * EXAMPLE: <code>
2650
     * s('foobar')->longestCommonSubstring('boofar'); // 'oo'
2651
     * </code>
2652
     *
2653
     * @param string $otherStr <p>Second string for comparison.</p>
2654
     *
2655
     * @psalm-mutation-free
2656
     *
2657
     * @return static
2658
     *                <p>Object with its $str being the longest common substring.</p>
2659
     */
2660 30
    public function longestCommonSubstring(string $otherStr): self
2661
    {
2662 30
        return static::create(
2663 30
            $this->utf8::str_longest_common_substring(
2664 30
                $this->str,
2665 30
                $otherStr,
2666 30
                $this->encoding
2667
            ),
2668 30
            $this->encoding
2669
        );
2670
    }
2671
2672
    /**
2673
     * Returns the longest common suffix between the string and $otherStr.
2674
     *
2675
     * EXAMPLE: <code>
2676
     * s('fòôbàř')->longestCommonSuffix('fòrbàř'); // 'bàř'
2677
     * </code>
2678
     *
2679
     * @param string $otherStr <p>Second string for comparison.</p>
2680
     *
2681
     * @psalm-mutation-free
2682
     *
2683
     * @return static
2684
     *                <p>Object with its $str being the longest common suffix.</p>
2685
     */
2686 30
    public function longestCommonSuffix(string $otherStr): self
2687
    {
2688 30
        return static::create(
2689 30
            $this->utf8::str_longest_common_suffix(
2690 30
                $this->str,
2691 30
                $otherStr,
2692 30
                $this->encoding
2693
            ),
2694 30
            $this->encoding
2695
        );
2696
    }
2697
2698
    /**
2699
     * Converts the first character of the string to lower case.
2700
     *
2701
     * EXAMPLE: <code>
2702
     * s('Σ Foo')->lowerCaseFirst(); // 'σ Foo'
2703
     * </code>
2704
     *
2705
     * @psalm-mutation-free
2706
     *
2707
     * @return static
2708
     *                <p>Object with the first character of $str being lower case.</p>
2709
     */
2710 16
    public function lowerCaseFirst(): self
2711
    {
2712 16
        return static::create(
2713 16
            $this->utf8::lcfirst($this->str, $this->encoding),
2714 16
            $this->encoding
2715
        );
2716
    }
2717
2718
    /**
2719
     * Determine if the string matches another string regardless of case.
2720
     * Alias for isEqualsCaseInsensitive()
2721
     *
2722
     * EXAMPLE: <code>
2723
     * </code>
2724
     *
2725
     * @psalm-mutation-free
2726
     *
2727
     * @param string|Stringy ...$str
2728
     *                               <p>The string to compare against.</p>
2729
     *
2730
     * @psalm-mutation-free
2731
     *
2732
     * @return bool
2733
     */
2734 3
    public function matchCaseInsensitive(...$str): bool
2735
    {
2736 3
        return $this->isEqualsCaseInsensitive(...$str);
2737
    }
2738
2739
    /**
2740
     * Determine if the string matches another string.
2741
     * Alias for isEqualsCaseSensitive()
2742
     *
2743
     * EXAMPLE: <code>
2744
     * </code>
2745
     *
2746
     * @psalm-mutation-free
2747
     *
2748
     * @param string|Stringy ...$str
2749
     *                               <p>The string to compare against.</p>
2750
     *
2751
     * @psalm-mutation-free
2752
     *
2753
     * @return bool
2754
     */
2755 7
    public function matchCaseSensitive(...$str): bool
2756
    {
2757 7
        return $this->isEqualsCaseSensitive(...$str);
2758
    }
2759
2760
    /**
2761
     * Create a md5 hash from the current string.
2762
     *
2763
     * @psalm-mutation-free
2764
     *
2765
     * @return static
2766
     */
2767 2
    public function md5(): self
2768
    {
2769 2
        return static::create($this->hash('md5'), $this->encoding);
2770
    }
2771
2772
    /**
2773
     * Replace all breaks [<br> | \r\n | \r | \n | ...] into "<br>".
2774
     *
2775
     * EXAMPLE: <code>
2776
     * </code>
2777
     *
2778
     * @return static
2779
     */
2780 1
    public function newLineToHtmlBreak(): self
2781
    {
2782 1
        return $this->removeHtmlBreak('<br>');
2783
    }
2784
2785
    /**
2786
     * Get every nth character of the string.
2787
     *
2788
     * EXAMPLE: <code>
2789
     * </code>
2790
     *
2791
     * @param int $step   <p>The number of characters to step.</p>
2792
     * @param int $offset [optional] <p>The string offset to start at.</p>
2793
     *
2794
     * @psalm-mutation-free
2795
     *
2796
     * @return static
2797
     */
2798 4
    public function nth(int $step, int $offset = 0): self
2799
    {
2800 4
        $length = $step - 1;
2801 4
        $substring = $this->substr($offset)->toString();
2802
2803 4
        if ($substring === '') {
2804
            return new static('', $this->encoding);
2805
        }
2806
2807 4
        \preg_match_all(
2808 4
            "/(?:^|(?:.|\p{L}|\w){" . $length . "})(.|\p{L}|\w)/u",
2809 4
            $substring,
2810 4
            $matches
2811
        );
2812
2813 4
        return new static(\implode('', $matches[1] ?? []), $this->encoding);
2814
    }
2815
2816
    /**
2817
     * Returns whether or not a character exists at an index. Offsets may be
2818
     * negative to count from the last character in the string. Implements
2819
     * part of the ArrayAccess interface.
2820
     *
2821
     * EXAMPLE: <code>
2822
     * </code>
2823
     *
2824
     * @param int $offset <p>The index to check.</p>
2825
     *
2826
     * @psalm-mutation-free
2827
     *
2828
     * @return bool
2829
     *              <p>Whether or not the index exists.</p>
2830
     */
2831 18
    public function offsetExists($offset): bool
2832
    {
2833 18
        return $this->utf8::str_offset_exists(
2834 18
            $this->str,
2835 18
            $offset,
2836 18
            $this->encoding
2837
        );
2838
    }
2839
2840
    /**
2841
     * Returns the character at the given index. Offsets may be negative to
2842
     * count from the last character in the string. Implements part of the
2843
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
2844
     * does not exist.
2845
     *
2846
     * EXAMPLE: <code>
2847
     * </code>
2848
     *
2849
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
2850
     *
2851
     * @throws \OutOfBoundsException
2852
     *                               <p>If the positive or negative offset does not exist.</p>
2853
     *
2854
     * @return string
2855
     *                <p>The character at the specified index.</p>
2856
     *
2857
     * @psalm-mutation-free
2858
     */
2859 6
    public function offsetGet($offset): string
2860
    {
2861 6
        return $this->utf8::str_offset_get($this->str, $offset, $this->encoding);
2862
    }
2863
2864
    /**
2865
     * Implements part of the ArrayAccess interface, but throws an exception
2866
     * when called. This maintains the immutability of Stringy objects.
2867
     *
2868
     * EXAMPLE: <code>
2869
     * </code>
2870
     *
2871
     * @param int   $offset <p>The index of the character.</p>
2872
     * @param mixed $value  <p>Value to set.</p>
2873
     *
2874
     * @throws \Exception
2875
     *                    <p>When called.</p>
2876
     *
2877
     * @return void
2878
     */
2879 3
    public function offsetSet($offset, $value)
2880
    {
2881
        // Stringy is immutable, cannot directly set char
2882
        /** @noinspection ThrowRawExceptionInspection */
2883 3
        throw new \Exception('Stringy object is immutable, cannot modify char');
2884
    }
2885
2886
    /**
2887
     * Implements part of the ArrayAccess interface, but throws an exception
2888
     * when called. This maintains the immutability of Stringy objects.
2889
     *
2890
     * EXAMPLE: <code>
2891
     * </code>
2892
     *
2893
     * @param int $offset <p>The index of the character.</p>
2894
     *
2895
     * @throws \Exception
2896
     *                    <p>When called.</p>
2897
     *
2898
     * @return void
2899
     */
2900 3
    public function offsetUnset($offset)
2901
    {
2902
        // Don't allow directly modifying the string
2903
        /** @noinspection ThrowRawExceptionInspection */
2904 3
        throw new \Exception('Stringy object is immutable, cannot unset char');
2905
    }
2906
2907
    /**
2908
     * Pads the string to a given length with $padStr. If length is less than
2909
     * or equal to the length of the string, no padding takes places. The
2910
     * default string used for padding is a space, and the default type (one of
2911
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
2912
     * if $padType isn't one of those 3 values.
2913
     *
2914
     * EXAMPLE: <code>
2915
     * s('fòôbàř')->pad(9, '-/', 'left'); // '-/-fòôbàř'
2916
     * </code>
2917
     *
2918
     * @param int    $length  <p>Desired string length after padding.</p>
2919
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2920
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
2921
     *
2922
     * @throws \InvalidArgumentException
2923
     *                                   <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
2924
     *
2925
     * @return static
2926
     *                <p>Object with a padded $str.</p>
2927
     *
2928
     * @psalm-mutation-free
2929
     */
2930 39
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
2931
    {
2932 39
        return static::create(
2933 39
            $this->utf8::str_pad(
2934 39
                $this->str,
2935 39
                $length,
2936 39
                $padStr,
2937 39
                $padType,
2938 39
                $this->encoding
2939
            )
2940
        );
2941
    }
2942
2943
    /**
2944
     * Returns a new string of a given length such that both sides of the
2945
     * string are padded. Alias for pad() with a $padType of 'both'.
2946
     *
2947
     * EXAMPLE: <code>
2948
     * s('foo bar')->padBoth(9, ' '); // ' foo bar '
2949
     * </code>
2950
     *
2951
     * @param int    $length <p>Desired string length after padding.</p>
2952
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2953
     *
2954
     * @psalm-mutation-free
2955
     *
2956
     * @return static
2957
     *                <p>String with padding applied.</p>
2958
     */
2959 33
    public function padBoth(int $length, string $padStr = ' '): self
2960
    {
2961 33
        return static::create(
2962 33
            $this->utf8::str_pad_both(
2963 33
                $this->str,
2964 33
                $length,
2965 33
                $padStr,
2966 33
                $this->encoding
2967
            )
2968
        );
2969
    }
2970
2971
    /**
2972
     * Returns a new string of a given length such that the beginning of the
2973
     * string is padded. Alias for pad() with a $padType of 'left'.
2974
     *
2975
     * EXAMPLE: <code>
2976
     * s('foo bar')->padLeft(9, ' '); // '  foo bar'
2977
     * </code>
2978
     *
2979
     * @param int    $length <p>Desired string length after padding.</p>
2980
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
2981
     *
2982
     * @psalm-mutation-free
2983
     *
2984
     * @return static
2985
     *                <p>String with left padding.</p>
2986
     */
2987 21
    public function padLeft(int $length, string $padStr = ' '): self
2988
    {
2989 21
        return static::create(
2990 21
            $this->utf8::str_pad_left(
2991 21
                $this->str,
2992 21
                $length,
2993 21
                $padStr,
2994 21
                $this->encoding
2995
            )
2996
        );
2997
    }
2998
2999
    /**
3000
     * Returns a new string of a given length such that the end of the string
3001
     * is padded. Alias for pad() with a $padType of 'right'.
3002
     *
3003
     * EXAMPLE: <code>
3004
     * s('foo bar')->padRight(10, '_*'); // 'foo bar_*_'
3005
     * </code>
3006
     *
3007
     * @param int    $length <p>Desired string length after padding.</p>
3008
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
3009
     *
3010
     * @psalm-mutation-free
3011
     *
3012
     * @return static
3013
     *                <p>String with right padding.</p>
3014
     */
3015 21
    public function padRight(int $length, string $padStr = ' '): self
3016
    {
3017 21
        return static::create(
3018 21
            $this->utf8::str_pad_right(
3019 21
                $this->str,
3020 21
                $length,
3021 21
                $padStr,
3022 21
                $this->encoding
3023
            )
3024
        );
3025
    }
3026
3027
    /**
3028
     * Convert the string to PascalCase.
3029
     * Alias for studlyCase()
3030
     *
3031
     * EXAMPLE: <code>
3032
     * </code>
3033
     *
3034
     * @psalm-mutation-free
3035
     *
3036
     * @return static
3037
     */
3038 3
    public function pascalCase(): self
3039
    {
3040 3
        return $this->studlyCase();
3041
    }
3042
3043
    /**
3044
     * Returns a new string starting with $prefix.
3045
     *
3046
     * EXAMPLE: <code>
3047
     * s('bàř')->prepend('fòô'); // 'fòôbàř'
3048
     * </code>
3049
     *
3050
     * @param string ...$prefix <p>The string to append.</p>
3051
     *
3052
     * @psalm-mutation-free
3053
     *
3054
     * @return static
3055
     *                <p>Object with appended $prefix.</p>
3056
     */
3057 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...
3058
    {
3059 8
        if (\count($prefix) <= 1) {
3060
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
3061 6
            $prefix = $prefix[0];
3062
        } else {
3063
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
3064 2
            $prefix = \implode('', $prefix);
3065
        }
3066
3067 8
        return static::create($prefix . $this->str, $this->encoding);
3068
    }
3069
3070
    /**
3071
     * Returns a new string starting with $prefix.
3072
     *
3073
     * EXAMPLE: <code>
3074
     * </code>
3075
     *
3076
     * @param CollectionStringy|static ...$prefix <p>The Stringy objects to append.</p>
3077
     *
3078
     * @psalm-param CollectionStringy<int,static>|static ...$prefix
3079
     *
3080
     * @psalm-mutation-free
3081
     *
3082
     * @return static
3083
     *                <p>Object with appended $prefix.</p>
3084
     */
3085 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...
3086
    {
3087 1
        $prefixStr = '';
3088 1
        foreach ($prefix as $prefixTmp) {
3089 1
            if ($prefixTmp instanceof CollectionStringy) {
3090 1
                $prefixStr .= $prefixTmp->implode('');
3091
            } else {
3092 1
                $prefixStr .= $prefixTmp->toString();
3093
            }
3094
        }
3095
3096 1
        return static::create($prefixStr . $this->str, $this->encoding);
3097
    }
3098
3099
    /**
3100
     * Replaces all occurrences of $pattern in $str by $replacement.
3101
     *
3102
     * EXAMPLE: <code>
3103
     * s('fòô ')->regexReplace('f[òô]+\s', 'bàř'); // 'bàř'
3104
     * s('fò')->regexReplace('(ò)', '\\1ô'); // 'fòô'
3105
     * </code>
3106
     *
3107
     * @param string $pattern     <p>The regular expression pattern.</p>
3108
     * @param string $replacement <p>The string to replace with.</p>
3109
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
3110
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
3111
     *
3112
     * @psalm-mutation-free
3113
     *
3114
     * @return static
3115
     *                <p>Object with the result2ing $str after the replacements.</p>
3116
     */
3117 29
    public function regexReplace(
3118
        string $pattern,
3119
        string $replacement,
3120
        string $options = '',
3121
        string $delimiter = '/'
3122
    ): self {
3123 29
        return static::create(
3124 29
            $this->utf8::regex_replace(
3125 29
                $this->str,
3126 29
                $pattern,
3127 29
                $replacement,
3128 29
                $options,
3129 29
                $delimiter
3130
            ),
3131 29
            $this->encoding
3132
        );
3133
    }
3134
3135
    /**
3136
     * Remove html via "strip_tags()" from the string.
3137
     *
3138
     * EXAMPLE: <code>
3139
     * s('řàb <ô>òf\', ô<br/>foo <a href="#">lall</a>')->removeHtml('<br><br/>'); // 'řàb òf\', ô<br/>foo lall'
3140
     * </code>
3141
     *
3142
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
3143
     *                              not be stripped. Default: null
3144
     *                              </p>
3145
     *
3146
     * @psalm-mutation-free
3147
     *
3148
     * @return static
3149
     */
3150 12
    public function removeHtml(string $allowableTags = ''): self
3151
    {
3152 12
        return static::create(
3153 12
            $this->utf8::remove_html($this->str, $allowableTags),
3154 12
            $this->encoding
3155
        );
3156
    }
3157
3158
    /**
3159
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
3160
     *
3161
     * EXAMPLE: <code>
3162
     * s('řàb <ô>òf\', ô<br/>foo <a href="#">lall</a>')->removeHtmlBreak(''); // 'řàb <ô>òf\', ô< foo <a href="#">lall</a>'
3163
     * </code>
3164
     *
3165
     * @param string $replacement [optional] <p>Default is a empty string.</p>
3166
     *
3167
     * @psalm-mutation-free
3168
     *
3169
     * @return static
3170
     */
3171 13
    public function removeHtmlBreak(string $replacement = ''): self
3172
    {
3173 13
        return static::create(
3174 13
            $this->utf8::remove_html_breaks($this->str, $replacement),
3175 13
            $this->encoding
3176
        );
3177
    }
3178
3179
    /**
3180
     * Returns a new string with the prefix $substring removed, if present.
3181
     *
3182
     * EXAMPLE: <code>
3183
     * s('fòôbàř')->removeLeft('fòô'); // 'bàř'
3184
     * </code>
3185
     *
3186
     * @param string $substring <p>The prefix to remove.</p>
3187
     *
3188
     * @psalm-mutation-free
3189
     *
3190
     * @return static
3191
     *                <p>Object having a $str without the prefix $substring.</p>
3192
     */
3193 36
    public function removeLeft(string $substring): self
3194
    {
3195 36
        return static::create(
3196 36
            $this->utf8::remove_left($this->str, $substring, $this->encoding),
3197 36
            $this->encoding
3198
        );
3199
    }
3200
3201
    /**
3202
     * Returns a new string with the suffix $substring removed, if present.
3203
     *
3204
     * EXAMPLE: <code>
3205
     * s('fòôbàř')->removeRight('bàř'); // 'fòô'
3206
     * </code>
3207
     *
3208
     * @param string $substring <p>The suffix to remove.</p>
3209
     *
3210
     * @psalm-mutation-free
3211
     *
3212
     * @return static
3213
     *                <p>Object having a $str without the suffix $substring.</p>
3214
     */
3215 36
    public function removeRight(string $substring): self
3216
    {
3217 36
        return static::create(
3218 36
            $this->utf8::remove_right($this->str, $substring, $this->encoding),
3219 36
            $this->encoding
3220
        );
3221
    }
3222
3223
    /**
3224
     * Try to remove all XSS-attacks from the string.
3225
     *
3226
     * EXAMPLE: <code>
3227
     * 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 >'
3228
     * </code>
3229
     *
3230
     * @psalm-mutation-free
3231
     *
3232
     * @return static
3233
     */
3234 12
    public function removeXss(): self
3235
    {
3236
        /**
3237
         * @var AntiXSS|null
3238
         *
3239
         * @psalm-suppress ImpureStaticVariable
3240
         */
3241 12
        static $antiXss = null;
3242
3243 12
        if ($antiXss === null) {
3244 1
            $antiXss = new AntiXSS();
3245
        }
3246
3247
        /**
3248
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the anti-xss class
3249
         */
3250 12
        $str = $antiXss->xss_clean($this->str);
3251
3252 12
        return static::create($str, $this->encoding);
3253
    }
3254
3255
    /**
3256
     * Returns a repeated string given a multiplier.
3257
     *
3258
     * EXAMPLE: <code>
3259
     * s('α')->repeat(3); // 'ααα'
3260
     * </code>
3261
     *
3262
     * @param int $multiplier <p>The number of times to repeat the string.</p>
3263
     *
3264
     * @psalm-mutation-free
3265
     *
3266
     * @return static
3267
     *                <p>Object with a repeated str.</p>
3268
     */
3269 21
    public function repeat(int $multiplier): self
3270
    {
3271 21
        return static::create(
3272 21
            \str_repeat($this->str, $multiplier),
3273 21
            $this->encoding
3274
        );
3275
    }
3276
3277
    /**
3278
     * Replaces all occurrences of $search in $str by $replacement.
3279
     *
3280
     * EXAMPLE: <code>
3281
     * s('fòô bàř fòô bàř')->replace('fòô ', ''); // 'bàř bàř'
3282
     * </code>
3283
     *
3284
     * @param string $search        <p>The needle to search for.</p>
3285
     * @param string $replacement   <p>The string to replace with.</p>
3286
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3287
     *
3288
     * @psalm-mutation-free
3289
     *
3290
     * @return static
3291
     *                <p>Object with the resulting $str after the replacements.</p>
3292
     */
3293 76
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
3294
    {
3295 76
        if ($search === '' && $replacement === '') {
3296 16
            return static::create($this->str, $this->encoding);
3297
        }
3298
3299 60
        if ($this->str === '' && $search === '') {
3300 2
            return static::create($replacement, $this->encoding);
3301
        }
3302
3303 58
        if ($caseSensitive) {
3304 48
            return static::create(
3305 48
                \str_replace($search, $replacement, $this->str),
3306 48
                $this->encoding
3307
            );
3308
        }
3309
3310 10
        return static::create(
3311 10
            $this->utf8::str_ireplace($search, $replacement, $this->str),
3312 10
            $this->encoding
3313
        );
3314
    }
3315
3316
    /**
3317
     * Replaces all occurrences of $search in $str by $replacement.
3318
     *
3319
     * EXAMPLE: <code>
3320
     * s('fòô bàř lall bàř')->replaceAll(['fòÔ ', 'lall'], '', false); // 'bàř bàř'
3321
     * </code>
3322
     *
3323
     * @param string[]        $search        <p>The elements to search for.</p>
3324
     * @param string|string[] $replacement   <p>The string to replace with.</p>
3325
     * @param bool            $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3326
     *
3327
     * @psalm-mutation-free
3328
     *
3329
     * @return static
3330
     *                <p>Object with the resulting $str after the replacements.</p>
3331
     */
3332 61
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
3333
    {
3334 61
        if ($caseSensitive) {
3335 47
            return static::create(
3336 47
                \str_replace($search, $replacement, $this->str),
3337 47
                $this->encoding
3338
            );
3339
        }
3340
3341 14
        return static::create(
3342 14
            $this->utf8::str_ireplace($search, $replacement, $this->str),
3343 14
            $this->encoding
3344
        );
3345
    }
3346
3347
    /**
3348
     * Replaces all occurrences of $search from the beginning of string with $replacement.
3349
     *
3350
     * EXAMPLE: <code>
3351
     * s('fòô bàř fòô bàř')->replaceBeginning('fòô', ''); // ' bàř bàř'
3352
     * </code>
3353
     *
3354
     * @param string $search      <p>The string to search for.</p>
3355
     * @param string $replacement <p>The replacement.</p>
3356
     *
3357
     * @psalm-mutation-free
3358
     *
3359
     * @return static
3360
     *                <p>Object with the resulting $str after the replacements.</p>
3361
     */
3362 32
    public function replaceBeginning(string $search, string $replacement): self
3363
    {
3364 32
        return static::create(
3365 32
            $this->utf8::str_replace_beginning($this->str, $search, $replacement),
3366 32
            $this->encoding
3367
        );
3368
    }
3369
3370
    /**
3371
     * Replaces all occurrences of $search from the ending of string with $replacement.
3372
     *
3373
     * EXAMPLE: <code>
3374
     * s('fòô bàř fòô bàř')->replaceEnding('bàř', ''); // 'fòô bàř fòô '
3375
     * </code>
3376
     *
3377
     * @param string $search      <p>The string to search for.</p>
3378
     * @param string $replacement <p>The replacement.</p>
3379
     *
3380
     * @psalm-mutation-free
3381
     *
3382
     * @return static
3383
     *                <p>Object with the resulting $str after the replacements.</p>
3384
     */
3385 32
    public function replaceEnding(string $search, string $replacement): self
3386
    {
3387 32
        return static::create(
3388 32
            $this->utf8::str_replace_ending($this->str, $search, $replacement),
3389 32
            $this->encoding
3390
        );
3391
    }
3392
3393
    /**
3394
     * Replaces first occurrences of $search from the beginning of string with $replacement.
3395
     *
3396
     * EXAMPLE: <code>
3397
     * </code>
3398
     *
3399
     * @param string $search      <p>The string to search for.</p>
3400
     * @param string $replacement <p>The replacement.</p>
3401
     *
3402
     * @psalm-mutation-free
3403
     *
3404
     * @return static
3405
     *                <p>Object with the resulting $str after the replacements.</p>
3406
     */
3407 32
    public function replaceFirst(string $search, string $replacement): self
3408
    {
3409 32
        return static::create(
3410 32
            $this->utf8::str_replace_first($search, $replacement, $this->str),
3411 32
            $this->encoding
3412
        );
3413
    }
3414
3415
    /**
3416
     * Replaces last occurrences of $search from the ending of string with $replacement.
3417
     *
3418
     * EXAMPLE: <code>
3419
     * </code>
3420
     *
3421
     * @param string $search      <p>The string to search for.</p>
3422
     * @param string $replacement <p>The replacement.</p>
3423
     *
3424
     * @psalm-mutation-free
3425
     *
3426
     * @return static
3427
     *                <p>Object with the resulting $str after the replacements.</p>
3428
     */
3429 30
    public function replaceLast(string $search, string $replacement): self
3430
    {
3431 30
        return static::create(
3432 30
            $this->utf8::str_replace_last($search, $replacement, $this->str),
3433 30
            $this->encoding
3434
        );
3435
    }
3436
3437
    /**
3438
     * Returns a reversed string. A multibyte version of strrev().
3439
     *
3440
     * EXAMPLE: <code>
3441
     * s('fòôbàř')->reverse(); // 'řàbôòf'
3442
     * </code>
3443
     *
3444
     * @psalm-mutation-free
3445
     *
3446
     * @return static
3447
     *                <p>Object with a reversed $str.</p>
3448
     */
3449 15
    public function reverse(): self
3450
    {
3451 15
        return static::create($this->utf8::strrev($this->str), $this->encoding);
3452
    }
3453
3454
    /**
3455
     * Truncates the string to a given length, while ensuring that it does not
3456
     * split words. If $substring is provided, and truncating occurs, the
3457
     * string is further truncated so that the substring may be appended without
3458
     * exceeding the desired length.
3459
     *
3460
     * EXAMPLE: <code>
3461
     * s('What are your plans today?')->safeTruncate(22, '...'); // 'What are your plans...'
3462
     * </code>
3463
     *
3464
     * @param int    $length                          <p>Desired length of the truncated string.</p>
3465
     * @param string $substring                       [optional] <p>The substring to append if it can fit. Default: ''</p>
3466
     * @param bool   $ignoreDoNotSplitWordsForOneWord
3467
     *
3468
     * @psalm-mutation-free
3469
     *
3470
     * @return static
3471
     *                <p>Object with the resulting $str after truncating.</p>
3472
     */
3473 68
    public function safeTruncate(
3474
        int $length,
3475
        string $substring = '',
3476
        bool $ignoreDoNotSplitWordsForOneWord = true
3477
    ): self {
3478 68
        return static::create(
3479 68
            $this->utf8::str_truncate_safe(
3480 68
                $this->str,
3481 68
                $length,
3482 68
                $substring,
3483 68
                $this->encoding,
3484 68
                $ignoreDoNotSplitWordsForOneWord
3485
            ),
3486 68
            $this->encoding
3487
        );
3488
    }
3489
3490
    /**
3491
     * Set the internal character encoding.
3492
     *
3493
     * EXAMPLE: <code>
3494
     * </code>
3495
     *
3496
     * @param string $new_encoding <p>The desired character encoding.</p>
3497
     *
3498
     * @psalm-mutation-free
3499
     *
3500
     * @return static
3501
     */
3502 1
    public function setInternalEncoding(string $new_encoding): self
3503
    {
3504 1
        return new static($this->str, $new_encoding);
3505
    }
3506
3507
    /**
3508
     * Create a sha1 hash from the current string.
3509
     *
3510
     * EXAMPLE: <code>
3511
     * </code>
3512
     *
3513
     * @psalm-mutation-free
3514
     *
3515
     * @return static
3516
     */
3517 2
    public function sha1(): self
3518
    {
3519 2
        return static::create($this->hash('sha1'), $this->encoding);
3520
    }
3521
3522
    /**
3523
     * Create a sha256 hash from the current string.
3524
     *
3525
     * EXAMPLE: <code>
3526
     * </code>
3527
     *
3528
     * @psalm-mutation-free
3529
     *
3530
     * @return static
3531
     */
3532 2
    public function sha256(): self
3533
    {
3534 2
        return static::create($this->hash('sha256'), $this->encoding);
3535
    }
3536
3537
    /**
3538
     * Create a sha512 hash from the current string.
3539
     *
3540
     * EXAMPLE: <code>
3541
     * </code>
3542
     *
3543
     * @psalm-mutation-free
3544
     *
3545
     * @return static
3546
     */
3547 2
    public function sha512(): self
3548
    {
3549 2
        return static::create($this->hash('sha512'), $this->encoding);
3550
    }
3551
3552
    /**
3553
     * Shorten the string after $length, but also after the next word.
3554
     *
3555
     * EXAMPLE: <code>
3556
     * s('this is a test')->shortenAfterWord(2, '...'); // 'this...'
3557
     * </code>
3558
     *
3559
     * @param int    $length   <p>The given length.</p>
3560
     * @param string $strAddOn [optional] <p>Default: '…'</p>
3561
     *
3562
     * @psalm-mutation-free
3563
     *
3564
     * @return static
3565
     */
3566 8
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
3567
    {
3568 8
        return static::create(
3569 8
            $this->utf8::str_limit_after_word($this->str, $length, $strAddOn),
3570 8
            $this->encoding
3571
        );
3572
    }
3573
3574
    /**
3575
     * A multibyte string shuffle function. It returns a string with its
3576
     * characters in random order.
3577
     *
3578
     * EXAMPLE: <code>
3579
     * s('fòôbàř')->shuffle(); // 'àôřbòf'
3580
     * </code>
3581
     *
3582
     * @return static
3583
     *                <p>Object with a shuffled $str.</p>
3584
     */
3585 9
    public function shuffle(): self
3586
    {
3587 9
        return static::create($this->utf8::str_shuffle($this->str), $this->encoding);
3588
    }
3589
3590
    /**
3591
     * Calculate the similarity between two strings.
3592
     *
3593
     * EXAMPLE: <code>
3594
     * </code>
3595
     *
3596
     * @param string $str <p>The delimiting string.</p>
3597
     *
3598
     * @psalm-mutation-free
3599
     *
3600
     * @return float
3601
     */
3602 2
    public function similarity(string $str): float
3603
    {
3604 2
        \similar_text($this->str, $str, $percent);
3605
3606 2
        return $percent;
3607
    }
3608
3609
    /**
3610
     * Returns the substring beginning at $start, and up to, but not including
3611
     * the index specified by $end. If $end is omitted, the function extracts
3612
     * the remaining string. If $end is negative, it is computed from the end
3613
     * of the string.
3614
     *
3615
     * EXAMPLE: <code>
3616
     * s('fòôbàř')->slice(3, -1); // 'bà'
3617
     * </code>
3618
     *
3619
     * @param int $start <p>Initial index from which to begin extraction.</p>
3620
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
3621
     *
3622
     * @psalm-mutation-free
3623
     *
3624
     * @return static
3625
     *                <p>Object with its $str being the extracted substring.</p>
3626
     */
3627 50
    public function slice(int $start, int $end = null): self
3628
    {
3629 50
        return static::create(
3630 50
            $this->utf8::str_slice($this->str, $start, $end, $this->encoding),
3631 50
            $this->encoding
3632
        );
3633
    }
3634
3635
    /**
3636
     * Converts the string into an URL slug. This includes replacing non-ASCII
3637
     * characters with their closest ASCII equivalents, removing remaining
3638
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
3639
     * $separator. The separator defaults to a single dash, and the string
3640
     * is also converted to lowercase. The language of the source string can
3641
     * also be supplied for language-specific transliteration.
3642
     *
3643
     * EXAMPLE: <code>
3644
     * s('Using strings like fòô bàř')->slugify(); // 'using-strings-like-foo-bar'
3645
     * </code>
3646
     *
3647
     * @param string                $separator             [optional] <p>The string used to replace whitespace.</p>
3648
     * @param string                $language              [optional] <p>Language of the source string.</p>
3649
     * @param array<string, string> $replacements          [optional] <p>A map of replaceable strings.</p>
3650
     * @param bool                  $replace_extra_symbols [optional]  <p>Add some more replacements e.g. "£" with "
3651
     *                                                     pound ".</p>
3652
     * @param bool                  $use_str_to_lower      [optional] <p>Use "string to lower" for the input.</p>
3653
     * @param bool                  $use_transliterate     [optional]  <p>Use ASCII::to_transliterate() for unknown
3654
     *                                                     chars.</p>
3655
     *
3656
     * @psalm-mutation-free
3657
     *
3658
     * @return static
3659
     *                <p>Object whose $str has been converted to an URL slug.</p>
3660
     *
3661
     * @noinspection PhpTooManyParametersInspection
3662
     */
3663 17
    public function slugify(
3664
        string $separator = '-',
3665
        string $language = 'en',
3666
        array $replacements = [],
3667
        bool $replace_extra_symbols = true,
3668
        bool $use_str_to_lower = true,
3669
        bool $use_transliterate = false
3670
    ): self {
3671 17
        return static::create(
3672 17
            $this->ascii::to_slugify(
3673 17
                $this->str,
3674 17
                $separator,
3675 17
                $language,
3676 17
                $replacements,
3677 17
                $replace_extra_symbols,
3678 17
                $use_str_to_lower,
3679 17
                $use_transliterate
3680
            ),
3681 17
            $this->encoding
3682
        );
3683
    }
3684
3685
    /**
3686
     * Convert the string to snake_case.
3687
     *
3688
     * EXAMPLE: <code>
3689
     * </code>
3690
     *
3691
     * @psalm-mutation-free
3692
     *
3693
     * @return static
3694
     */
3695 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...
3696
    {
3697 3
        $words = \array_map(
3698
            static function (self $word) {
3699 3
                return $word->toLowerCase();
3700 3
            },
3701 3
            $this->words('', true)
3702
        );
3703
3704 3
        return new static(\implode('_', $words), $this->encoding);
3705
    }
3706
3707
    /**
3708
     * Convert a string to snake_case.
3709
     *
3710
     * EXAMPLE: <code>
3711
     * s('foo1 Bar')->snakeize(); // 'foo_1_bar'
3712
     * </code>
3713
     *
3714
     * @psalm-mutation-free
3715
     *
3716
     * @return static
3717
     *                <p>Object with $str in snake_case.</p>
3718
     */
3719 40
    public function snakeize(): self
3720
    {
3721 40
        return static::create(
3722 40
            $this->utf8::str_snakeize($this->str, $this->encoding),
3723 40
            $this->encoding
3724
        );
3725
    }
3726
3727
    /**
3728
     * Wrap the string after the first whitespace character after a given number
3729
     * of characters.
3730
     *
3731
     * EXAMPLE: <code>
3732
     * </code>
3733
     *
3734
     * @param int    $width <p>Number of characters at which to wrap.</p>
3735
     * @param string $break [optional] <p>Character used to break the string. | Default "\n"</p>
3736
     *
3737
     * @psalm-mutation-free
3738
     *
3739
     * @return static
3740
     */
3741 2
    public function softWrap(int $width, string $break = "\n"): self
3742
    {
3743 2
        return $this->lineWrapAfterWord($width, $break, false);
3744
    }
3745
3746
    /**
3747
     * Splits the string with the provided regular expression, returning an
3748
     * array of Stringy objects. An optional integer $limit will truncate the
3749
     * results.
3750
     *
3751
     * EXAMPLE: <code>
3752
     * s('foo,bar,baz')->split(',', 2); // ['foo', 'bar']
3753
     * </code>
3754
     *
3755
     * @param string $pattern <p>The regex with which to split the string.</p>
3756
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no
3757
     *                        limit</p>
3758
     *
3759
     * @psalm-mutation-free
3760
     *
3761
     * @return static[]
3762
     *                  <p>An array of Stringy objects.</p>
3763
     *
3764
     * @psalm-return array<int,static>
3765
     */
3766 51
    public function split(string $pattern, int $limit = null): array
3767
    {
3768 51
        if ($this->str === '') {
3769
            return [];
3770
        }
3771
3772 51
        if ($limit === null) {
3773 7
            $limit = -1;
3774
        }
3775
3776 51
        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
3777
        /** @noinspection AlterInForeachInspection */
3778 51
        foreach ($array as $i => &$value) {
3779 45
            $value = static::create($value, $this->encoding);
3780
        }
3781
3782
        /** @noinspection PhpSillyAssignmentInspection */
3783
        /** @var static[] $array */
3784 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...
3785
3786 51
        return $array;
3787
    }
3788
3789
    /**
3790
     * Splits the string with the provided regular expression, returning an
3791
     * collection of Stringy objects. An optional integer $limit will truncate the
3792
     * results.
3793
     *
3794
     * EXAMPLE: <code>
3795
     * </code>
3796
     *
3797
     * @param string $pattern <p>The regex with which to split the string.</p>
3798
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no
3799
     *                        limit</p>
3800
     *
3801
     * @psalm-mutation-free
3802
     *
3803
     * @return CollectionStringy|static[]
3804
     *                                    <p>An collection of Stringy objects.</p>
3805
     *
3806
     * @psalm-return CollectionStringy<int,static>
3807
     */
3808 35
    public function splitCollection(string $pattern, int $limit = null): CollectionStringy
3809
    {
3810
        /**
3811
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
3812
         */
3813 35
        return CollectionStringy::create(
3814 35
            $this->split($pattern, $limit)
3815
        );
3816
    }
3817
3818
    /**
3819
     * Returns true if the string begins with $substring, false otherwise. By
3820
     * default, the comparison is case-sensitive, but can be made insensitive
3821
     * by setting $caseSensitive to false.
3822
     *
3823
     * EXAMPLE: <code>
3824
     * s('FÒÔbàřbaz')->startsWith('fòôbàř', false); // true
3825
     * </code>
3826
     *
3827
     * @param string $substring     <p>The substring to look for.</p>
3828
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3829
     *
3830
     * @psalm-mutation-free
3831
     *
3832
     * @return bool
3833
     *              <p>Whether or not $str starts with $substring.</p>
3834
     */
3835 99
    public function startsWith(string $substring, bool $caseSensitive = true): bool
3836
    {
3837 99
        if ($caseSensitive) {
3838 53
            return $this->utf8::str_starts_with($this->str, $substring);
3839
        }
3840
3841 46
        return $this->utf8::str_istarts_with($this->str, $substring);
3842
    }
3843
3844
    /**
3845
     * Returns true if the string begins with any of $substrings, false otherwise.
3846
     * By default the comparison is case-sensitive, but can be made insensitive by
3847
     * setting $caseSensitive to false.
3848
     *
3849
     * EXAMPLE: <code>
3850
     * s('FÒÔbàřbaz')->startsWithAny(['fòô', 'bàř'], false); // true
3851
     * </code>
3852
     *
3853
     * @param string[] $substrings    <p>Substrings to look for.</p>
3854
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
3855
     *
3856
     * @psalm-mutation-free
3857
     *
3858
     * @return bool
3859
     *              <p>Whether or not $str starts with $substring.</p>
3860
     */
3861 35
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
3862
    {
3863 35
        if ($caseSensitive) {
3864 23
            return $this->utf8::str_starts_with_any($this->str, $substrings);
3865
        }
3866
3867 12
        return $this->utf8::str_istarts_with_any($this->str, $substrings);
3868
    }
3869
3870
    /**
3871
     * Remove one or more strings from the string.
3872
     *
3873
     * EXAMPLE: <code>
3874
     * </code>
3875
     *
3876
     * @param string|string[] $search One or more strings to be removed
3877
     *
3878
     * @psalm-mutation-free
3879
     *
3880
     * @return static
3881
     */
3882 3
    public function strip($search): self
3883
    {
3884 3
        if (\is_array($search)) {
3885 1
            return $this->replaceAll($search, '');
3886
        }
3887
3888 2
        return $this->replace($search, '');
3889
    }
3890
3891
    /**
3892
     * Strip all whitespace characters. This includes tabs and newline characters,
3893
     * as well as multibyte whitespace such as the thin space and ideographic space.
3894
     *
3895
     * EXAMPLE: <code>
3896
     * s('   Ο     συγγραφέας  ')->stripWhitespace(); // 'Οσυγγραφέας'
3897
     * </code>
3898
     *
3899
     * @psalm-mutation-free
3900
     *
3901
     * @return static
3902
     */
3903 36
    public function stripWhitespace(): self
3904
    {
3905 36
        return static::create(
3906 36
            $this->utf8::strip_whitespace($this->str),
3907 36
            $this->encoding
3908
        );
3909
    }
3910
3911
    /**
3912
     * Remove css media-queries.
3913
     *
3914
     * EXAMPLE: <code>
3915
     * s('test @media (min-width:660px){ .des-cla #mv-tiles{width:480px} } test ')->stripeCssMediaQueries(); // 'test  test '
3916
     * </code>
3917
     *
3918
     * @psalm-mutation-free
3919
     *
3920
     * @return static
3921
     */
3922 2
    public function stripeCssMediaQueries(): self
3923
    {
3924 2
        return static::create(
3925 2
            $this->utf8::css_stripe_media_queries($this->str),
3926 2
            $this->encoding
3927
        );
3928
    }
3929
3930
    /**
3931
     * Remove empty html-tag.
3932
     *
3933
     * EXAMPLE: <code>
3934
     * s('foo<h1></h1>bar')->stripeEmptyHtmlTags(); // 'foobar'
3935
     * </code>
3936
     *
3937
     * @psalm-mutation-free
3938
     *
3939
     * @return static
3940
     */
3941 2
    public function stripeEmptyHtmlTags(): self
3942
    {
3943 2
        return static::create(
3944 2
            $this->utf8::html_stripe_empty_tags($this->str),
3945 2
            $this->encoding
3946
        );
3947
    }
3948
3949
    /**
3950
     * Convert the string to StudlyCase.
3951
     *
3952
     * EXAMPLE: <code>
3953
     * </code>
3954
     *
3955
     * @psalm-mutation-free
3956
     *
3957
     * @return static
3958
     */
3959 6
    public function studlyCase(): self
3960
    {
3961 6
        $words = \array_map(
3962
            static function (self $word) {
3963 6
                return $word->substr(0, 1)
3964 6
                    ->toUpperCase()
3965 6
                    ->appendStringy($word->substr(1));
3966 6
            },
3967 6
            $this->words('', true)
3968
        );
3969
3970 6
        return new static(\implode('', $words), $this->encoding);
3971
    }
3972
3973
    /**
3974
     * Returns the substring beginning at $start with the specified $length.
3975
     * It differs from the $this->utf8::substr() function in that providing a $length of
3976
     * null will return the rest of the string, rather than an empty string.
3977
     *
3978
     * EXAMPLE: <code>
3979
     * </code>
3980
     *
3981
     * @param int $start  <p>Position of the first character to use.</p>
3982
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
3983
     *
3984
     * @psalm-mutation-free
3985
     *
3986
     * @return static
3987
     *                <p>Object with its $str being the substring.</p>
3988
     */
3989 40
    public function substr(int $start, int $length = null): self
3990
    {
3991 40
        return static::create(
3992 40
            $this->utf8::substr(
3993 40
                $this->str,
3994 40
                $start,
3995 40
                $length,
3996 40
                $this->encoding
3997
            ),
3998 40
            $this->encoding
3999
        );
4000
    }
4001
4002
    /**
4003
     * Return part of the string.
4004
     * Alias for substr()
4005
     *
4006
     * EXAMPLE: <code>
4007
     * s('fòôbàř')->substring(2, 3); // 'ôbà'
4008
     * </code>
4009
     *
4010
     * @param int $start  <p>Starting position of the substring.</p>
4011
     * @param int $length [optional] <p>Length of substring.</p>
4012
     *
4013
     * @psalm-mutation-free
4014
     *
4015
     * @return static
4016
     */
4017 3
    public function substring(int $start, int $length = null): self
4018
    {
4019 3
        if ($length === null) {
4020 2
            return $this->substr($start);
4021
        }
4022
4023 3
        return $this->substr($start, $length);
4024
    }
4025
4026
    /**
4027
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
4028
     * If no match is found returns new empty Stringy object.
4029
     *
4030
     * EXAMPLE: <code>
4031
     * </code>
4032
     *
4033
     * @param string $needle       <p>The string to look for.</p>
4034
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
4035
     *
4036
     * @psalm-mutation-free
4037
     *
4038
     * @return static
4039
     */
4040 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...
4041
    {
4042 4
        return static::create(
4043 4
            $this->utf8::str_substr_first(
4044 4
                $this->str,
4045 4
                $needle,
4046 4
                $beforeNeedle,
4047 4
                $this->encoding
4048
            ),
4049 4
            $this->encoding
4050
        );
4051
    }
4052
4053
    /**
4054
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
4055
     * If no match is found returns new empty Stringy object.
4056
     *
4057
     * EXAMPLE: <code>
4058
     * </code>
4059
     *
4060
     * @param string $needle       <p>The string to look for.</p>
4061
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
4062
     *
4063
     * @psalm-mutation-free
4064
     *
4065
     * @return static
4066
     */
4067 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...
4068
    {
4069 4
        return static::create(
4070 4
            $this->utf8::str_isubstr_first(
4071 4
                $this->str,
4072 4
                $needle,
4073 4
                $beforeNeedle,
4074 4
                $this->encoding
4075
            ),
4076 4
            $this->encoding
4077
        );
4078
    }
4079
4080
    /**
4081
     * Surrounds $str with the given substring.
4082
     *
4083
     * EXAMPLE: <code>
4084
     * s(' ͜ ')->surround('ʘ'); // 'ʘ ͜ ʘ'
4085
     * </code>
4086
     *
4087
     * @param string $substring <p>The substring to add to both sides.</P>
4088
     *
4089
     * @psalm-mutation-free
4090
     *
4091
     * @return static
4092
     *                <p>Object whose $str had the substring both prepended and appended.</p>
4093
     */
4094 15
    public function surround(string $substring): self
4095
    {
4096 15
        return static::create(
4097 15
            $substring . $this->str . $substring,
4098 15
            $this->encoding
4099
        );
4100
    }
4101
4102
    /**
4103
     * Returns a case swapped version of the string.
4104
     *
4105
     * EXAMPLE: <code>
4106
     * s('Ντανιλ')->swapCase(); // 'νΤΑΝΙΛ'
4107
     * </code>
4108
     *
4109
     * @psalm-mutation-free
4110
     *
4111
     * @return static
4112
     *                <p>Object whose $str has each character's case swapped.</P>
4113
     */
4114 15
    public function swapCase(): self
4115
    {
4116 15
        return static::create(
4117 15
            $this->utf8::swapCase($this->str, $this->encoding),
4118 15
            $this->encoding
4119
        );
4120
    }
4121
4122
    /**
4123
     * Returns a string with smart quotes, ellipsis characters, and dashes from
4124
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
4125
     * equivalents.
4126
     *
4127
     * EXAMPLE: <code>
4128
     * s('“I see…”')->tidy(); // '"I see..."'
4129
     * </code>
4130
     *
4131
     * @psalm-mutation-free
4132
     *
4133
     * @return static
4134
     *                <p>Object whose $str has those characters removed.</p>
4135
     */
4136 12
    public function tidy(): self
4137
    {
4138 12
        return static::create(
4139 12
            $this->ascii::normalize_msword($this->str),
4140 12
            $this->encoding
4141
        );
4142
    }
4143
4144
    /**
4145
     * Returns a trimmed string with the first letter of each word capitalized.
4146
     * Also accepts an array, $ignore, allowing you to list words not to be
4147
     * capitalized.
4148
     *
4149
     * EXAMPLE: <code>
4150
     * $ignore = ['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the'];
4151
     * s('i like to watch television')->titleize($ignore); // 'I Like to Watch Television'
4152
     * </code>
4153
     *
4154
     * @param array|string[]|null $ignore            [optional] <p>An array of words not to capitalize or null.
4155
     *                                               Default: null</p>
4156
     * @param string|null         $word_define_chars [optional] <p>An string of chars that will be used as whitespace
4157
     *                                               separator === words.</p>
4158
     * @param string|null         $language          [optional] <p>Language of the source string.</p>
4159
     *
4160
     * @psalm-mutation-free
4161
     *
4162
     * @return static
4163
     *                <p>Object with a titleized $str.</p>
4164
     */
4165 23
    public function titleize(
4166
        array $ignore = null,
4167
        string $word_define_chars = null,
4168
        string $language = null
4169
    ): self {
4170 23
        return static::create(
4171 23
            $this->utf8::str_titleize(
4172 23
                $this->str,
4173 23
                $ignore,
4174 23
                $this->encoding,
4175 23
                false,
4176 23
                $language,
4177 23
                false,
4178 23
                true,
4179 23
                $word_define_chars
4180
            ),
4181 23
            $this->encoding
4182
        );
4183
    }
4184
4185
    /**
4186
     * Returns a trimmed string in proper title case: Also accepts an array, $ignore, allowing you to list words not to be
4187
     * capitalized.
4188
     *
4189
     * EXAMPLE: <code>
4190
     * </code>
4191
     *
4192
     * Adapted from John Gruber's script.
4193
     *
4194
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
4195
     *
4196
     * @param string[] $ignore <p>An array of words not to capitalize.</p>
4197
     *
4198
     * @psalm-mutation-free
4199
     *
4200
     * @return static
4201
     *                <p>Object with a titleized $str</p>
4202
     */
4203 70
    public function titleizeForHumans(array $ignore = []): self
4204
    {
4205 70
        return static::create(
4206 70
            $this->utf8::str_titleize_for_humans(
4207 70
                $this->str,
4208 70
                $ignore,
4209 70
                $this->encoding
4210
            ),
4211 70
            $this->encoding
4212
        );
4213
    }
4214
4215
    /**
4216
     * Returns an ASCII version of the string. A set of non-ASCII characters are
4217
     * replaced with their closest ASCII counterparts, and the rest are removed
4218
     * by default. The language or locale of the source string can be supplied
4219
     * for language-specific transliteration in any of the following formats:
4220
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
4221
     * to "aeoeue" rather than "aou" as in other languages.
4222
     *
4223
     * EXAMPLE: <code>
4224
     * s('fòôbàř')->toAscii(); // 'foobar'
4225
     * </code>
4226
     *
4227
     * @param string $language          [optional] <p>Language of the source string.</p>
4228
     * @param bool   $removeUnsupported [optional] <p>Whether or not to remove the
4229
     *                                  unsupported characters.</p>
4230
     *
4231
     * @psalm-mutation-free
4232
     *
4233
     * @return static
4234
     *                <p>Object whose $str contains only ASCII characters.</p>
4235
     */
4236 23
    public function toAscii(string $language = 'en', bool $removeUnsupported = true): self
4237
    {
4238 23
        return static::create(
4239 23
            $this->ascii::to_ascii(
4240 23
                $this->str,
4241 23
                $language,
4242 23
                $removeUnsupported
4243
            ),
4244 23
            $this->encoding
4245
        );
4246
    }
4247
4248
    /**
4249
     * Returns a boolean representation of the given logical string value.
4250
     * For example, <strong>'true', '1', 'on' and 'yes'</strong> will return true. <strong>'false', '0',
4251
     * 'off', and 'no'</strong> will return false. In all instances, case is ignored.
4252
     * For other numeric strings, their sign will determine the return value.
4253
     * In addition, blank strings consisting of only whitespace will return
4254
     * false. For all other strings, the return value is a result of a
4255
     * boolean cast.
4256
     *
4257
     * EXAMPLE: <code>
4258
     * s('OFF')->toBoolean(); // false
4259
     * </code>
4260
     *
4261
     * @psalm-mutation-free
4262
     *
4263
     * @return bool
4264
     *              <p>A boolean value for the string.</p>
4265
     */
4266 45
    public function toBoolean(): bool
4267
    {
4268
        /**
4269
         * @psalm-suppress ArgumentTypeCoercion -> maybe the string looks like an int ;)
4270
         */
4271 45
        return $this->utf8::to_boolean($this->str);
4272
    }
4273
4274
    /**
4275
     * Converts all characters in the string to lowercase.
4276
     *
4277
     * EXAMPLE: <code>
4278
     * s('FÒÔBÀŘ')->toLowerCase(); // 'fòôbàř'
4279
     * </code>
4280
     *
4281
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
4282
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
4283
     *
4284
     * @psalm-mutation-free
4285
     *
4286
     * @return static
4287
     *                <p>Object with all characters of $str being lowercase.</p>
4288
     */
4289 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...
4290
    {
4291 23
        return static::create(
4292 23
            $this->utf8::strtolower(
4293 23
                $this->str,
4294 23
                $this->encoding,
4295 23
                false,
4296 23
                $lang,
4297 23
                $tryToKeepStringLength
4298
            ),
4299 23
            $this->encoding
4300
        );
4301
    }
4302
4303
    /**
4304
     * Converts each tab in the string to some number of spaces, as defined by
4305
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
4306
     *
4307
     * EXAMPLE: <code>
4308
     * s(' String speech = "Hi"')->toSpaces(); // '    String speech = "Hi"'
4309
     * </code>
4310
     *
4311
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
4312
     *
4313
     * @psalm-mutation-free
4314
     *
4315
     * @return static
4316
     *                <p>Object whose $str has had tabs switched to spaces.</p>
4317
     */
4318 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...
4319
    {
4320 18
        if ($tabLength === 4) {
4321 9
            $tab = '    ';
4322 9
        } elseif ($tabLength === 2) {
4323 3
            $tab = '  ';
4324
        } else {
4325 6
            $tab = \str_repeat(' ', $tabLength);
4326
        }
4327
4328 18
        return static::create(
4329 18
            \str_replace("\t", $tab, $this->str),
4330 18
            $this->encoding
4331
        );
4332
    }
4333
4334
    /**
4335
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
4336
     * string.
4337
     *
4338
     * EXAMPLE: <code>
4339
     * s('fòôbàř')->toString(); // 'fòôbàř'
4340
     * </code>
4341
     *
4342
     * @psalm-mutation-free
4343
     *
4344
     * @return string
4345
     */
4346 2200
    public function toString(): string
4347
    {
4348 2200
        return (string) $this->str;
4349
    }
4350
4351
    /**
4352
     * Converts each occurrence of some consecutive number of spaces, as
4353
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
4354
     * are converted to a tab.
4355
     *
4356
     * EXAMPLE: <code>
4357
     * s('    fòô    bàř')->toTabs(); // '   fòô bàř'
4358
     * </code>
4359
     *
4360
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
4361
     *
4362
     * @psalm-mutation-free
4363
     *
4364
     * @return static
4365
     *                <p>Object whose $str has had spaces switched to tabs.</p>
4366
     */
4367 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...
4368
    {
4369 15
        if ($tabLength === 4) {
4370 9
            $tab = '    ';
4371 6
        } elseif ($tabLength === 2) {
4372 3
            $tab = '  ';
4373
        } else {
4374 3
            $tab = \str_repeat(' ', $tabLength);
4375
        }
4376
4377 15
        return static::create(
4378 15
            \str_replace($tab, "\t", $this->str),
4379 15
            $this->encoding
4380
        );
4381
    }
4382
4383
    /**
4384
     * Converts the first character of each word in the string to uppercase
4385
     * and all other chars to lowercase.
4386
     *
4387
     * EXAMPLE: <code>
4388
     * s('fòô bàř')->toTitleCase(); // 'Fòô Bàř'
4389
     * </code>
4390
     *
4391
     * @psalm-mutation-free
4392
     *
4393
     * @return static
4394
     *                <p>Object with all characters of $str being title-cased.</p>
4395
     */
4396 15
    public function toTitleCase(): self
4397
    {
4398 15
        return static::create(
4399 15
            $this->utf8::titlecase($this->str, $this->encoding),
4400 15
            $this->encoding
4401
        );
4402
    }
4403
4404
    /**
4405
     * Returns an ASCII version of the string. A set of non-ASCII characters are
4406
     * replaced with their closest ASCII counterparts, and the rest are removed
4407
     * unless instructed otherwise.
4408
     *
4409
     * EXAMPLE: <code>
4410
     * </code>
4411
     *
4412
     * @param bool   $strict  [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad
4413
     *                        performance | Default: false</p>
4414
     * @param string $unknown [optional] <p>Character use if character unknown. (default is ?)</p>
4415
     *
4416
     * @psalm-mutation-free
4417
     *
4418
     * @return static
4419
     *                <p>Object whose $str contains only ASCII characters.</p>
4420
     */
4421 34
    public function toTransliterate(bool $strict = false, string $unknown = '?'): self
4422
    {
4423 34
        return static::create(
4424 34
            $this->ascii::to_transliterate($this->str, $unknown, $strict),
4425 34
            $this->encoding
4426
        );
4427
    }
4428
4429
    /**
4430
     * Converts all characters in the string to uppercase.
4431
     *
4432
     * EXAMPLE: <code>
4433
     * s('fòôbàř')->toUpperCase(); // 'FÒÔBÀŘ'
4434
     * </code>
4435
     *
4436
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
4437
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
4438
     *
4439
     * @psalm-mutation-free
4440
     *
4441
     * @return static
4442
     *                <p>Object with all characters of $str being uppercase.</p>
4443
     */
4444 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...
4445
    {
4446 26
        return static::create(
4447 26
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
4448 26
            $this->encoding
4449
        );
4450
    }
4451
4452
    /**
4453
     * Returns a string with whitespace removed from the start and end of the
4454
     * string. Supports the removal of unicode whitespace. Accepts an optional
4455
     * string of characters to strip instead of the defaults.
4456
     *
4457
     * EXAMPLE: <code>
4458
     * s('  fòôbàř  ')->trim(); // 'fòôbàř'
4459
     * </code>
4460
     *
4461
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
4462
     *
4463
     * @psalm-mutation-free
4464
     *
4465
     * @return static
4466
     *                <p>Object with a trimmed $str.</p>
4467
     */
4468 36
    public function trim(string $chars = null): self
4469
    {
4470 36
        return static::create(
4471 36
            $this->utf8::trim($this->str, $chars),
4472 36
            $this->encoding
4473
        );
4474
    }
4475
4476
    /**
4477
     * Returns a string with whitespace removed from the start of the string.
4478
     * Supports the removal of unicode whitespace. Accepts an optional
4479
     * string of characters to strip instead of the defaults.
4480
     *
4481
     * EXAMPLE: <code>
4482
     * s('  fòôbàř  ')->trimLeft(); // 'fòôbàř  '
4483
     * </code>
4484
     *
4485
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
4486
     *
4487
     * @psalm-mutation-free
4488
     *
4489
     * @return static
4490
     *                <p>Object with a trimmed $str.</p>
4491
     */
4492 39
    public function trimLeft(string $chars = null): self
4493
    {
4494 39
        return static::create(
4495 39
            $this->utf8::ltrim($this->str, $chars),
4496 39
            $this->encoding
4497
        );
4498
    }
4499
4500
    /**
4501
     * Returns a string with whitespace removed from the end of the string.
4502
     * Supports the removal of unicode whitespace. Accepts an optional
4503
     * string of characters to strip instead of the defaults.
4504
     *
4505
     * EXAMPLE: <code>
4506
     * s('  fòôbàř  ')->trimRight(); // '  fòôbàř'
4507
     * </code>
4508
     *
4509
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
4510
     *
4511
     * @psalm-mutation-free
4512
     *
4513
     * @return static
4514
     *                <p>Object with a trimmed $str.</p>
4515
     */
4516 39
    public function trimRight(string $chars = null): self
4517
    {
4518 39
        return static::create(
4519 39
            $this->utf8::rtrim($this->str, $chars),
4520 39
            $this->encoding
4521
        );
4522
    }
4523
4524
    /**
4525
     * Truncates the string to a given length. If $substring is provided, and
4526
     * truncating occurs, the string is further truncated so that the substring
4527
     * may be appended without exceeding the desired length.
4528
     *
4529
     * EXAMPLE: <code>
4530
     * s('What are your plans today?')->truncate(19, '...'); // 'What are your pl...'
4531
     * </code>
4532
     *
4533
     * @param int    $length    <p>Desired length of the truncated string.</p>
4534
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
4535
     *
4536
     * @psalm-mutation-free
4537
     *
4538
     * @return static
4539
     *                <p>Object with the resulting $str after truncating.</p>
4540
     */
4541 66
    public function truncate(int $length, string $substring = ''): self
4542
    {
4543 66
        return static::create(
4544 66
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
4545 66
            $this->encoding
4546
        );
4547
    }
4548
4549
    /**
4550
     * Returns a lowercase and trimmed string separated by underscores.
4551
     * Underscores are inserted before uppercase characters (with the exception
4552
     * of the first character of the string), and in place of spaces as well as
4553
     * dashes.
4554
     *
4555
     * EXAMPLE: <code>
4556
     * s('TestUCase')->underscored(); // 'test_u_case'
4557
     * </code>
4558
     *
4559
     * @psalm-mutation-free
4560
     *
4561
     * @return static
4562
     *                <p>Object with an underscored $str.</p>
4563
     */
4564 48
    public function underscored(): self
4565
    {
4566 48
        return $this->delimit('_');
4567
    }
4568
4569
    /**
4570
     * Returns an UpperCamelCase version of the supplied string. It trims
4571
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
4572
     * and underscores, and removes spaces, dashes, underscores.
4573
     *
4574
     * EXAMPLE: <code>
4575
     * s('Upper Camel-Case')->upperCamelize(); // 'UpperCamelCase'
4576
     * </code>
4577
     *
4578
     * @psalm-mutation-free
4579
     *
4580
     * @return static
4581
     *                <p>Object with $str in UpperCamelCase.</p>
4582
     */
4583 39
    public function upperCamelize(): self
4584
    {
4585 39
        return static::create(
4586 39
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
4587 39
            $this->encoding
4588
        );
4589
    }
4590
4591
    /**
4592
     * Converts the first character of the supplied string to upper case.
4593
     *
4594
     * EXAMPLE: <code>
4595
     * s('σ foo')->upperCaseFirst(); // 'Σ foo'
4596
     * </code>
4597
     *
4598
     * @psalm-mutation-free
4599
     *
4600
     * @return static
4601
     *                <p>Object with the first character of $str being upper case.</p>
4602
     */
4603 18
    public function upperCaseFirst(): self
4604
    {
4605 18
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
4606
    }
4607
4608
    /**
4609
     * Simple url-decoding.
4610
     *
4611
     * e.g:
4612
     * 'test+test' => 'test test'
4613
     *
4614
     * EXAMPLE: <code>
4615
     * </code>
4616
     *
4617
     * @psalm-mutation-free
4618
     *
4619
     * @return static
4620
     */
4621 1
    public function urlDecode(): self
4622
    {
4623 1
        return static::create(\urldecode($this->str));
4624
    }
4625
4626
    /**
4627
     * Multi url-decoding + decode HTML entity + fix urlencoded-win1252-chars.
4628
     *
4629
     * e.g:
4630
     * 'test+test'                     => 'test test'
4631
     * 'D&#252;sseldorf'               => 'Düsseldorf'
4632
     * 'D%FCsseldorf'                  => 'Düsseldorf'
4633
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
4634
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
4635
     * 'Düsseldorf'                   => 'Düsseldorf'
4636
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
4637
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
4638
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
4639
     *
4640
     * EXAMPLE: <code>
4641
     * </code>
4642
     *
4643
     * @psalm-mutation-free
4644
     *
4645
     * @return static
4646
     */
4647 1
    public function urlDecodeMulti(): self
4648
    {
4649 1
        return static::create($this->utf8::urldecode($this->str));
4650
    }
4651
4652
    /**
4653
     * Simple url-decoding.
4654
     *
4655
     * e.g:
4656
     * 'test+test' => 'test+test
4657
     *
4658
     * EXAMPLE: <code>
4659
     * </code>
4660
     *
4661
     * @psalm-mutation-free
4662
     *
4663
     * @return static
4664
     */
4665 1
    public function urlDecodeRaw(): self
4666
    {
4667 1
        return static::create(\rawurldecode($this->str));
4668
    }
4669
4670
    /**
4671
     * Multi url-decoding + decode HTML entity + fix urlencoded-win1252-chars.
4672
     *
4673
     * e.g:
4674
     * 'test+test'                     => 'test+test'
4675
     * 'D&#252;sseldorf'               => 'Düsseldorf'
4676
     * 'D%FCsseldorf'                  => 'Düsseldorf'
4677
     * 'D&#xFC;sseldorf'               => 'Düsseldorf'
4678
     * 'D%26%23xFC%3Bsseldorf'         => 'Düsseldorf'
4679
     * 'Düsseldorf'                   => 'Düsseldorf'
4680
     * 'D%C3%BCsseldorf'               => 'Düsseldorf'
4681
     * 'D%C3%83%C2%BCsseldorf'         => 'Düsseldorf'
4682
     * 'D%25C3%2583%25C2%25BCsseldorf' => 'Düsseldorf'
4683
     *
4684
     * EXAMPLE: <code>
4685
     * </code>
4686
     *
4687
     * @psalm-mutation-free
4688
     *
4689
     * @return static
4690
     */
4691 1
    public function urlDecodeRawMulti(): self
4692
    {
4693 1
        return static::create($this->utf8::rawurldecode($this->str));
4694
    }
4695
4696
    /**
4697
     * Simple url-encoding.
4698
     *
4699
     * e.g:
4700
     * 'test test' => 'test+test'
4701
     *
4702
     * EXAMPLE: <code>
4703
     * </code>
4704
     *
4705
     * @psalm-mutation-free
4706
     *
4707
     * @return static
4708
     */
4709 1
    public function urlEncode(): self
4710
    {
4711 1
        return static::create(\urlencode($this->str));
4712
    }
4713
4714
    /**
4715
     * Simple url-encoding.
4716
     *
4717
     * e.g:
4718
     * 'test test' => 'test%20test'
4719
     *
4720
     * EXAMPLE: <code>
4721
     * </code>
4722
     *
4723
     * @psalm-mutation-free
4724
     *
4725
     * @return static
4726
     */
4727 1
    public function urlEncodeRaw(): self
4728
    {
4729 1
        return static::create(\rawurlencode($this->str));
4730
    }
4731
4732
    /**
4733
     * Converts the string into an URL slug. This includes replacing non-ASCII
4734
     * characters with their closest ASCII equivalents, removing remaining
4735
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
4736
     * $separator. The separator defaults to a single dash, and the string
4737
     * is also converted to lowercase.
4738
     *
4739
     * EXAMPLE: <code>
4740
     * s('Using strings like fòô bàř - 1$')->urlify(); // 'using-strings-like-foo-bar-1-dollar'
4741
     * </code>
4742
     *
4743
     * @param string                $separator    [optional] <p>The string used to replace whitespace. Default: '-'</p>
4744
     * @param string                $language     [optional] <p>The language for the url. Default: 'en'</p>
4745
     * @param array<string, string> $replacements [optional] <p>A map of replaceable strings.</p>
4746
     * @param bool                  $strToLower   [optional] <p>string to lower. Default: true</p>
4747
     *
4748
     * @psalm-mutation-free
4749
     *
4750
     * @return static
4751
     *                <p>Object whose $str has been converted to an URL slug.</p>
4752
     *
4753
     * @psalm-suppress ImpureMethodCall :/
4754
     */
4755 32
    public function urlify(
4756
        string $separator = '-',
4757
        string $language = 'en',
4758
        array $replacements = [],
4759
        bool $strToLower = true
4760
    ): self {
4761
        // init
4762 32
        $str = $this->str;
4763
4764 32
        foreach ($replacements as $from => $to) {
4765 32
            $str = \str_replace($from, $to, $str);
4766
        }
4767
4768 32
        return static::create(
4769 32
            URLify::slug(
4770 32
                $str,
4771 32
                $language,
4772 32
                $separator,
4773 32
                $strToLower
4774
            ),
4775 32
            $this->encoding
4776
        );
4777
    }
4778
4779
    /**
4780
     * Converts the string into an valid UTF-8 string.
4781
     *
4782
     * EXAMPLE: <code>
4783
     * s('Düsseldorf')->utf8ify(); // 'Düsseldorf'
4784
     * </code>
4785
     *
4786
     * @psalm-mutation-free
4787
     *
4788
     * @return static
4789
     */
4790 2
    public function utf8ify(): self
4791
    {
4792 2
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
4793
    }
4794
4795
    /**
4796
     * Convert a string into an array of words.
4797
     *
4798
     * EXAMPLE: <code>
4799
     * </code>
4800
     *
4801
     * @param string   $char_list           [optional] <p>Additional chars for the definition of "words".</p>
4802
     * @param bool     $remove_empty_values [optional] <p>Remove empty values.</p>
4803
     * @param int|null $remove_short_values [optional] <p>The min. string length or null to disable</p>
4804
     *
4805
     * @psalm-mutation-free
4806
     *
4807
     * @return static[]
4808
     *
4809
     * @psalm-return array<int,static>
4810
     */
4811 14
    public function words(
4812
        string $char_list = '',
4813
        bool $remove_empty_values = false,
4814
        int $remove_short_values = null
4815
    ): array {
4816 14
        if ($remove_short_values === null) {
4817 14
            $strings = $this->utf8::str_to_words(
4818 14
                $this->str,
4819 14
                $char_list,
4820 14
                $remove_empty_values
4821
            );
4822
        } else {
4823 2
            $strings = $this->utf8::str_to_words(
4824 2
                $this->str,
4825 2
                $char_list,
4826 2
                $remove_empty_values,
4827 2
                $remove_short_values
4828
            );
4829
        }
4830
4831
        /** @noinspection AlterInForeachInspection */
4832 14
        foreach ($strings as &$string) {
4833 14
            $string = static::create($string);
4834
        }
4835
4836
        /** @noinspection PhpSillyAssignmentInspection */
4837
        /** @var static[] $strings */
4838 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...
4839
4840 14
        return $strings;
4841
    }
4842
4843
    /**
4844
     * Convert a string into an collection of words.
4845
     *
4846
     * EXAMPLE: <code>
4847
     * S::create('中文空白 oöäü#s')->wordsCollection('#', true)->toStrings(); // ['中文空白', 'oöäü#s']
4848
     * </code>
4849
     *
4850
     * @param string   $char_list           [optional] <p>Additional chars for the definition of "words".</p>
4851
     * @param bool     $remove_empty_values [optional] <p>Remove empty values.</p>
4852
     * @param int|null $remove_short_values [optional] <p>The min. string length or null to disable</p>
4853
     *
4854
     * @psalm-mutation-free
4855
     *
4856
     * @return CollectionStringy|static[]
4857
     *                                    <p>An collection of Stringy objects.</p>
4858
     *
4859
     * @psalm-return CollectionStringy<int,static>
4860
     */
4861 2
    public function wordsCollection(
4862
        string $char_list = '',
4863
        bool $remove_empty_values = false,
4864
        int $remove_short_values = null
4865
    ): CollectionStringy {
4866
        /**
4867
         * @psalm-suppress ImpureMethodCall -> add more psalm stuff to the collection class
4868
         */
4869 2
        return CollectionStringy::create(
4870 2
            $this->words(
4871 2
                $char_list,
4872 2
                $remove_empty_values,
4873 2
                $remove_short_values
4874
            )
4875
        );
4876
    }
4877
4878
    /**
4879
     * Surrounds $str with the given substring.
4880
     *
4881
     * EXAMPLE: <code>
4882
     * </code>
4883
     *
4884
     * @param string $substring <p>The substring to add to both sides.</P>
4885
     *
4886
     * @psalm-mutation-free
4887
     *
4888
     * @return static
4889
     *                <p>Object whose $str had the substring both prepended and appended.</p>
4890
     */
4891 10
    public function wrap(string $substring): self
4892
    {
4893 10
        return $this->surround($substring);
4894
    }
4895
4896
    /**
4897
     * Returns the replacements for the toAscii() method.
4898
     *
4899
     * @noinspection PhpUnused
4900
     *
4901
     * @psalm-mutation-free
4902
     *
4903
     * @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...
4904
     *                       <p>An array of replacements.</p>
4905
     *
4906
     * @deprecated   this is only here for backward-compatibly reasons
4907
     */
4908 1
    protected function charsArray(): array
4909
    {
4910 1
        return $this->ascii::charsArrayWithMultiLanguageValues();
4911
    }
4912
4913
    /**
4914
     * Returns true if $str matches the supplied pattern, false otherwise.
4915
     *
4916
     * @param string $pattern <p>Regex pattern to match against.</p>
4917
     *
4918
     * @psalm-mutation-free
4919
     *
4920
     * @return bool
4921
     *              <p>Whether or not $str matches the pattern.</p>
4922
     */
4923 24
    protected function matchesPattern(string $pattern): bool
4924
    {
4925 24
        return $this->utf8::str_matches_pattern($this->str, $pattern);
4926
    }
4927
}
4928