Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 95 additions & 2 deletions src/Str.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static function camel(?string $subject): string
*
* @param ?string $subject
* @param string $start
* @param bool $caseSensitive
* @param bool $caseSensitive
*
* @return bool
*/
Expand All @@ -46,6 +46,84 @@ public static function startsWith(?string $subject, string $start, bool $caseSen
return str_starts_with($subject, $start);
}

/**
* Check if the given string ends with the specified substring
*
* @param ?string $subject
* @param string $end
* @param bool $caseSensitive
*
* @return bool
*/
public static function endsWith(?string $subject, string $end, bool $caseSensitive = true): bool
{
$subject ??= '';
if (! $caseSensitive) {
return strncasecmp($subject, $end, strlen($end)) === 0;
}

return str_ends_with($subject, $end);
}

/**
* Check if the given string contains the specified substring
*
* @param ?string $subject
* @param string $needle
* @param bool $caseSensitive
*
* @return bool
*/
public static function contains(?string $subject, string $needle, bool $caseSensitive = true): bool
{
$subject ??= '';
if (! $caseSensitive) {
return str_contains(strtolower($subject), strtolower($needle));
}

return str_contains($subject, $needle);
}

/**
* Check if the given string contains any of the specified substrings
*
* @param ?string $haystack
* @param string[] $needles
* @param bool $caseSensitive
*
* @return bool
*/
public static function containsAny(?string $haystack, array $needles, bool $caseSensitive = true): bool
{
foreach ($needles as $needle) {
if (self::contains($haystack, $needle, $caseSensitive)) {
return true;
}
}

return false;
}

/**
* Check if the given string contains all the specified substrings
*
* @param ?string $haystack
* @param string[] $needles
* @param bool $caseSensitive
*
* @return bool
*/
public static function containsAll(?string $haystack, array $needles, bool $caseSensitive = true): bool
{
foreach ($needles as $needle) {
if (! self::contains($haystack, $needle, $caseSensitive)) {
return false;
}
}

return true;
}

/**
* Split string into an array padded to the size specified by limit
*
Expand Down Expand Up @@ -76,7 +154,7 @@ public static function symmetricSplit(
*
* @param ?string $subject
* @param string $delimiter
* @param ?int $limit
* @param ?int $limit
*
* @return array<string>
*/
Expand All @@ -90,4 +168,19 @@ public static function trimSplit(?string $subject, string $delimiter = ',', ?int

return array_map('trim', $exploded);
}

/**
* Check if the given string is empty
*
* Null is considered empty and strings are trimmed before checking.
*
* @param ?string $subject
* @param string $characters
*
* @return bool
*/
public static function isEmpty(?string $subject, string $characters = " \n\r\t\v\0"): bool
{
return $subject === null || trim($subject, $characters) === '';
}
}
156 changes: 156 additions & 0 deletions tests/StrTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,162 @@ public function testStartsWithReturnsFalseIfStringDoesNotStartWithTheSpecifiedSu
$this->assertFalse(Str::startsWith('FOOBAR', 'foo', true));
}

public function testEndsWithReturnsTrueIfStringEndsWithTheSpecifiedSubstring()
{
$this->assertTrue(Str::endsWith('config.ini', '.ini'));
}

public function testEndsWithReturnsFalseIfStringDoesNotEndWithTheSpecifiedSubstring()
{
$this->assertFalse(Str::endsWith('config.ini', '.php'));
}

public function testEndsWithReturnsTrueIfStringEndsWithTheSpecifiedSubstringAndCaseIsStrict()
{
$this->assertTrue(Str::endsWith('config.INI', '.INI', true));
}

public function testEndsWithReturnsFalseIfStringDoesNotEndWithTheSpecifiedSubstringAndCaseIsStrict()
{
$this->assertFalse(Str::endsWith('config.INI', '.ini', true));
}

public function testContainsReturnsTrueIfStringContainsTheSpecifiedSubstring()
{
$this->assertTrue(Str::contains('MySQL server has gone away', 'server has gone away'));
}

public function testContainsReturnsFalseIfStringDoesNotContainTheSpecifiedSubstring()
{
$this->assertFalse(Str::contains('Query executed successfully', 'server has gone away'));
}

