PHP: Строки

14 вопросов

1 Как устроены строки в PHP?

Строка в PHP - это массив байтов плюс длина. Внутренне это zend_string структура: refcount, хеш (для использования как ключ массива), длина и данные. Строки не null-terminated для пользователя, но имеют завершающий null для совместимости с C.

PHP строки не имеют внутренней кодировки - это просто байты. Для работы с UTF-8 используются функции mb_*.

Открыть отдельно →
2 Являются ли строки иммутабельными?

Нет, строки в PHP мутабельны - можно изменять отдельные байты по индексу:

$s = "hello";
$s[0] = 'H';
echo $s; // "Hello"

Однако благодаря copy-on-write присваивание строки другой переменной не создает копию до первой модификации. Это отличие от Go и Java, где строки иммутабельны.

Открыть отдельно →
3 Как эффективно конкатенировать строки?

Для единичных операций оператор . достаточен. Для конкатенации в цикле:

// Плохо: O(n^2) из-за создания новых строк
$result = '';
foreach ($items as $item) {
    $result .= $item; // каждый раз копирование
}

// Лучше: собрать в массив, затем implode
$parts = [];
foreach ($items as $item) {
    $parts[] = $item;
}
$result = implode('', $parts);

implode() эффективнее для больших объемов: рассчитывает итоговый размер, выделяет память один раз.

Открыть отдельно →
4 Что произойдет при конкатенации оператором .= в цикле?

При каждой итерации PHP может выделять новый блок памяти и копировать всю строку + новую часть. Это приводит к квадратичной сложности O(n^2) по памяти и времени.

На практике PHP оптимизирует случай, когда у строки refcount=1 (единственная ссылка) - тогда память расширяется через realloc без копирования. Но если строка имеет другие ссылки, произойдет полное копирование.

Для большого количества итераций (1000+) implode() с массивом или sprintf() предпочтительнее.

Открыть отдельно →
5 Как определить длину строки? (strlen vs mb_strlen)

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().

Открыть отдельно →
6 Как работать с многобайтовыми строками? (mbstring)

Расширение 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, чтобы не указывать кодировку каждый раз.

Открыть отдельно →
7 Что такое кодировка UTF-8? Как PHP работает с Unicode?

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).

Открыть отдельно →
8 Как преобразовать строку в число и обратно?
// Строка -> число
$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"
Открыть отдельно →
9 Какие функции для работы со строками есть в стандартной библиотеке?

Основные группы:

  • Поиск: strpos, strrpos, strstr, str_contains (8.0), str_starts_with (8.0), str_ends_with (8.0)
  • Замена: str_replace, str_ireplace, substr_replace, preg_replace
  • Разделение: explode, str_split, strtok, preg_split
  • Объединение: implode (join)
  • Регистр: strtolower, strtoupper, ucfirst, lcfirst, ucwords
  • Обрезка: trim, ltrim, rtrim
  • Подстрока: substr, mb_substr
  • Форматирование: sprintf, printf, number_format
  • Хеширование: md5, sha1, hash, crc32
  • Кодирование: base64_encode/decode, urlencode/decode, htmlspecialchars
Открыть отдельно →
10 Что такое регулярные выражения?

Регулярные выражения (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() для диагностики.

Открыть отдельно →
11 Что такое heredoc и nowdoc?

Heredoc (<<<LABEL) - многострочная строка с интерполяцией переменных, как двойные кавычки. Nowdoc (<<<'LABEL') - без интерполяции, как одинарные кавычки.

$name = "World";

// Heredoc - переменные подставляются
$html = <<<HTML
<p>Hello, $name</p>
HTML;

// Nowdoc - всё буквально
$code = <<<'PHP'
echo $name; // $name не подставляется
PHP;

С PHP 7.3 закрывающий маркер можно ставить с отступом.

Открыть отдельно →
12 Как форматировать строки?
// 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 (научная нотация), %% (литерал %).

Открыть отдельно →
13 Как экранировать специальные символы?
// Для 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, командная строка.

Открыть отдельно →
14 Чем bytes.Buffer аналог? (implode для массивов, конкатенация)

В 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() с массивом - оптимальный выбор.

Открыть отдельно →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.