众所周知,trim
系列(包括 ltrim
和 rtrim
)函数在 PHP 中被用于删除字符串两边的空白字符,其中 ltrim
用于删除字符串开头的特殊字符,rtrim
删除字符串末尾的特殊字符。
以 ltrim
为例,不少资料给出的用法通常是:
ltrim($str[, $character_mask])
其中,第一个参数用于指定要操作的字符串,后面一个参数指定需要删除的“特殊字符“,一次在项目中如下使用 ltrim 函数:
$str = '/public/storage/app/file';
$del = '/public';
$ret = ltrim($str, $del);
按照往常的理解,上面一段代码执行后 $ret
值应该是字符串 /storage/app/file
,然而实际使用中 $ret
的值是 storage/app/file
,也就是说实际处理过程中,ltrim
函数多删除了一个 /
符号!
其实这并不是 PHP 出现的 “bug”,在官方手册中,ltrim 函数提供了如下的使用案例:
When using a $character_mask the trimming stops at the first character that is not on that mask. So in the $string = "Hello world" example with $character_mask = "Hdle", ltrim($hello, $character_mask) goes like this:
- Check H from "Hello world" => it is in the $character_mask, so remove it
- Check e from "ello world" => it is in the $character_mask, so remove it
- Check l from "llo world" => it is in the $character_mask, so remove it
- Check l from "lo world" => it is in the $character_mask, so remove it
- Check o from "o world" => it is NOT in the $character_mask, exit the function Remaining string is "o world".
也就是说,第二个参数 $character_mask
在函数执行过程中,并不会被当做完整的字符串,而是作为“字符列表”,PHP 会从开头位置逐个遍历,如果发现有字符出现在“字符列表”中,就删除,直到发现第一个不在列表中的字符为止!
在之前的项目案例中,/public
作为字符列表,/
字符包含在其中,因此当 ltrim 函数删除遇到 storage
之前·/
字符时候,同样也会删除,而 storage
中的 s
并不在 /public
参数列表中,因此删除过程会在此停止,最后原始字符串就只剩下 storage/app/file
这部分了。