使用 $str[0] 获取字符串的第一个字符

308

我想要获取字符串的第一个字母,我注意到 $str[0] 这种写法很好用。我不确定这是否是'良好实践',因为这种表示通常与数组一起使用。这个特性似乎没有很好的文档说明,所以我来问问你们,能否在所有方面都使用这种方法?

还是说我应该坚持使用经典的 substr($str, 0, 1)

另外我也注意到花括号 ($str{0}) 同样适用。这是怎么回事呢?


5
给“好的旧的substr($str, 0, 1)”加1。 - Máster
9个回答

425

可以。字符串可以看作字符数组,访问数组的位置方式是使用[]运算符。通常情况下,使用$str[0](我非常确定比substr()方法快)没有问题。

这两种方法只有一个警告:它们会获取第一个 字节 而不是第一个字符。如果你使用多字节编码(如UTF-8),这一点很重要。如果你想支持它,请使用mb_substr()。可以说,现在应该总是假定输入是多字节的,所以这是最好的选择,但它会稍微慢一些。


7
PHP $str[0] 会考虑到可能存在2个字节长的字符吗?比如UTF等字符集?(尽管substr()函数也无法处理这种情况!) - Tomer W
82
如果您想要更加安全,可以使用mb_substr($str, 0, 1, 'utf-8')来避免截取多字节字符串。 - Vic
18
虽然这段代码比substr($str, 0, 1)更短、更易记,但它容易让读代码的人感到困惑。 - trante
10
方括号和substr()函数之间的选择在很大程度上取决于个人偏好,但要注意当应用于空字符串时结果会有所不同。如果$s = "",则$s[] === "",但substr($s, 0, 1) === false。 - xtempore
10
如果 $s = "",那么 $s[0] 将会生成一个 "Notice: Uninitialized string offset: 0" 的警告,而 substr($s, 0, 1) 不会。请注意,不要改变原始含义。 - chris
显示剩余6条评论

52

从PHP 5.3.0开始,{}语法已弃用,建议使用方括号。


14
注意:为了同样的目的,字符串还可以使用花括号进行访问,例如 $str{42}。然而,这种语法自 PHP 5.3.0 起已被弃用。请改用方括号,例如 $str[42]。 - VolkerK
4
在你提供的链接中,我注意到他们删除了PHP手册上的注释,只留下了以下内容:“注意:为了相同的目的,字符串也可以使用花括号访问,例如$ str {42}。”所以我想知道,他们是否决定在PHP 6中不再弃用使用“{}”。 - Marco Demaio
1
@MarcoDemaio,该链接现在显示了MichaelMorton所说的内容。 - Tino
1
“不表明已弃用” - 实际上,在修订版304518中已删除了弃用消息 - “花括号字符串索引访问器语法不会发出任何弃用通知,尽管原始通知在PHP 5.x中一直存在,但在当前版本中不存在,因此我们不应将其标记为已弃用。与错误#52254相关。”- https://svn.php.net/repository/phpdoc/en/trunk/language/types/string.xml?p=304518 - VolkerK
截至今天(2018年5月10日),引用自喜爱的PHP文档注意:字符串也可以使用大括号访问,例如 $str{42},目的相同。看起来这种语法会持续一段时间。 - Fr0zenFyr
它已经再次更新了。自PHP 7.4.0起,它已被弃用,并在8.0.0中删除。 - RobinHood70

30
假设您只想从 $_POST 的一部分中获取第一个字符,我们称之为'type'。并且 $_POST['type'] 目前为 'Control'。在这种情况下,如果您使用 $_POST['type'][0]substr($_POST['type'], 0, 1),您将得到 C
然而,如果客户端修改他们发送给您的数据,例如将 type 修改为 type[],然后将 'Control' 和 'Test' 作为此数组的数据发送,$_POST['type'][0] 现在将返回 Control 而不是 C,而 substr($_POST['type'], 0, 1) 将会失败。
因此,使用 $str[0] 可能存在问题,但这取决于周围的情况。

3
顺便提一句,为了规避这个特定问题,在任何情况下都应该进行数据验证。 if (true === is_string($_POST['type'])) - Will B.

13

我唯一的疑虑是这种技术在多字节字符串上的适用性,但如果这不是一个问题,那么我认为你已经做得很好了。(如果有疑问,mb_substr()似乎是一个显而易见的安全选择。)

但是,从宏观的角度来看,我要想知道你需要多经常访问字符串中的第n个字符才会成为一个关键考虑因素。


12

如果使用多字节(Unicode)字符串,使用str[0]可能会出现问题。 mb_substr() 是更好的解决方案。例如:

$first_char = mb_substr($title, 0, 1);

这里有一些细节:获取UTF-8字符串的第一个字符