public function testContainsReturnsTrueIfStringContainsTheSpecifiedSubstringAndCaseIsStrict()
{
$this->assertTrue(Str::contains(
'Lost connection to MySQL server during query',
'Lost connection',
true,
));
}

public function testContainsReturnsFalseIfStringDoesNotContainTheSpecifiedSubstringAndCaseIsStrict()
{
$this->assertFalse(Str::contains(
'lost connection to MySQL server during query',
'Lost connection',
true,
));
}

public function testContainsAnyReturnsTrueIfStringContainsOneOfTheSpecifiedSubstrings()
{
$this->assertTrue(Str::containsAny('MySQL server has gone away', [
'server has gone away',
'Lost connection',
'Connection refused',
]));
}

public function testContainsAnyReturnsFalseIfStringContainsNoneOfTheSpecifiedSubstrings()
{
$this->assertFalse(Str::containsAny('Query executed successfully', [
'server has gone away',
'Lost connection',
'Connection refused',
]));
}

public function testContainsAnyReturnsTrueIfStringContainsOneOfTheSpecifiedSubstringsCaseInsensitively()
{
$this->assertTrue(Str::containsAny('LOST CONNECTION to MySQL server', [
'server has gone away',
'Lost connection',
], false));
}

public function testContainsAnyReturnsFalseIfStringContainsNoneOfTheSpecifiedSubstringsAndCaseIsStrict()
{
$this->assertFalse(Str::containsAny('lost connection to MySQL server', [
'server has gone away',
'Lost connection',
], true));
}

public function testContainsAllReturnsTrueIfStringContainsAllSpecifiedSubstrings()
{
$this->assertTrue(Str::containsAll(
'host=db1.example.com;dbname=icingaweb2;charset=utf8',
['host=', 'dbname=', 'charset='],
));
}

public function testContainsAllReturnsFalseIfStringIsMissingOneOfTheSpecifiedSubstrings()
{
$this->assertFalse(Str::containsAll(
'host=db1.example.com;charset=utf8',
['host=', 'dbname=', 'charset='],
));
}

public function testContainsAllReturnsTrueIfStringContainsAllSpecifiedSubstringsCaseInsensitively()
{
$this->assertTrue(Str::containsAll(
'HOST=db1.example.com;DBNAME=icingaweb2',
['host=', 'dbname='],
false,
));
}

public function testContainsAllReturnsFalseIfStringIsMissingOneOfTheSpecifiedSubstringsAndCaseIsStrict()
{
$this->assertFalse(Str::containsAll(
'HOST=db1.example.com;DBNAME=icingaweb2',
['host=', 'dbname='],
true,
));
}

public function testIsEmptyReturnsTrueForNull()
{
$this->assertTrue(Str::isEmpty(null));
}

public function testIsEmptyReturnsTrueForEmptyString()
{
$this->assertTrue(Str::isEmpty(''));
}

public function testIsEmptyReturnsTrueForStringWithLeadingAndTrailingWhitespace()
{
$this->assertTrue(Str::isEmpty(' '));
}

public function testIsEmptyReturnsTrueForStringWithOnlyWhitespace()
{
$this->assertTrue(Str::isEmpty("\t\n"));
}

public function testIsEmptyReturnsFalseForZero()
{
$this->assertFalse(Str::isEmpty('0'));
}

public function testIsEmptyReturnsFalseForNonEmptyString()
{
$this->assertFalse(Str::isEmpty('Warning'));
}

public function testIsEmptyReturnsFalseForStringWithContentAndSurroundingWhitespace()
{
$this->assertFalse(Str::isEmpty(' Warning '));
}

public function testIsEmptyReturnsTrueForStringWithCustomCharacters()
{
$this->assertTrue(Str::isEmpty('---', '-'));
Comment thread
Al2Klimov marked this conversation as resolved.
}

public function testSymmetricSplitReturnsArrayPaddedToTheSizeSpecifiedByLimitUsingNullAsValueByDefault()
{
$this->assertSame(['foo', 'bar', null, null], Str::symmetricSplit('foo,bar', ',', 4));
Expand Down
Loading