Строки
Строка (string) — это набор символов, в котором символ — то же,
что и байт. То есть PHP поддерживает набор только из 256 символов и, следовательно,
не обеспечивает встроенную поддержку кодировки Unicode. Подробнее об этом рассказывает раздел
«Подробные сведения о строковом типе».
В 32-битных сборках размер строки (string) ограничен 2 ГБ (2 147 483 647 байтов максимум).
Синтаксис
Строковый литерал определяют четырьмя способами:
одинарными кавычками
двойными кавычками
heredoc-синтаксисом
nowdoc-синтаксисом
Одинарные кавычки
Простейший способ определить строку — заключить строку в одинарные кавычки
(символ ').
Чтобы записать внутри строки буквальную одинарную кавычку, её экранируют обратным слешем
(\). Чтобы записать сам обратный слеш, его дублируют
(\\). В остальных случаях обратный слеш будет
обработан как буквальный обратный слеш: то есть
последовательности вроде \r или
\n не будут рассматриваться как управляющие, а будут выведены как записаны.
Переменные и управляющие последовательности служебных символов
в одинарных кавычках не обрабатываются,
в отличие от синтаксиса двойных кавычек
и heredoc.
]]>
Двойные кавычки
PHP распознает следующие управляющие последовательности служебных символов,
если строку заключили в двойные кавычки ("):
Управляющие последовательностиПоследовательностьЗначение\nновая строка (LF или 0x0A (10) в ASCII)\rвозврат каретки (CR или 0x0D (13) в ASCII)\tгоризонтальная табуляция (HT или 0x09 (9) в ASCII)\vвертикальная табуляция (VT или 0x0B (11) в ASCII)\eescape-знак (ESC или 0x1B (27) в ASCII)\fподача страницы (FF или 0x0C (12) в ASCII)\\обратная косая черта\$знак доллара\"двойная кавычка\[0-7]{1,3}
Восьмеричная запись: символ, код которого записали в восьмеричной нотации (т. е. "\101" === "A"),
т. е. в виде последовательности символов, которая соответствует регулярному выражению [0-7]{1,3}.
В ситуации целочисленного переполнения (если символ не поместится в один байт),
старшие биты будут без предупреждения отброшены (т. е. "\400" === "\000")
\x[0-9A-Fa-f]{1,2}
Шестнадцатеричная система счисления: символ, код которого записали
в шестнадцатеричной нотации (т. е. "\x41" === "A"),
т. е. в виде последовательности символов, которая соответствует
регулярному выражению [0-9A-Fa-f]{1,2}\u{[0-9A-Fa-f]+}
Стандарт Unicode: символ, код которого записали в нотации кодовых точек Unicode,
т. е. в виде последовательности символов, которая соответствует
регулярному выражению [0-9A-Fa-f]+,
которые будут отображены как строка в кодировке UTF-8.
Последовательность необходимо заключать в фигурные скобки.
Например: "\u{41}" === "A"
Как и в строках в одинарных кавычках, экранирование другого символа
выведет также и символ обратного слеша.
Наиболее важное свойство строк в двойных кавычках состоит в том,
что имена переменных в них будут развёрнуты и обработаны.
Подробнее об этом рассказывает раздел
«Синтаксический анализ переменных».
Heredoc
Третий способ определения строк — это heredoc-синтаксис:
<<<. Следом за этим оператором указывают идентификатор,
а затем перевод строки. Затем идёт сама строка, за которой снова идёт тот же идентификатор,
чтобы закрыть вставку.
Закрывающий идентификатор разрешено отбивать пробелами или символами табуляции,
и тогда отступ будет удалён из каждой строки в блоке документа.
До PHP 7.3.0 закрывающий идентификатор указывали в самом начале новой строки.
Кроме того, закрывающий идентификатор подчиняется тем же правилам именования,
что и другие метки в PHP: содержит только буквенно-цифровые символы
и подчёркивания, и не начинается с цифрового символа или символа подчёркивания.
Базовый пример использования Heredoc-синтаксиса в PHP 7.3.0
&example.outputs.73;
Если закрывающий идентификатор смещён дальше хотя бы одной строки тела,
будет выброшено исключение ParseError:
Отступу закрывающего идентификатора нельзя отступать больше, чем другим строкам тела
&example.outputs.73;
В теле тоже будет допустимо указывать табуляции, если закрывающий идентификатор отбить отступом.
Однако табуляциям и пробелам не разрешено
смешиваться относительно отступа закрывающего идентификатора и тела (вплоть до закрывающего идентификатора).
В каждом из этих случаев будет выброшено исключение ParseError.
Эти ограничения на пробельные отступы добавили, потому что смешивание табуляций
и пробелов для отступов вредно для разбора.
Другой отступ для закрывающего идентификатора тела (пробелов)
&example.outputs.73;
За закрывающим идентификатором основной строки не обязательно ставить точку с запятой или новую строку.
Например, начиная с PHP 7.3.0 разрешён следующий код:
Продолжение выражения после закрывающего идентификатора
&example.outputs.73;
string(11) "a
b
c"
[1] =>
string(5) "d e f"
}
]]>
Парсер примет идентификатор за закрывающий и выбросит
исключение ParseError, если найдёт
закрывающий идентификатор в начале строки, даже если это часть слова.
Закрывающий идентификатор в теле текста провоцирует исключение ParseError
&example.outputs.73;
Чтобы не возникало таких проблем, следуют несложному, но надёжному правилу:
не выбирать закрывающий идентификатор, который встречается в теле текста.
До PHP 7.3.0 строке с закрывающим идентификатором нельзя было содержать
символов, кроме точки с запятой (;). То есть
идентификатор не разрешено вводить с отступом,
а пробелы или знаки табуляции нельзя вводить до или после точки с запятой.
Учитывают также, что первым символом перед закрывающим идентификатором идёт
символ новой строки, который определён в операционной системе. Например,
в Unix-системах, включая macOS, это символ \n. После закрывающего
идентификатора должна сразу начинаться новая строка.
PHP не будет считать идентификатор закрывающим и продолжит поиск идентификатора
дальше, если это правило нарушили и закрывающий идентификатор не «чистый».
На последней строке возникнет ошибка синтаксического анализа, если PHP
так и не найдёт правильный закрывающий идентификатор до конца текущего файла.
Пример неправильного до PHP 7.3.0 синтаксиса
]]>
Пример правильного даже до PHP 7.3.0 синтаксиса
]]>
Переменные в Heredoc-синтаксисе не инициализируют свойств класса.
Heredoc-текст хотя и не заключён в двойные кавычки, ведёт себя как строка в двойных кавычках.
То есть в heredoc кавычки не экранируют,
но перечисленные управляющие коды по-прежнему разрешено указывать.
Переменные разворачиваются, но в выражениях со сложными переменными внутри heredoc
работают так же внимательно, как и при работе со строками.
Пример определения heredoc-строки
foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'Имярек';
echo <<foo.
Теперь я вывожу {$foo->bar[1]}.
Это должно вывести заглавную букву 'A': \x41
EOT;
?>
]]>
&example.outputs;
Heredoc-синтаксис разрешён также для передачи данных через аргументы функции:
Пример heredoc-синтаксиса с аргументами
]]>
В heredoc-синтаксисе разрешено инициализировать статические переменные и свойства или константы класса:
Инициализация статических переменных heredoc-синтаксисом
]]>
Допустимо также окружать heredoc-идентификатор двойными кавычками:
Двойные кавычки в heredoc
]]>
Nowdoc
Nowdoc — это то же для строк в одинарных кавычках, что и heredoc для строк
в двойных кавычках. Синтаксис Nowdoc похож на heredoc-синтаксис, но внутри него
не выполняются подстановки. Конструкция
легко встраивает PHP-код или другие большие блоки текста без
предварительного экранирования. В этом он отчасти похож на SGML-конструкцию
<![CDATA[ ]]>, в том, что он объявляет блок текста,
который не требует обработки.
Nowdoc задают той же последовательностью символов <<<,
что и в heredoc, но следующий за ней идентификатор берут
в одинарные кавычки, например, <<<'EOT'.
Условия, которые распространяются на идентификаторы heredoc-синтаксиса, действительны также
и для синтаксиса nowdoc, а больше остальных те, что относятся к закрывающему идентификатору.
Пример nowdoc-синтаксиса
&example.outputs;
Nowdoc с переменными в строках с двойными кавычками
foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'Имярек';
echo <<<'EOT'
Меня зовут "$name". Я печатаю $foo->foo.
Теперь я печатаю {$foo->bar[1]}.
Это не должно вывести заглавную 'A': \x41
EOT;
?>
]]>
&example.outputs;
foo.
Теперь я печатаю {$foo->bar[1]}.
Это не должно вывести заглавную 'A': \x41]]>
Пример со статичными данными
]]>
Синтаксический анализ переменных
PHP обрабатывает переменные
внутри строки, если строку указали в двойных кавычках или heredoc-синтаксисом.
В PHP предусмотрели два вида синтаксиса для указания переменных в строках:
простой и
сложный.
Простым синтаксисом пользуются чаще, с ним легко
встраивать переменную, значение массива (array) или
свойство объекта (object) с минимумом усилий.
Сложный синтаксис легко определить по фигурным скобкам, которые окружают выражение.
Простой синтаксис
Если интерпретатор встречает знак доллара ($), он захватывает
как можно больше символов, чтобы сформировать правильное имя переменной.
Имя переменной берут в фигурные скобки, если нужно точно определить конец имени.
]]>
&example.outputs;
Аналогично будет проанализирован индекс массива (array) или свойство
объекта (object). В индексах массива закрывающая квадратная скобка
(]) означает конец определения индекса. На свойства объекта
распространяются те же правила, что и на простые переменные.
Пример простого синтаксиса
"purple");
echo "He drank some $juices[0] juice.".PHP_EOL;
echo "He drank some $juices[1] juice.".PHP_EOL;
echo "He drank some $juices[koolaid1] juice.".PHP_EOL;
class people {
public $john = "John Smith";
public $jane = "Jane Smith";
public $robert = "Robert Paulsen";
public $smith = "Smith";
}
$people = new people();
echo "$people->john drank some $juices[0] juice.".PHP_EOL;
echo "$people->john then said hello to $people->jane.".PHP_EOL;
echo "$people->john's wife greeted $people->robert.".PHP_EOL;
echo "$people->robert greeted the two $people->smiths."; // Не сработает
?>
]]>
&example.outputs;
В PHP 7.1.0 добавлена поддержка отрицательных
числовых индексов.
Отрицательные числовые индексы
]]>
&example.outputs;
Для выражений, которые сложнее этих, лучше пользоваться сложным синтаксисом.
Сложный (фигурный) синтаксис
Он называется сложным не из-за сложности синтаксиса,
а только потому, что разрешает писать сложные выражения.
Скалярная переменная, элемент массива или отображаемое в строку свойство объекта
разрешено указывать в строке этим синтаксисом. Выражение записывается
как и вне строки, а затем берётся в фигурные скобки: { и }.
Поскольку знак { невозможно экранировать, этот синтаксис будет
распознаваться только тогда, когда знак $ идёт непосредственно за знаком {.
Чтобы получить литерал {$, знак доллара экранируют {\$.
Поясняющие примеры:
width}00 сантиметров.";
// Работает, ключи, взятые в кавычки, работают только с синтаксисом фигурных скобок
echo "Это работает: {$arr['key']}";
// Работает
echo "Это работает: {$arr[4][3]}";
// Следующая запись неверна по той же причине, по которой запись $foo[bar] неверна вне строки.
// Сначала PHP ищет константу foo и выбрасывает ошибку, если не находит.
// PHP, если найдёт константу, будет использовать как индекс массива
// значение константы, а не само «foo»
echo "Это неправильно: {$arr[foo][3]}";
// Работает. При обращении к многомерным массивам внутри
// строк указывают фигурные скобки
echo "Это работает: {$arr['foo'][3]}";
// Работает.
echo "Это работает: " . $arr['foo'][3];
echo "Это тоже работает: {$obj->values[3]->name}";
echo "Это значение переменной с именем $name: {${$name}}";
echo "Это значение переменной с именем, которое возвращает функция getName(): {${getName()}}";
echo "Это значение переменной с именем, которое возвращает \$object->getName(): {${$object->getName()}}";
// Не работает, выводит: Это то, что возвращает функция getName(): {getName()}
echo "Это то, что возвращает функция getName(): {getName()}";
// Не работает, выводит: C:\folder\{fantastic}.txt
echo "C:\folder\{$great}.txt"
// Работает, выводит: C:\folder\fantastic.txt
echo "C:\\folder\\{$great}.txt"
?>
]]>
Через переменные внутри строк, которые записали таким синтаксисом,
доступны свойства класса.
$bar}\n";
echo "{$foo->{$baz[1]}}\n";
?>
]]>
&example.outputs;
Значение внутри литерала {$}, к которому получают доступ из функций,
вызовов методов, статических переменных класса и констант класса, интерпретируется как имя
переменной в области, в которой определена строка. Синтаксис
одинарных фигурных скобок ({}) не будет работать
для доступа к значениям функций, методов,
констант классов или статических переменных класса.
]]>
Доступ и изменение символа в строке
Чтобы получить доступ и изменить символ в строке,
нужно в квадратных скобках после переменной определить смещение искомого символа
относительно начала строки начиная с нуля, например, $str[42].
Для этого о строке думают как о массиве символов.
Чтобы получить или заменить больше одного символа, вызывают
функции substr и substr_replace.
Начиная с PHP 7.1.0 поддерживаются отрицательные значения смещения.
Они задают смещение с конца строки. Раньше отрицательные смещение вызывали
ошибку уровня E_NOTICE при чтении (возвращая пустую строку)
или E_WARNING при записи (оставляя строку без изменений).
До PHP 8.0.0 доступ к символам в строках (string) получали,
указывая фигурные скобки, например $str{42}.
Синтаксис фигурных скобок устарел с PHP 7.4.0 и не поддерживается с PHP 8.0.0.
Попытка записи в смещение за границами строки дополнит строку
пробелами до этого смещения. Нецелочисленные типы преобразуются в целочисленные.
Неверный тип смещения выдаст ошибку уровня E_WARNING.
При добавлении в смещение строки новых символов присвоится только первый символ (байт).
Начиная с PHP 7.1.0 присваивание пустой строки вызовет фатальную ошибку. Раньше
присваивался нулевой байт (NULL).
Внутренне строки PHP представлены массивами байтов. Поэтому
доступ или изменение строки по смещению небезопасны для многобайтовых данных
и выполняются только со строками в однобайтных кодировках,
например ISO-8859-1.
Начиная с PHP 7.1.0 попытка указать оператор пустого индекса
на пустой строке выдаст фатальную ошибку.
Раньше пустая строка преобразовывалась в массив без предупреждения.
Примеры строк
]]>
Смещение в строке задают либо целым числом, либо целочисленной строкой,
иначе PHP выдаст предупреждение.
Пример недопустимого смещения строки
]]>
&example.outputs;
Доступ к переменным других типов (не включая массивы, а также
объекты, реализующие соответствующие интерфейсы) через операторы []
или {} без предупреждения возвращает &null;.
Доступ к символам в строковых литералах получают
через операторы [] или {}.
Доступ к символам в строковых литералах
через оператор {} объявлен устаревшим в PHP 7.4
и удалён в PHP 8.0.
Полезные функции и операторы
Строки разрешено объединять оператором «.» (точка).
Обратите внимание, оператор сложения «+» здесь не работает.
Подробнее об этом рассказано в разделе
«Строковые операторы».
В языке предусмотрен ряд полезных функций для манипулирования строками.
Общие функции описаны в разделе
«Функции для работы со строками», а для расширенного поиска
и замены — «Функции Perl-совместимых регулярных выражений».
Предусмотрены также функции для работы с URL
и функции шифрования или дешифрования строк (Sodium и Hash).
Наконец, смотрите также
функции символьных типов.
Преобразование в строку
Значение преобразовывают в строку приведением
через оператор (string) или функцией strval.
В выражениях, в которых требуется строка, преобразование выполняется автоматически.
Это выполняется во время вывода через языковые конструкции echo
или print, либо когда значение переменной сравнивается
со строкой. Разделы руководства
«Типы»
и «Манипуляции с типами»,
прояснят сказанное ниже. Смотрите также описание функции settype.
Значение bool &true; преобразовывается в строку
«1», а логическое значение &false; преобразовывается
в «» (пустую строку). Такое поведение допускает преобразование значения
в обе стороны — из логического типа в строковый и наоборот.
Целое число (int) или число с плавающей точкой
(float) преобразовывается в строку, которая будет представлять число в текстовом виде
(включая экспоненциальную часть для чисел с плавающей точкой).
Большие числа с плавающей точкой преобразовываются в экспоненциальную запись (4.1E+6).
Начиная с PHP 8.0.0 в качестве разделителя дробной части в числах
с плавающей точкой разрешено использовать только точку («.»).
До PHP 8.0.0 символ десятичной точки определялся в настройках языкового стандарта скрипта
(категория LC_NUMERIC). Смотрите функцию setlocale.
Массивы преобразовываются в строку «Array».
Поэтому конструкции echo или print
не умеют без помощи функций отображать содержимое массива (array).
Чтобы просмотреть отдельный элемент, пользуются
синтаксисом echo $arr['foo']. Ниже будет рассказано о том,
как отобразить или просмотреть всё содержимое.
Для преобразования объекта (object) в строку (string)
определяют магический метод
__toString.
Ресурс (resource) преобразовывается в строку (string) вида
«Resource id #1», где 1 —
это номер ресурса, который PHP назначает ресурсу (resource) во время исполнения кода.
И хотя она уникальна для текущего запуска скрипта (т. е. веб-запроса или
CLI-процесса) и не будет использована повторно для этого ресурса,
не стоит полагаться на эту строку, потому что её могут изменить в будущем.
Тип ресурса можно получить вызовом функции get_resource_type.
Значение &null; всегда преобразовывается в пустую строку.
Как указано выше, прямое преобразование в строку массивов, объектов
или ресурсов не даёт полезной информации о значении, кроме типа.
Более эффективные инструменты вывода значений для отладки этих типов — это функции
print_r и var_dump.
Бо́льшая часть значений в PHP преобразуема в строку для постоянного
хранения. Этот метод преобразования называется сериализацией. Сериализуют значения
функцией serialize.
Подробные сведения о строковом типе
Строковый тип (string) в PHP реализован в виде массива
байтов и целочисленного значения, содержащего длину буфера. В этой структуре
нет информации о том, как преобразовывать байты в символы,
эту задачу решает программист. Нет ограничений на значения, из которых состоит строка,
например, байт со значением 0 (NUL-байт) разрешён
где угодно в строке (однако рекомендовано учитывать, что ряд функций,
которые в этом руководстве названы «бинарно-небезопасными»,
передают строки библиотекам, которые игнорируют
данные после NUL-байта).
Такая природа строкового типа объясняет, почему в PHP нет отдельного
типа «byte» — строки выполняют эту роль. Функции, которые не возвращают текстовых данных, —
например, произвольный поток данных, считываемый из сетевого сокета, —
по-прежнему возвращают строки.
С учётом того, что PHP не диктует конкретную кодировку
для строк, может возникнуть вопрос: Как тогда кодируются строковые
литералы? Например, строка «á» эквивалентна
«\xE1» (ISO-8859-1), «\xC3\xA1»
(UTF-8, форма нормализации C), «\x61\xCC\x81»
(UTF-8, форма нормализации D) или другому возможному
представлению? Ответ такой: строка будет закодирована
способом, которым она закодирована в файле скрипта. Поэтому, если
скрипт записан в кодировке ISO-8859-1, то и строка будет закодирована в
ISO-8859-1 и т. д. Однако это правило не выполняется при включённом
режиме Zend Multibyte: скрипт записывают в произвольной
кодировке, объявляя её или полагаясь на автоопределение,
а затем конвертируют в конкретную внутреннюю кодировку, которая и будет
использована для строковых литералов.
Учтите, что на кодировку скрипта (или на внутреннюю кодировку, если
включён режим Zend Multibyte) накладывается ряд ограничений:
почти в каждом случае эта кодировка должна быть надмножеством кодировки ASCII,
например, UTF-8 или ISO-8859-1. Учтите также, что кодировки, зависящие
от состояния, где одни и те же значения байтов допустимы
в начальном и не начальном состоянии сдвига, создают риск проблем.
Строковые функции, чтобы быть полезными, пробуют предположить кодировку строки.
Единство в этом вопросе не помешало бы, но PHP-функции работают с текстом по-разному:
Одни — предполагают, что строка закодирована в какой-то
однобайтовой кодировке, но для корректной работы
им не нужно интерпретировать байты как конкретные символы.
Сюда попадают функции вроде substr,
strpos, strlen
и strcmp. Другой способ мышления об этих функциях —
представлять, что они оперируют буферами памяти, т. е. работают
непосредственно с байтами и их смещениями.
Другим — передаётся кодировка строки или они принимают
значение по умолчанию, если кодировку не передали.
Это относится к функции htmlentities
и большей части функций модуля mbstring.
Третьи — работают с текущими настройками локали (смотрите
setlocale), но оперируют побайтово.
Наконец четвёртые — предполагают, что строка использует
конкретную кодировку, обычно UTF-8. Сюда попадает бо́льшая часть
функций из модулей intl
и PCRE
(для последнего — только при указании модификатора u).
В конечном счёте, программа будет работать с кодировкой Unicode правильно,
если старательно избегать функций,
которые не будут работать с Unicode-строками или повредят данные, и вызывать вместо них те,
которые ведут себя корректно, обычно это функции из модулей intl
и mbstring.
Однако работа с функциями, которые умеют обрабатывать Unicode, —
это только начало. Независимо от того, какие функции предлагает
язык, рекомендовано знать спецификацию Unicode. Например, программа,
которая предполагает существование только прописных и строчных букв,
делает неверное предположение.