Отримання першого символу рядка з $ str [0]


276

Я хочу отримати першу букву рядка, і я помітив, що це $str[0]чудово працює. Я просто не впевнений, чи це "хороша практика", оскільки це позначення зазвичай використовується для масивів. Ця функція, здається, не дуже добре задокументована, тому я звертаюся до вас, хлопці, скажіть мені, чи все в порядку - в усіх відношеннях - використовувати це позначення?

Або я повинен просто дотримуватися хорошого ol ' substr($str, 0, 1)?

Також я зазначив, що фігурні брекети ( $str{0}) також працюють. Що з цим?


5
плюс 1 для субстрату "good ol" ($ str, 0, 1) ".
Сантьяго виходить з ТО

Відповіді:


390

Так. Рядки можна розглядати як масиви символів, а спосіб доступу до масиву - використовувати []оператор. Зазвичай у використанні немає проблем $str[0](і я впевнений, що це набагато швидше, ніж substr()метод).

Є лише один застереження з обома методами: вони отримають перший байт , а не перший символ . Це важливо, якщо ви використовуєте багатобайтові кодування (наприклад, UTF-8). Якщо ви хочете підтримати це, використовуйте mb_substr(). Можливо, ви завжди повинні приймати багатобайтові введення в ці дні, тому це найкращий варіант, але він буде трохи повільніше.


7
Чи враховує PHP $ str [0], що може бути 2Byte довгих символів? UTF і таке? (навіть якщо substr () теж не допомагає в цьому!)
Tomer W

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

18
Хоча це коротше і запам'ятовується легше, ніж substr($str, 0, 1)це збиває з пантелику того, хто читає код.
trante

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

9
Якщо $ s = "", то $ s [0] генерує "Повідомлення: Зніс неініціалізованого рядка: 0", тоді як substr ($ s, 0, 1) не буде.
chris

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
Marco Demaio

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, давайте назвати його "тип". І що $ _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']))
fyrye

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: середній мікрочасовий поплавок, що використовує "масив []", становить 2.2427082061768E-7, середній мікрочасовий поплавок, використовуючи "substr ()", становить 3.9647579193115E-7, середній мікрочасовий поплавок з використанням "масиву {}" 2.1522283554077E-7
Ellert van Koperen

для точних вимірювань вам слід краще робити мікрочаси з циклу, а не змішувати різні підходи в межах одного циклу.
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

У разі використання багатобайтових (unicode) рядків str[0]може спричинити проблеми. mb_substr()є кращим рішенням. Наприклад:

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

Деякі деталі тут: Отримайте перший символ рядка UTF-8


Дякую за таке рішення! якщо перший символ є unicode, [] не буде працювати
SunB

1

Раніше я вже використовував це позначення, без жодних побічних ефектів і непорозумінь. Це має сенс - рядок - це лише масив символів.


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


@gattsbr всередині них є, але що стосується моделі, яку виставляє PHP, вони принципово інша річ. Доступ до зміщення за допомогою позначення квадратних дужок - це майже єдина операція, яку вони мають спільне з масивами; Функції рядків не працюють на масивах, ні vica навпаки, а синтаксис додавання масиву ( $arr[] = $new_element) не працює в рядках. Як такий, я не думаю, що уявлення рядків як масивів символів є корисним.
Марк Амері

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