Fluent string wrapper. Namespace Zero\Lib\Support\Stringable. Build with Str::of($value) or the global str($value) helper.
use Zero\Lib\Support\Str;
Str::of('users.profile-photo')
->replaceLast('.', '/')
->slug('/'); // 'users/profile-photo'
str('Hello {name}')
->swap(['{name}' => 'World'])
->upper(); // 'HELLO WORLD'Stringable::__toString() returns the underlying string, so it casts cleanly: (string) $stringable.
Stringable forwards every static Str::* call automatically: anything that takes a string as its first argument and returns a string is chainable. So all of these work:
str('foo')->upper(); // FOO
str('Hello World')->slug(); // hello-world
str('a/b/c')->after('/'); // 'b/c'
str('foo bar')->replace('foo', 'XX'); // 'XX bar'Methods that return non-strings (->isUuid(), ->length(), ->test(), …) return that value directly.
Implementation: Stringable.php.
(string) str('foo')->append('bar', 'baz'); // 'foobarbaz'
(string) str('bar')->prepend('foo'); // 'foobar'(string) str('a')->newLine(2); // "a\n\n"(string) str('/a/b/c.txt')->basename(); // 'c.txt'
(string) str('/a/b/c.txt')->basename('.txt'); // 'c'(string) str('/a/b/c.txt')->dirname(); // '/a/b'
(string) str('/a/b/c.txt')->dirname(2); // '/a'Last segment of a fully qualified class name.
(string) str('Foo\\Bar\\Baz')->classBasename(); // 'Baz'(string) str('<b>x</b>')->stripTags(); // 'x'
(string) str('<b>x</b><i>y</i>')->stripTags('<b>'); // '<b>x</b>y'(string) str('x')->hash(); // 64-char SHA-256
(string) str('x')->hash('md5'); // '9dd4e461268c8034f5c8564e155c67a6'str('hello')->exactly('hello'); // truestr('')->isEmpty(); // true
str('x')->isNotEmpty(); // truestr('hello')->test('/^h/'); // truestr('a,b,c')->explode(','); // ['a', 'b', 'c']Regex split.
str('a1b2c')->split('/\d/'); // ['a', 'b', 'c']sscanf shortcut.
str('SN/2020/01')->scan('SN/%d/%d'); // [2020, 1]These run $cb only when the predicate matches; otherwise $default (if given). Each returns the (possibly modified) Stringable.
$cond may be a callable, in which case its return value is checked.
(string) str('foo')->when(true, fn ($s) => $s->upper()); // 'FOO'
(string) str('foo')->when(false, fn ($s) => $s->upper()); // 'foo'
(string) str('foo')->unless(false, fn ($s) => $s->upper()); // 'FOO'(string) str('')->whenEmpty(fn ($s) => $s->append('x')); // 'x'
(string) str('x')->whenNotEmpty(fn ($s) => $s->append('y')); // 'xy'(string) str('hello')->whenContains('ell', fn ($s) => $s->upper()); // 'HELLO'(string) str('hello')->whenStartsWith('he', fn ($s) => $s->upper()); // 'HELLO'
(string) str('hello')->whenEndsWith('lo', fn ($s) => $s->upper()); // 'HELLO'(string) str('foo')->whenExactly('foo', fn ($s) => $s->upper()); // 'FOO'Wildcard match (Str::is).
(string) str('foobar')->whenIs('foo*', fn ($s) => $s->upper()); // 'FOOBAR'(string) str('hi')->whenIsAscii(fn ($s) => $s->upper()); // 'HI'(string) str('hi5')->whenTest('/\d/', fn ($s) => $s->upper()); // 'HI5'Send through a closure (return whatever you want).
str('queue')->pipe(fn ($s) => (string) $s . ':default'); // 'queue:default'Side effect; returns the Stringable.
(string) str('foo')->tap(fn ($s) => logger($s)); // 'foo'