谢谢您提供的解决方案!如果第一个字符是Unicode,[]将无法工作。 - SunB

10
$str = 'abcdef';
echo $str[0];                 // a

6
OP的问题是这种语法是否是一种不好的做法,而你的回答是……重复了这个语法,没有任何评论?这不是一个答案。 - Mark Amery

9

根据资源不同,情况会有所不同,但您可以运行下面的脚本并自己查看;)

<?php
$tests = 100000;

for ($i = 0; $i < $tests; $i++)
{
    $string = md5(rand());
    $position = rand(0, 31);

    $start1 = microtime(true);
    $char1 = $string[$position];
    $end1 = microtime(true);
    $time1[$i] = $end1 - $start1;

    $start2 = microtime(true);
    $char2 = substr($string, $position, 1);
    $end2 = microtime(true);
    $time2[$i] = $end2 - $start2;

    $start3 = microtime(true);
    $char3 = $string{$position};
    $end3 = microtime(true);
    $time3[$i] = $end3 - $start3;
}

$avg1 = array_sum($time1) / $tests;
echo 'the average float microtime using "array[]" is '. $avg1 . PHP_EOL;

$avg2 = array_sum($time2) / $tests;
echo 'the average float microtime using "substr()" is '. $avg2 . PHP_EOL;

$avg3 = array_sum($time3) / $tests;
echo 'the average float microtime using "array{}" is '. $avg3 . PHP_EOL;
?>

一些参考数字(在旧的CoreDuo机器上)

$ php 1.php 
the average float microtime using "array[]" is 1.914701461792E-6
the average float microtime using "substr()" is 2.2536706924438E-6
the average float microtime using "array{}" is 1.821768283844E-6

$ php 1.php 
the average float microtime using "array[]" is 1.7251944541931E-6
the average float microtime using "substr()" is 2.0931363105774E-6
the average float microtime using "array{}" is 1.7225742340088E-6

$ php 1.php 
the average float microtime using "array[]" is 1.7293763160706E-6
the average float microtime using "substr()" is 2.1037721633911E-6
the average float microtime using "array{}" is 1.7249774932861E-6

看起来使用[]{}运算符基本上是一样的。


2
不错的测试! 来自一台三年前的 Xeon 的一些数字: 使用“array []”的平均浮点微秒为 2.2427082061768E-7 使用“substr()”的平均浮点微秒为 3.9647579193115E-7 使用“array {}”的平均浮点微秒为 2.1522283554077E-7 - Ellert van Koperen
@PypeBros,您能详细说明一下您的方法的优点,并分享代码吗?谢谢。 - Willy Stadnick
1
不在同一循环中混合执行testAtestB意味着您能够检测到例如testB是一个破坏缓存的事实,而testA是缓存友好的。当它们都在同一个循环中时,它们被测量为具有完全相同的时间,因为testB污染了testA的缓存。 - PypeBros
1
同样地,我会避免在测试循环内生成字符串或随机数,并在附近的数组中准备好它们。 - PypeBros
1
-1;撇开可疑的计时机制不谈(最好计时多个操作而不是逐个计时;我担心仅仅执行“microtime()”调用所花费的时间就会占据大部分时间差异,尽管实验结果似乎并非如此),在这里没有理由关心微小的速度差异。这只是百万分之一秒的一小部分;这种情况何时会有任何影响呢? - Mark Amery
显示剩余2条评论

7

作为一个普通人,我会选择使用$str[0]。在我看来,一眼就能理解$str[0]的含义比理解substr($str, 0, 1)更快。这可能归结为个人喜好。

至于性能,建议进行性能分析。 :) 或者你可以查看PHP源代码...


1

我之前也使用过这种表示法,没有任何不良副作用和误解。这很有道理——毕竟一个字符串只是字符数组而已。


不,一个字符串不是一个字符数组(至少在PHP使用这两个术语时不是)。-1。 - Mark Amery
@MarkAmery 【通过在字符串后使用方括号指定所需字符的零基偏移量,可以访问和修改字符串中的字符。例如 $str[42]。为此目的,请将字符串视为字符数组。】(http://php.net/manual/en/language.types.string.php#language.types.string.substr)在内部,PHP字符串是字节数组。 - gattsbr
@gattsbr 他们在内部属于同一种数据类型,但就 PHP 所公开的模型而言,它们是根本不同的东西。使用方括号表示法访问偏移量几乎是它们与数组唯一共有的操作; 字符串函数不能用于数组,反之亦然,并且数组追加语法($arr[] = $new_element)不能用于字符串。因此,我认为将字符串视为字符数组是没有意义的。 - Mark Amery
@markamery最好开始重写php.net手册,以包含这样微不足道的技术细节。 - gattsbr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接