14 вопросов
Строка в PHP - это массив байтов плюс длина. Внутренне это zend_string структура: refcount, хеш (для использования как ключ массива), длина и данные. Строки не null-terminated для пользователя, но имеют завершающий null для совместимости с C.
PHP строки не имеют внутренней кодировки - это просто байты. Для работы с UTF-8 используются функции mb_*.
Нет, строки в PHP мутабельны - можно изменять отдельные байты по индексу:
$s = "hello";
$s[0] = 'H';
echo $s; // "Hello"Однако благодаря copy-on-write присваивание строки другой переменной не создает копию до первой модификации. Это отличие от Go и Java, где строки иммутабельны.
Для единичных операций оператор . достаточен. Для конкатенации в цикле:
// Плохо: O(n^2) из-за создания новых строк
$result = '';
foreach ($items as $item) {
$result .= $item; // каждый раз копирование
}
// Лучше: собрать в массив, затем implode
$parts = [];
foreach ($items as $item) {
$parts[] = $item;
}
$result = implode('', $parts);implode() эффективнее для больших объемов: рассчитывает итоговый размер, выделяет память один раз.
При каждой итерации PHP может выделять новый блок памяти и копировать всю строку + новую часть. Это приводит к квадратичной сложности O(n^2) по памяти и времени.
На практике PHP оптимизирует случай, когда у строки refcount=1 (единственная ссылка) - тогда память расширяется через realloc без копирования. Но если строка имеет другие ссылки, произойдет полное копирование.
Для большого количества итераций (1000+) implode() с массивом или sprintf() предпочтительнее.
strlen() возвращает количество байтов, mb_strlen() - количество символов:
$s = "Привет";
echo strlen($s); // 12 (6 символов x 2 байта в UTF-8)
echo mb_strlen($s, 'UTF-8'); // 6Для ASCII-строк результат одинаковый. Для UTF-8 текста с кириллицей, иероглифами, эмодзи - всегда используйте mb_strlen().
Расширение mbstring предоставляет функции для работы с многобайтовыми кодировками:
mb_strlen($str, 'UTF-8');
mb_substr($str, 0, 5, 'UTF-8');
mb_strtolower($str, 'UTF-8');
mb_strpos($str, $needle, 0, 'UTF-8');
mb_detect_encoding($str);
mb_convert_encoding($str, 'UTF-8', 'Windows-1251');Установите mb_internal_encoding('UTF-8') или default_charset = "UTF-8" в php.ini, чтобы не указывать кодировку каждый раз.
UTF-8 - кодировка Unicode переменной длины: ASCII-символы занимают 1 байт, кириллица - 2 байта, иероглифы - 3 байта, эмодзи - 4 байта.
PHP строки - просто массивы байтов без привязки к кодировке. Стандартные функции (strlen, substr, strpos) работают с байтами. Для корректной работы с UTF-8 нужны mb_* функции.
С PHP 8.2 многие стандартные функции стали корректно работать с UTF-8 (например, strtolower для ASCII). Для полной поддержки Unicode используйте расширение intl (ICU).
// Строка -> число
$n = (int)"42abc"; // 42
$n = intval("0xFF", 16); // 255
$n = (float)"3.14"; // 3.14
$n = "42" + 0; // 42 (жонглирование)
// Число -> строка
$s = (string)42; // "42"
$s = strval(3.14); // "3.14"
$s = "$n"; // интерполяция
$s = number_format(1234.5, 2, '.', ','); // "1,234.50"
$s = sprintf("%05d", 42); // "00042"Основные группы:
Регулярные выражения (regex) - шаблоны для поиска и замены в строках. PHP использует PCRE (Perl Compatible Regular Expressions):
// Поиск
preg_match('/^[a-z]+$/i', $str, $matches);
// Все совпадения
preg_match_all('/\d+/', $str, $matches);
// Замена
$result = preg_replace('/\s+/', ' ', $str);
// Замена с callback
$result = preg_replace_callback('/\{(\w+)\}/', function($m) {
return $vars[$m[1]] ?? $m[0];
}, $template);
// Разделение
$parts = preg_split('/[,;\s]+/', $str);Всегда проверяйте результат на false (ошибка компиляции regex). Используйте preg_last_error() для диагностики.
Heredoc (<<<LABEL) - многострочная строка с интерполяцией переменных, как двойные кавычки. Nowdoc (<<<'LABEL') - без интерполяции, как одинарные кавычки.
$name = "World";
// Heredoc - переменные подставляются
$html = <<<HTML
<p>Hello, $name</p>
HTML;
// Nowdoc - всё буквально
$code = <<<'PHP'
echo $name; // $name не подставляется
PHP;С PHP 7.3 закрывающий маркер можно ставить с отступом.
// sprintf - возвращает отформатированную строку
$msg = sprintf("User %s has %d points (%.2f%%)", $name, $pts, $pct);
// printf - сразу выводит
printf("%05d", 42); // "00042"
// number_format - форматирование чисел
echo number_format(1234567.891, 2, '.', ','); // "1,234,567.89"
// vsprintf - принимает массив аргументов
$msg = vsprintf("ID: %d, Name: %s", [42, 'John']);Спецификаторы: %s (строка), %d (целое), %f (float), %x (hex), %b (binary), %e (научная нотация), %% (литерал %).
// Для HTML - защита от XSS
$safe = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
// < > " ' & заменяются на HTML-сущности
// htmlentities - больше символов
$safe = htmlentities($input, ENT_QUOTES, 'UTF-8');
// Для URL
$encoded = urlencode("hello world"); // "hello+world"
$encoded = rawurlencode("hello world"); // "hello%20world"
// Для SQL - НЕ ИСПОЛЬЗУЙТЕ!
// addslashes() - небезопасно
// Используйте prepared statementsГлавное правило: экранируйте данные в контексте использования - HTML, URL, SQL, JSON, командная строка.
В PHP нет прямого аналога Go bytes.Buffer. Ближайшие аналоги:
// 1. implode - собрать массив строк
$parts = [];
$parts[] = "Hello";
$parts[] = " ";
$parts[] = "World";
$result = implode('', $parts);
// 2. Буферизация вывода
ob_start();
echo "Hello ";
echo "World";
$result = ob_get_clean();
// 3. php://memory (SplTempFileObject)
$buffer = fopen('php://memory', 'r+');
fwrite($buffer, 'Hello ');
fwrite($buffer, 'World');
rewind($buffer);
$result = stream_get_contents($buffer);Для большинства задач implode() с массивом - оптимальный выбор.