Строка в PHP это последовательность байтов без знания о кодировке. Отсюда главный вопрос собеса: почему strlen("привет") равно 12 и как работать с UTF-8.
Байты и символы
strlen("привет"); // 12: в UTF-8 кириллица по 2 байта
mb_strlen("привет"); // 6
substr("Ёжик", 0, 3); // битая строка: полтора символа
mb_substr("Ёжик", 0, 3); // "Ёжи"
strtoupper("ёж"); // "ёж": с PHP 8.2 меняет только ASCII
mb_strtoupper("ёж"); // "ЁЖ"
Для пользовательского текста используйте mb_*: mb_strlen, mb_substr, mb_strtolower, mb_str_split. В регулярных выражениях модификатор u: preg_match('/^\p{L}+$/u', $name).
Кавычки, heredoc и nowdoc
'текст $x': буквально, только\'и\\."текст $x\n": подстановка переменных и escape-последовательности."{$user['name']}","{$obj->prop}": сложные выражения в фигурных скобках.- heredoc
<<<EOTведёт себя как двойные кавычки, nowdoc<<<'EOT'как одинарные.
Поиск
Классическая ловушка:
if (!strpos($s, "a")) { ... } // неверно, если "a" в позиции 0
if (strpos($s, "a") === false) { ... }
if (!str_contains($s, "a")) { ... } // PHP 8.0
Есть ещё str_starts_with и str_ends_with. Они возвращают bool и не страдают от позиции 0.
Разбиение и сборка
explode(",", "a,,b,"); // ["a", "", "b", ""]: пустые элементы остаются
implode(", ", $names);
preg_split('/\s+/', trim($text));
str_pad("7", 3, "0", STR_PAD_LEFT); // "007"
sprintf("%05.2f", 3.14159); // "03.14"
number_format(1234.5, 2, ".", " "); // "1 234.50"
Сравнение без учёта регистра
strcasecmp и strtolower работают по ASCII. Для кириллицы mb_strtolower($a) === mb_strtolower($b), для сортировки по правилам языка Collator из intl.
Как PHP хранит строки
zend_string хранит длину, хеш и счётчик ссылок. Присваивание не копирует данные (copy-on-write), литералы интернируются. Склейка .= в цикле обычно недорога, но гигабайтный файл через file_get_contents упрётся в memory_limit: большие данные читают потоково (fgets, SplFileObject, генераторы).
Экранирование по контексту
- HTML:
htmlspecialchars($s, ENT_QUOTES, 'UTF-8'). - URL:
rawurlencode,http_build_query. - Shell:
escapeshellarg. - SQL: только подготовленные запросы.
Частые ошибки
strlen,substr,ucfirstдля кириллицы.strpos(...) == false.explodeи ожидание, что пустых элементов не будет.- Регулярки без
uдля UTF-8.
Что спросят на собесе
- Почему
strlenдля кириллицы возвращает больше, чем символов? - Чем одинарные кавычки отличаются от двойных, heredoc от nowdoc?
- В чём ловушка
strposи что появилось в PHP 8? - Как правильно экранировать строку для HTML, URL и shell?