Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PHP 8.4 #143

Merged
merged 8 commits into from
Feb 9, 2025
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ jobs:
os: >-
['ubuntu-latest', 'windows-latest']
php: >-
['8.1', '8.2', '8.3']
['8.1', '8.2', '8.3', '8.4']
2 changes: 1 addition & 1 deletion .github/workflows/composer-require-checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.1', '8.2', '8.3']
['8.1', '8.2', '8.3', '8.4']
2 changes: 1 addition & 1 deletion .github/workflows/mutation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.2']
['8.4']
secrets:
STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
2 changes: 1 addition & 1 deletion .github/workflows/rector.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.3']
['8.4']
2 changes: 1 addition & 1 deletion .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.1', '8.2', '8.3']
['8.1', '8.2', '8.3', '8.4']
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Bug #138: Explicitly mark nullable parameters (@ferrumfist)
- Chg #140: Bump minimal required PHP version to 8.1 and minor refactoring (@vjik)
- Chg #143: Change PHP constraint in `composer.json` to `~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0` (@vjik)
- Bug #142: Check string on a valid UTF-8 in `StringHelper` methods: `trim()`, `ltrim()` and `rtrim()` (@vjik)
- Bug #141: `StringHelper::parsePath()` for empty string returns path `['']` instead of `[]` before (@vjik)

Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@
}
],
"require": {
"php": "^8.1",
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"ext-mbstring": "*"
},
"require-dev": {
"maglnet/composer-require-checker": "^4.7.1",
"phpunit/phpunit": "^10.5.44",
"rector/rector": "^2.0.7",
"phpunit/phpunit": "^10.5.45",
"rector/rector": "^2.0.8",
"roave/infection-static-analysis-plugin": "^1.35",
"spatie/phpunit-watcher": "^1.24",
"vimeo/psalm": "^5.26.1"
"vimeo/psalm": "^5.26.1|^6.4.1"
},
"autoload": {
"psr-4": {
Expand Down
80 changes: 57 additions & 23 deletions src/Inflector.php
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@
}
foreach ($this->pluralizeRules as $rule => $replacement) {
if (preg_match($rule, $input)) {
/** @var string `$rule` and `$replacement` always correct, so `preg_replace` always returns string */
return preg_replace($rule, $replacement, $input);
}
}
Expand All @@ -459,6 +460,7 @@

foreach ($this->singularizeRules as $rule => $replacement) {
if (preg_match($rule, $input)) {
/** @var string `$rule` and `$replacement` always correct, so `preg_replace` always returns string */
return preg_replace($rule, $replacement, $input);
}
}
Expand Down Expand Up @@ -488,17 +490,21 @@
* Converts a string into space-separated words.
* For example, 'PostTag' will be converted to 'Post Tag'.
*
* @param string $input The string to be converted.
* @param string $input The valid UTF-8 string to be converted.
*
* @return string The resulting words.
*/
public function toWords(string $input): string
{
return mb_strtolower(trim(str_replace([
'-',
'_',
'.',
], ' ', preg_replace('/(?<!\p{Lu})(\p{Lu})|(\p{Lu})(?=\p{Ll})/u', ' \0', $input))));
/**
* @var string $words We assume that `$input` is valid UTF-8 string, so `preg_replace()` never returns `false`.
*/
$words = preg_replace('/(?<!\p{Lu})(\p{Lu})|(\p{Lu})(?=\p{Ll})/u', ' \0', $input);
return mb_strtolower(
trim(
str_replace(['-', '_', '.'], ' ', $words)
)
);
}

/**
Expand All @@ -507,7 +513,7 @@
* For example, 'PostTag' will be converted to 'post-tag'.
*
* @param string $input The string to be converted.
* @param string $separator The character used to concatenate the words in the ID.
* @param string $separator The character used to concatenate the words in the ID. It must be valid UTF-8 string.
* @param bool $strict Whether to insert a separator between two consecutive uppercase chars, defaults to false.
*
* @return string The resulting ID.
Expand All @@ -518,10 +524,14 @@
? '/(?<=\p{L})(\p{Lu})/u'
: '/(?<=\p{L})(?<!\p{Lu})(\p{Lu})/u';

/**
* @var string $result We assume that `$separator` and `$input` are valid UTF-8 strings, so `preg_replace()`
* never returns `false`.
*/
$result = preg_replace($regex, addslashes($separator) . '\1', $input);

if ($separator !== '_') {

Check warning on line 533 in src/Inflector.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "NotIdentical": @@ @@ * never returns `false`. */ $result = preg_replace($regex, addslashes($separator) . '\1', $input); - if ($separator !== '_') { + if ($separator === '_') { $result = str_replace('_', $separator, $result); } return mb_strtolower(trim($result, $separator));
$result = str_replace('_', $separator, $result);

Check warning on line 534 in src/Inflector.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "UnwrapStrReplace": @@ @@ */ $result = preg_replace($regex, addslashes($separator) . '\1', $input); if ($separator !== '_') { - $result = str_replace('_', $separator, $result); + $result = $result; } return mb_strtolower(trim($result, $separator)); }
}

return mb_strtolower(trim($result, $separator));
Expand All @@ -534,32 +544,38 @@
* will remove non alphanumeric character from the word, so
* "who's online" will be converted to "WhoSOnline".
*
* @param string $input The word to PascalCase.
* @param string $input The word to PascalCase. It must be valid UTF-8 string.
*
* @return string PascalCased string.
*
* @see toCamelCase()
*/
public function toPascalCase(string $input): string
{
/**
* @var string $input We assume that `$input` is valid UTF-8 string, so `preg_replace()` never returns `false`.
*/
$input = preg_replace('/[^\pL\pN]+/u', ' ', $input);
return str_replace(
' ',
'',
StringHelper::uppercaseFirstCharacterInEachWord(preg_replace('/[^\pL\pN]+/u', ' ', $input)),
StringHelper::uppercaseFirstCharacterInEachWord($input),
);
}

/**
* Returns a human-readable string.
*
* @param string $input The string to humanize.
* @param string $input The valid UTF-8 string to humanize.
* @param bool $uppercaseWords Whether to set all words to uppercase or not.
*
* @return string
*/
public function toHumanReadable(string $input, bool $uppercaseWords = false): string
{
$input = str_replace('_', ' ', preg_replace('/_id$/', '', $input));
/**
* @var string $input We assume that `$input` is valid UTF-8 string, so `preg_replace()` never returns `false`.
*/
$input = preg_replace('/_id$/', '', $input);
$input = str_replace('_', ' ', $input);

return $uppercaseWords
? StringHelper::uppercaseFirstCharacterInEachWord($input)
Expand All @@ -581,7 +597,7 @@
{
$input = $this->toPascalCase($input);

return mb_strtolower(mb_substr($input, 0, 1)) . mb_substr($input, 1);

Check warning on line 600 in src/Inflector.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "MBString": @@ @@ public function toCamelCase(string $input): string { $input = $this->toPascalCase($input); - return mb_strtolower(mb_substr($input, 0, 1)) . mb_substr($input, 1); + return strtolower(mb_substr($input, 0, 1)) . mb_substr($input, 1); } /** * Returns given word as "snake_cased".
}

/**
Expand All @@ -591,14 +607,18 @@
* It will remove non-alphanumeric character from the word,
* so "who's online" will be converted to "who_s_online".
*
* @param string $input The word to convert.
* @param string $input The word to convert. It must be valid UTF-8 string.
* @param bool $strict Whether to insert a separator between two consecutive uppercase chars, defaults to true.
*
* @return string The "snake_cased" string.
*/
public function toSnakeCase(string $input, bool $strict = true): string
{
return $this->pascalCaseToId(preg_replace('/[^\pL\pN]+/u', '_', $input), '_', $strict);
/**
* @var string $input We assume that `$input` is valid UTF-8 string, so `preg_replace()` never returns `false`.
*/
$input = preg_replace('/[^\pL\pN]+/u', '_', $input);
return $this->pascalCaseToId($input, '_', $strict);
}

/**
Expand Down Expand Up @@ -635,20 +655,32 @@
* and removes the rest. You may customize characters map via $transliteration property
* of the helper.
*
* @param string $input An arbitrary string to convert.
* @param string $replacement The replacement to use for spaces.
* @param string $input An arbitrary valid UTF-8 string to convert.
* @param string $replacement The replacement to use for spaces. It must be valid UTF-8 string.
* @param bool $lowercase whether to return the string in lowercase or not. Defaults to `true`.
*
* @return string The converted string.
*/
public function toSlug(string $input, string $replacement = '-', bool $lowercase = true): string
{
$quotedReplacement = preg_quote($replacement, '/');

Check warning on line 666 in src/Inflector.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "PregQuote": @@ @@ */ public function toSlug(string $input, string $replacement = '-', bool $lowercase = true): string { - $quotedReplacement = preg_quote($replacement, '/'); + $quotedReplacement = $replacement; /** * Replace all non-words character *
// replace all non words character

/**
* Replace all non-words character
*
* @var string $input We assume that `$input` and `$replacement` are valid UTF-8 strings, so `preg_replace()`
* never returns `false`.
*/
$input = preg_replace('/[^a-zA-Z0-9]+/u', $replacement, $this->toTransliterated($input));
// remove first and last replacements

/**
* Remove first and last replacements
*
* @var string $input We assume that `$input` and `$quotedReplacement` are valid UTF-8 strings, so
* `preg_replace()` never returns `false`.
*/
$input = preg_replace(
"/^(?:$quotedReplacement)+|(?:$quotedReplacement)+$/u" . ($lowercase ? 'i' : ''),

Check warning on line 683 in src/Inflector.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "Ternary": @@ @@ * @var string $input We assume that `$input` and `$quotedReplacement` are valid UTF-8 strings, so * `preg_replace()` never returns `false`. */ - $input = preg_replace("/^(?:{$quotedReplacement})+|(?:{$quotedReplacement})+\$/u" . ($lowercase ? 'i' : ''), '', $input); + $input = preg_replace("/^(?:{$quotedReplacement})+|(?:{$quotedReplacement})+\$/u" . ($lowercase ? '' : 'i'), '', $input); return $lowercase ? strtolower($input) : $input; } /**

Check warning on line 683 in src/Inflector.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "ConcatOperandRemoval": @@ @@ * @var string $input We assume that `$input` and `$quotedReplacement` are valid UTF-8 strings, so * `preg_replace()` never returns `false`. */ - $input = preg_replace("/^(?:{$quotedReplacement})+|(?:{$quotedReplacement})+\$/u" . ($lowercase ? 'i' : ''), '', $input); + $input = preg_replace("/^(?:{$quotedReplacement})+|(?:{$quotedReplacement})+\$/u", '', $input); return $lowercase ? strtolower($input) : $input; } /**
'',
$input,
);
Expand All @@ -665,12 +697,10 @@
*
* @noinspection PhpComposerExtensionStubsInspection
*
* @param string $input Input string.
* @param string $input Input string. It must be valid UTF-8 string.
* @param string|Transliterator|null $transliterator either a {@see \Transliterator} or a string
* from which a {@see \Transliterator} can be built. If null, value set with {@see withTransliterator()}
* or {@see TRANSLITERATE_LOOSE} is used.
*
* @return string
*/
public function toTransliterated(string $input, $transliterator = null): string
{
Expand All @@ -679,7 +709,11 @@
$transliterator = $this->transliterator;
}

/* @noinspection PhpComposerExtensionStubsInspection */
/**
* @noinspection PhpComposerExtensionStubsInspection
* @var string We assume that `$input` are valid UTF-8 strings and `$transliterator` is valid, so
* `preg_replace()` never returns `false`.
*/
return transliterator_transliterate($transliterator, $input);
}

Expand Down
7 changes: 5 additions & 2 deletions src/NumericHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static function toOrdinal(mixed $value): string
/**
* Returns string representation of a number value without thousands separators and with dot as decimal separator.
*
* @param bool|float|int|string|Stringable $value
* @param bool|float|int|string|Stringable $value String in `string` or `Stringable` must be valid UTF-8 string.
*
* @throws InvalidArgumentException if value is not scalar.
*/
Expand All @@ -69,8 +69,11 @@ public static function normalize(mixed $value): string
return $value ? '1' : '0';
}

$value = str_replace([' ', ','], ['', '.'], (string)$value);
$value = str_replace([' ', ','], ['', '.'], (string) $value);

/**
* @var string We assume that `$value` is valid UTF-8 string, so `preg_replace()` never returns `false`.
*/
return preg_replace('/\.(?=.*\.)/', '', $value);
}

Expand Down
18 changes: 15 additions & 3 deletions src/StringHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@
*
* @return int The number of bytes in the given string.
*/
public static function byteLength(string|null $input): int

Check warning on line 52 in src/StringHelper.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "PublicVisibility": @@ @@ * * @return int The number of bytes in the given string. */ - public static function byteLength(string|null $input): int + protected static function byteLength(string|null $input): int { return mb_strlen((string) $input, '8bit'); }
{
return mb_strlen((string)$input, '8bit');

Check warning on line 54 in src/StringHelper.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "MBString": @@ @@ */ public static function byteLength(string|null $input): int { - return mb_strlen((string) $input, '8bit'); + return strlen((string) $input); } /** * Returns the portion of string specified by the start and length parameters.
}

/**
Expand Down Expand Up @@ -410,13 +410,16 @@
/**
* Uppercase the first character of each word in a string.
*
* @param string $string The string to be processed.
* @param string $string The valid UTF-8 string to be processed.
* @param string $encoding The encoding to use, defaults to "UTF-8".
*
* @see https://php.net/manual/en/function.ucwords.php
*/
public static function uppercaseFirstCharacterInEachWord(string $string, string $encoding = 'UTF-8'): string
{
/**
* @var array $words We assume that `$string` is valid UTF-8 string, so `preg_split()` never returns `false`.
Tigrov marked this conversation as resolved.
Show resolved Hide resolved
*/
$words = preg_split('/\s/u', $string, -1, PREG_SPLIT_NO_EMPTY);

$wordsWithUppercaseFirstCharacter = array_map(
Expand Down Expand Up @@ -466,13 +469,22 @@
* Split a string to array with non-empty lines.
* Whitespace from the beginning and end of a each line will be stripped.
*
* @param string $string The input string.
* @param string $string The input string. It must be valid UTF-8 string.
* @param string $separator The boundary string. It is a part of regular expression
* so should be taken into account or properly escaped with {@see preg_quote()}.
* so should be taken into account or properly escaped with {@see preg_quote()}. It must be valid UTF-8 string.
*/
public static function split(string $string, string $separator = '\R'): array
{
/**
* @var string $string We assume that `$string` is valid UTF-8 string, so `preg_replace()` never returns
* `false`.
*/
$string = preg_replace('(^\s*|\s*$)', '', $string);

/**
* @var array We assume that $separator is prepared by `preg_quote()` and $string is valid UTF-8 string,
* so `preg_split()` never returns `false`.
*/
return preg_split('~\s*' . $separator . '\s*~u', $string, -1, PREG_SPLIT_NO_EMPTY);
}

Expand Down
2 changes: 2 additions & 0 deletions src/WildcardPattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public function ignoreCase(bool $flag = true): self
*/
public static function isDynamic(string $pattern): bool
{
/** @var string $pattern `$rule` and `$replacement` always correct, so `preg_replace` always returns string */
$pattern = preg_replace('/\\\\./', '', $pattern);
return preg_match('/[*{?\[]/', $pattern) === 1;
}
Expand All @@ -93,6 +94,7 @@ public static function isDynamic(string $pattern): bool
*/
public static function quote(string $string): string
{
/** @var string `$rule` and `$replacement` always correct, so `preg_replace` always returns string */
return preg_replace('#([\\\\?*\\[\\]])#', '\\\\$1', $string);
}

Expand Down
Loading