Получение первого символа строки с помощью $ str [0]


276

Я хочу получить первую букву строки, и я заметил, что это $str[0]прекрасно работает. Я просто не уверен, является ли это «хорошей практикой», так как эта запись обычно используется с массивами. Эта функция не очень хорошо документирована, поэтому я обращаюсь к вам, ребята, чтобы сказать мне, все ли в порядке - во всех отношениях - использовать эту запись?

Или я должен просто придерживаться старого доброго substr($str, 0, 1)?

Также я заметил, что фигурные скобки ( $str{0}) также работают. Что с этим?


5
плюс 1 за «добрый старый субстрат ($ str, 0, 1)».
Сантьяго выходит SO

Ответы:


390

Да. Строки можно рассматривать как символьные массивы, и способ доступа к позиции массива заключается в использовании []оператора. Обычно в использовании нет никаких проблем $str[0](и я уверен, что это намного быстрее, чем substr()метод).

С обоими методами есть только одно предупреждение: они получат первый байт , а не первый символ . Это важно, если вы используете многобайтовые кодировки (такие как UTF-8). Если вы хотите поддержать это, используйте mb_substr(). Возможно, вы должны всегда предполагать многобайтовый ввод в эти дни, так что это лучший вариант, но он будет немного медленнее.


7
Учитывает ли PHP $ str [0], что могут быть 2-байтовые символы? UTF и такие? (хотя substr () тоже не помогает!)
Томер W

77
Если вы хотите быть сверхбезопасным, вам следует придерживаться этого, mb_substr($str, 0, 1, 'utf-8')чтобы не обрезать многобайтовую строку.
Вик

18
Хотя это короче и легче запомнить substr($str, 0, 1), это сбивает с толку тех, кто читает код.
Трант

10
Выбор между квадратными скобками и substr () во многом зависит от предпочтений, но имейте в виду, что результат будет другим при применении к пустой строке. Если $ s = "", то $ s [] === "", но substr ($ s, 0, 1) === false.
xtempore

9
Если $ s = "", то $ s [0] сгенерирует "Примечание: смещение неинициализированной строки: 0", тогда как substr ($ s, 0, 1) - нет.
Крис

46

Синтаксис {} устарел, начиная с PHP 5.3.0. Квадратные скобки рекомендуются.


14
docs.php.net/language.types.string :Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose. However, this syntax is deprecated as of PHP 5.3.0. Use square brackets instead, such as $str[42].
VolkerK

4
@VolkerK: по ссылке, которую вы предоставили, я заметил, что они удалили примечание к руководству по PHP, которое они оставили только: Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose.поэтому мне интересно, решили ли они, что использование {}НЕ устарело с PHP 6
Марко Демайо

1
@MarcoDemaio Теперь ссылка говорит о том, что говорит Майкл Мортон.
Тино

1
«не указывает на устаревание» - Действительно, сообщение об устаревании было удалено в ревизии 304518 - The curly-brackets-string-index-accessor-syntax does not emit any deprecation notice, although the original notice have been on and off for PHP 5.x, it does not in the current version, thrus we should not label it as deprecated. Related to bug #52254- svn.php.net/repository/phpdoc/en/trunk/language/types/…
VolkerK

На сегодняшний день (10 мая 18 года) цитата из понравившихся PHP документов : Note: Strings may also be accessed using braces, as in $str{42}, for the same purpose. похоже, этот синтаксис останется на некоторое время.
Fr0zenFyr

25

Допустим, вам нужен только первый символ из части $ _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], но это зависит от окружающих обстоятельств.


2
В качестве дополнительного примечания, чтобы обойти эту конкретную проблему и в любом случае всегда следует выполнять проверку данных. if (true === is_string($_POST['type']))
фюре

13

Единственное, в чем я сомневаюсь, это то, насколько применим этот метод к многобайтовым строкам, но если это не так, то я подозреваю, что вы защищены. (Если сомневаетесь, mb_substr()кажется, очевидно, безопасный выбор.)

Однако, с точки зрения общей картины, я должен задаться вопросом, как часто вам нужен доступ к n-му символу в строке, чтобы это было ключевым фактором.


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
Хороший тест! Несколько чисел от 3-летнего Xeon: среднее время микропрограммы с использованием «array []» равно 2.2427082061768E-7, среднее время микропрограммы с использованием «substr ()» составляет 3.9647579193115E-7, среднее время работы с помощью «array {}» равно 2.1522283554077E-7
Эллерт ван Коперен

для точных измерений вы должны сделать микротайм вне цикла и не смешивать различные подходы в одном цикле.
PypeBros

1
не смешивая исполнение testA и testBвнутри одного и того же цикла означает, что вы способны обнаружить, например, тот факт, что testBкеш-убийца, а testAкеш-дружественный. Когда они оба находятся в одной и той же петле, у них одинаковые тайминги, потому что кеширование testBзагрязнено testA.
PypeBros

1
аналогично, я бы избегал генерации строк или случайных чисел в циклах тестирования и имел бы их готовыми в массиве поблизости.
PypeBros

1
-1; оставляя в стороне сомнительный механизм синхронизации (было бы лучше рассчитать время выполнения многих операций, чем рассчитывать их по одной за раз; прочитав это, я беспокоился, что именно время, затраченное на выполнение microtime()вызова, будет составлять большую часть разницы во времени, хотя экспериментально это кажется чтобы не быть правдой), здесь нет причин беспокоиться о крошечной разнице в скорости. Это доля миллионной доли секунды; когда это когда-либо будет иметь значение?
Марк Амери

6

Говоря как простой смертный, я бы придерживался $str[0]. Насколько мне известно, быстрее понять значение с первого $str[0]взгляда, чем substr($str, 0, 1). Это, вероятно, сводится к вопросу предпочтений.

Что касается производительности, ну, профиль профиль профиль. :) Или вы можете заглянуть в исходный код PHP ...


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

6
-1; вопрос ОП заключался в том, был ли этот синтаксис плохой практикой, и вы ответили ... повторив синтаксис без каких-либо комментариев? Это не ответ.
Марк Амери

5

В случае использования многобайтовых (юникодных) строк str[0]может возникнуть проблема. mb_substr()это лучшее решение. Например:

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

Некоторые детали здесь: Получить первый символ строки UTF-8


Спасибо за это решение! если первый символ Unicode, [] не будет работать
SunB

1

Я использовал эту запись и раньше, без побочных эффектов и недоразумений. Это имеет смысл - в конце концов, строка - это просто массив символов.


Нет, строка не является массивом символов (по крайней мере, так как PHP использует эти два термина). -1.
Марк Амери


@gattsbr внутренне они есть, но с точки зрения модели, представленной PHP, это принципиально иная вещь. Доступ к смещению с использованием записи в квадратных скобках - это практически единственная операция, которую они имеют вместе с массивами; Строковые функции не работают с массивами, и наоборот, а синтаксис добавления массива ( $arr[] = $new_element) не работает со строками. Поэтому я не думаю, что представление строк как символьных массивов полезно.
Марк Эмери

@markamery лучше переписать руководство php.net, чем включать такую ​​незначительную техническую составляющую.
gattsbr
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.