Строки
Строка (string) — набор символов, в котором символ — то же,
что и байт. PHP поддерживает набор только из 256 символов и поэтому
внутренне не поддерживает кодировку Unicode. Подробнее об этом рассказывает раздел
«Подробные сведения о строковом типе».
В 32-битных сборках размер строки (string) ограничивается 2 ГБ — максимум 2 147 483 647 байтов.
Синтаксис
Строковый литерал определяют четырьмя способами:
одинарными кавычками
двойными кавычками
heredoc-синтаксисом
nowdoc-синтаксисом
Одинарные кавычки
Простейший способ определить строку — заключить строку в одинарные кавычки —
символ '.
Буквальную одинарную кавычку при записи в строке экранируют обратным
слешем — \. Сам обратный слеш дублируют —
\\. В остальных случаях обратный слеш в одинарных кавычках
обрабатывется как буквальный обратный слеш: PHP не рассматривает последовательности
вроде \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;
PHP выбросит исключение ParseError,
если закрывающий идентификатор сместили дальше хотя бы одной строки тела:
Идентификатору закрытия нельзя отступать дальше строк тела
]]>
&example.outputs.73;
В теле и перед идентификатором окончания heredoc-блока разрешается делать отступы
символами пробелов и табуляции, но нельзя смешивать символы
табуляции и пробелы относительно отступа идентификатора закрытия и отступа тела
до начала закрывающего идентификатора; heredoc-синтаксис будет работать с отступом перед маркером закрытия,
только если каждая строка тела начинается, но не ограничивается, с того же отступа,
что и отступ перед маркером закрытия. При несовпадении отступов в начале строк тела с отступом
перед идентификатором закрытия PHP выбросит исключение 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 умеет подставлять внутри строк значения вместо переменных,
если строку (string) указали в двойных кавычках или heredoc-синтаксисом.
В PHP предусмотрели два вида синтаксиса для указания переменных в строках:
базовый
и продвинутый.
Базовым синтаксисом пользуются чаще, им легко
встраивать переменную, значение массива (array)
или свойство объекта (object) с минимумом усилий.
Базовый синтаксис
PHP интерпретирует как переменную и подставит вместо переменной значение этой переменной,
если встретит в строке знак доллара $,
за которым идут символы, из которых PHP разрешает составлять название переменной.
]]>
&example.outputs;
Формально структура базового синтаксиса подстановки переменных
выглядит вот так:
имя
имя-переменной::
$ имя
имя::
[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*
]]>
Синтаксис ${ выражение } устарел
с PHP 8.2.0, поскольку интерпретируется
как переменные переменных:
]]>
&example.outputs.82;
&example.outputs;
Вместо этого пользуются
продвинутым
синтаксисом интерполяции строк.
Знак доллара остается в строке как сам знак доллара,
если невозможно сформировать допустимое имя:
]]>
&example.outputs;
Пример интерполяции значений первого уровня массива или свойства объекта
"фиолетового");
echo "Он выпил немного $juices[0] сока.";
echo PHP_EOL;
echo "Он выпил немного $juices[1] сока.";
echo PHP_EOL;
echo "Он выпил немного $juices[string_key] сока.";
echo PHP_EOL;
class A
{
public $s = "string";
}
$o = new A();
echo "Значение свойства объекта: $o->s.";
?>
]]>
&example.outputs;
Ключ массива указывают без кавычек, поэтому невозможно
ссылаться на константу как на ключ в базовом синтаксисе. Вместо этого пользуются
продвинутым
синтаксисом.
В PHP 7.1.0 добавили поддержку отрицательных
числовых индексов.
Отрицательные числовые индексы
]]>
&example.outputs;
Для выражений, которые сложнее этих, лучше пользоваться
продвинутым
синтаксисом.
Продвинутый, или фигурный, синтаксис
Продвинутый синтаксис разрешает интерполировать
переменные с произвольными методами доступа.
В строках продвинутым синтаксисом указывают скалярные переменные, элементы массива,
статические и динамические свойства объекта со строковым представлением.
Выражение записывается как и вне строки, а затем оборачивается
в фигурные скобки { и }.
Поскольку знак { невозможно экранировать, продвинутый синтаксис
распознаётся только тогда, когда знак $ идёт непосредственно за знаком {.
Знак доллара экранируют синтаксисом {\$, чтобы получить литерал {$.
Поясняющие примеры:
'Индексное значение',
'const-key' => 'Ключ со знаком минуса',
'foo' => ['foo1', 'foo2', 'foo3']
];
// Не работает, выводит: Это { здорово}
echo "Это { $great}";
// Работает, выводит: Это здорово
echo "Это {$great}";
class Square
{
public $width;
public function __construct(int $width)
{
$this->width = $width;
}
}
$square = new Square(5);
// Работает
echo "Ширина квадрата составляет {$square->width}00 сантиметров.";
// Работает, ключи, взятые в кавычки, работают только с синтаксисом фигурных скобок
echo "Это работает: {$arr['key']}";
// Работает
echo "Это работает: {$arr[3][2]}";
echo "Работает: {$arr[DATA_KEY]}";
// При работе с многомерными массивами массивы внутри строк оборачивают в фигурные скобки
echo "Это работает: {$arr['foo'][2]}";
echo "Работает: {$obj->values[3]->name}";
echo "Работает: {$obj->$staticProp}";
// Не работает, выводит: C:\directory\{fantastic}.txt
echo "C:\directory\{$great}.txt";
// Работает, выводит: C:\directory\fantastic.txt
echo "C:\\directory\\{$great}.txt";
?>
]]>
В строках с продвинутым синтаксисом возможно записывать
переменные переменных,
поскольку продвинутый синтаксис разрешает произвольные выражения.
Доступ к символам и изменение символов в строке
Символы внутри строк индексируются с начала строки, индексы начинаются с 0.
Смещение символа, который требуется прочитать или изменить внутри строки,
указывают после строки в квадратных скобках массива (array),
например $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-совместимых регулярных выражений».
В PHP также предусмотрели функции для работы с 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. Например, программа,
которая предполагает существование только прописных и строчных букв,
делает неверное предположение.