编程

PHP 8.4: 新增 mb_ucfirst 和 mb_lcfirst 函数

105 2024-04-18 21:18:00

PHP 提供 ucfirstlcfirst 函数来更改给定字符串中第一个字符的大小写。

mbstring 扩展为 PHP 的大多数标准字符串函数提供了多字节安全函数。然而,在 PHP8.4 之前,mbstring 扩展没有为 ucfirstlcfirst 函数提供多字节安全的对应函数。

在 PHP 8.4 中,mbstring 扩展添加了 mb_ucfirstmb_lcfirst 函数,作为 ucfirstlcfirst 函数的多字节安全替代方案。

Titlecase vs UPPERcase
Unicode 标准定义了一个字符映射列表,这些映射在 uppercase(大写)和 titlecase(标题大小写)中的工作方式不同。

例如,小写字符 nj (U+01CC - 拉丁文小写字母 Nj)在大写中更改为 NJ (U+01CA - 拉丁文大写字母 Nj);而 titlecase 中则改为 Nj (U+01CB - 拉丁文大写字母  N 及小写字母 J)。另一个例子是德语 Eszett 字符(ß - U+00DF),其大写字母为 SS,而标题格为 Ss

有关具有 Changes_When_Titlecased (CWT) 属性的代码点,请参阅 Unicode 常见问题解答Unicode 派生代码属性

新增 mb_ucfirstmb_lcfirst 函数

新增的 mb_ucfirstmb_lcfirst 函数提供了多字节安全函数,用以修改给定字符串的首字母大小写。

类似于其他的 mb_* 函数,mb_ucfirstmb_lcfirst 函数也接受 ?string $encoding = null 作为最后一个参数,而这两个函数的第一个参数是需要修改大小写的字符串。

请注意,多字节转换可以改变字节大小(strlen() 输出)以及值的长度(mb_strlen() 输出)。比如

  •  K 字符( - U+212A,占用 3 字节) 的小写字母为 k (U+006B,1 字节)。
  • Eszett 字符 (ß) 转换为 Ss (titlecase) 和 SS (uppercase)。字节大小保留为 2 个字节,不过本例中,长度(mb_strlen())变为 1 到 2 字节。

这可能会影响验证字符串长度和大小的功能,例如数据库索引大小限制。

mb_ucfirst {#mb_ucfirst} 函数

mb_ucfirst 函数将给定字符的首个字符改为大写。其他字符保持不变,即使它是大写形式。和 ucfirst 函数不同的是,mb_ucfirst 支持多字节字符,因此支持所有的 Unicode 大写规范。

/**  
 * Make a string's first character uppercase multi-byte safely.
 **/
function mb_ucfirst(string $string, ?string $encoding = null): string {}  

用例

mb_ucfirst('test'); // Test - unchanged
mb_ucfirst('TEST'); // TEST
mb_ucfirst('tEst'); // TEst
mb_ucfirst('tEst'); // TEst
mb_ucfirst('łámał'); // Łámał
mb_ucfirst("\u{01CA}"); // "\u{01CB}"
mb_ucfirst("💓🙈"); // "💓🙈" - unchanged
mb_ucfirst("ß"); // "Ss" - Only the first S uppercase.

mb_lcfirst {#mb_lcfirst} 函数

类似于 mb_ucfirst 函数,mb_lcfirst 将给定字符串的首个字符转换成小写。不像 lcfirst 函数,mb_lbfirst 可用修改多字节字符。

/**  
 * Make a string's first character lowercase multi-byte safely.
 **/
function mb_lcfirst(string $string, ?string $encoding = null): string {}

用例

mb_ucfirst('test'); // test - unchanged
mb_ucfirst('TEST'); // tEST
mb_ucfirst('tEst'); // tEst
mb_ucfirst('tEst'); // TEst
mb_ucfirst('Łámał'); // łámał
mb_ucfirst("\u{01CA}"); // "\u{01CB}"
mb_ucfirst("ß"); // "ß" - unchanged

PHP Polyfills

这些函数可以在用户空间 PHP 中简单地实现:

/**
 * Make a string's first character uppercase multi-byte safely.
 */
function mb_ucfirst(string $string, ?string $encoding = null): string {
    $firstChar = mb_substr($string, 0, 1, $encoding);
    $firstChar = mb_convert_case($firstChar, MB_CASE_TITLE, $encoding);

    return $firstChar . mb_substr($string, 1, null, $encoding);
}

/**
 * Make a string's first character lowercase multi-byte safely.
 */
function mb_lcfirst(string $string, ?string $encoding = null): string {
    $firstChar = mb_substr($string, 0, 1, $encoding);
    $firstChar = mb_convert_case($firstChar, MB_CASE_LOWER, $encoding);

    return $firstChar . mb_substr($string, 1, null, $encoding);
}

以上实现也可以作为 Composer 包安装:

composer require polyfills/mb-ucfirst-lcfirst

向后兼容性影响

这两个函数,mb_ucfirstmb_lcfirst,在全局命名空间中声明。除非现有的函数在全局命名空间中使用了相同的名称,否则这个修改对向后兼容性不会有影响。 

此外,新函数可以在用户空间 PHP 中实现。