Menu

Вопросы на собеседовании по PHP и ответы (PHP 8)

24 вопроса на собеседовании по PHP с короткими правильными ответами для PHP 8: от == и === и isset и empty до ссылок в foreach, self и static, генераторов, SQL-инъекций и хеширования паролей. У большинства ответов есть код, который можно запустить и изменить.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Это вопросы по PHP, которые чаще всего встречаются на собеседованиях, с короткими ответами, верными для PHP 8.3, и кодом там, где код нагляднее. Предскажите вывод каждого блока до нажатия Run: именно это и проверяет интервьюер.

Вопросы по PHP для начинающих

Что такое PHP и как он работает?

PHP это серверный скриптовый язык. Веб-сервер (Nginx или Apache) передаёт запрос в PHP (обычно PHP-FPM), PHP выполняет скрипт сверху, а всё, что он напечатал, становится ответом, обычно HTML. Каждый запрос начинается заново: переменные не переживают переход между запросами, если не сохранить их в сессии, базе данных или кеше. PHP также запускает скрипты из командной строки (php script.php).

Чем == отличается от ===?

== сравнивает после приведения типов, === сравнивает значение и тип без преобразования. Разминка выше показывает работу ==: числовые строки сравниваются как числа, поэтому '10' == '1e1' даёт true. Начиная с PHP 8 число, сравниваемое с нечисловой строкой, сравнивается как строка, поэтому 0 == 'a' даёт false (в PHP 7 было true). Нажимайте на ячейки, чтобы сравнить оба оператора:

Нестрогое (==) и строгое (===) сравнение
Point at or tap a cell to read it as PHP.
$a == $btruefalse01"0""1"""null[]"a""10""1e1"
true
false
0
1
"0"
"1"
""
null
[]
"a"
"10"
"1e1"
Every cell computed by PHP 8.3.19.

По умолчанию используйте ===. in_array() и array_search() используют ==, если не передать true третьим аргументом.

Чем echo отличается от print?

Оба выводят строки. echo принимает несколько аргументов (echo $a, $b;) и ничего не возвращает; print принимает один и возвращает 1, поэтому может стоять в выражении. Ни то, ни другое не функция, поэтому скобки необязательны. На практике все используют echo.

Одинарные или двойные кавычки?

Строки в двойных кавычках подставляют переменные и обрабатывают escape-последовательности: "Hi $name\n". Строки в одинарных кавычках буквальны, кроме \' и \\: 'Hi $name\n' выводит ровно эти символы. Разница в скорости ничтожна, поэтому выбор дело читаемости: двойные кавычки, когда подставляете значения, одинарные, когда нет.

Какие типы данных есть в PHP?

Четыре скалярных типа (int, float, string, bool), два составных (array и object) и два специальных (null и resource). callable, iterable, mixed и void существуют только как объявления типов и никогда как тип значения. gettype() и get_debug_type() сообщают тип значения во время выполнения, а var_dump() печатает его вместе со значением.

Чем отличаются isset, empty и is_null?

isset($x) даёт true, когда переменная существует и не равна null. empty($x) даёт true, когда переменной нет или она ложна (0, '0', '', [], false, null). is_null($x) даёт true для null, но предупреждает о неопределённой переменной. isset и empty никогда не предупреждают, поэтому их применяют к ключам массивов.

isset, empty и is_null для каждого значения $x
Point at or tap a cell to read it as PHP.
$xissetemptyis_null
null
false
0
"0"
""
" "
[]
"a"
0.0
Every cell computed by PHP 8.3.19.

Строка, в которой чаще всего ошибаются, это "0": строка ноль пуста, а " " (пробел) нет. Полная таблица на странице про isset.

Чем include отличается от require?

Оба вставляют и выполняют другой файл. Если файла нет, include выдаёт предупреждение, и скрипт продолжает работу, а require выбрасывает Error ("Failed opening required"), который останавливает скрипт, если его никто не перехватит. Варианты _once (include_once, require_once) пропускают уже загруженный файл, что предотвращает ошибки "cannot redeclare function". Используйте require (или require_once) для файлов, без которых скрипт не может работать, а это почти все; автозагрузчик Composer делает большинство ручных подключений ненужными.

Чем GET отличается от POST?

GET передаёт данные в строке запроса URL ($_GET), поэтому они видны, сохраняются в закладках и ограничены по длине; используйте его для чтения, например поиска и пагинации. POST передаёт данные в теле запроса ($_POST); используйте его для всего, что меняет состояние: вход, сохранение, платежи. GET-запрос никогда не должен менять данные, потому что ссылки заранее загружаются и обходятся краулерами.

Что такое оператор объединения с null?

$a ?? $b возвращает $a, если оно существует и не равно null, иначе $b, без предупреждения о неопределённой переменной или ключе: $page = $_GET['page'] ?? 1;. ??= присваивает, только когда левая часть равна null или отсутствует. Он отличается от ?:, который берёт запасное значение для любого ложного значения, поэтому 0 ?: 5 даёт 5, а 0 ?? 5 даёт 0.

Вопросы по PHP среднего уровня

Что происходит при обходе по ссылке в foreach?

foreach ($arr as &$v) позволяет менять элементы на месте, но после цикла $v остаётся ссылкой на последний элемент. Повторное использование имени во втором цикле перезаписывает этот элемент:

Последний элемент равен 20, а не 30: во втором цикле $v (всё ещё $arr[2]) получает 10, потом 20, потом сам себя. Уберите // перед unset($v) и запустите снова. Ссылки подробно разобраны на странице про foreach.

Чем абстрактный класс отличается от интерфейса? И что такое трейт?

Интерфейс это контракт: сигнатуры методов (и константы) без реализации, и класс может реализовать много интерфейсов. Абстрактный класс может содержать свойства, конструкторы и готовые методы плюс абстрактные методы, которые должны написать его потомки; класс наследует только один. Трейт это набор методов, копируемый в класс через use, чтобы переиспользовать код в классах без общего родителя.

Короткий ответ, который нравится интервьюерам: интерфейс говорит, что объект умеет делать, абстрактный класс делится тем, как это делается, а трейт нужен, когда несвязанным классам нужны одни и те же несколько методов.

Чем self отличается от static?

self указывает на класс, в котором написан код. static указывает на класс, который на самом деле вызван во время выполнения, это называется поздним статическим связыванием. Это важно в родительских методах, которые создают или описывают "объект такого вида":

User::createStatic() строит User. User::createSelf() строит Model, а это нарушает тип возвращаемого значения static, поэтому PHP выбрасывает TypeError. Вот почему фабричные методы используют new static().

Что такое магические методы?

Методы, которые PHP вызывает за вас, все они начинаются с двух подчёркиваний. Распространённые: __construct() при создании объекта, __destruct() при его уничтожении, __toString() при использовании как строки, __get() и __set() для недоступных свойств, __call() и __callStatic() для отсутствующих методов, __invoke(), когда объект вызывают как функцию, и __clone() после clone.

Чем array_merge() отличается от оператора +?

array_merge() дописывает: числовые ключи перенумеровываются, а более поздние строковые ключи перезаписывают более ранние. + это объединение: он сохраняет левый массив и добавляет только отсутствующие ключи, поэтому при повторяющемся ключе побеждает первое значение.

+ правильный инструмент для значений по умолчанию: $options + ['timeout' => 30] сохраняет то, что передал вызывающий код, и заполняет остальное.

Что делает declare(strict_types=1)?

Без него PHP приводит скалярные аргументы к объявленному типу параметра, когда может: передача "5" в параметр int даёт 5. С declare(strict_types=1); первой инструкцией файла вызовы из этого файла должны передавать точный тип, иначе выбрасывается TypeError (передача int в параметр float это единственное разрешённое расширение).

Удалите строку с declare и запустите снова: второй вызов вернёт 10, а не выбросит ошибку.

Cookie хранится в браузере и отправляется с каждым запросом, поэтому посетитель может её прочитать и изменить. Сессия хранит данные на сервере и держит в cookie только случайный ID (PHPSESSID). Всё, чему нужно доверять, например ID вошедшего пользователя, кладите в $_SESSION; после входа вызывайте session_regenerate_id(true). Код есть на странице о сессиях и cookie.

Как защититься от SQL-инъекций?

Никогда не собирайте SQL склейкой ввода. Используйте подготовленные запросы, чтобы значения отправлялись отдельно от запроса:

<?php
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();

Плейсхолдеры работают только для значений. Имена таблиц, столбцов и ASC/DESC нужно проверять по списку разрешённых, прежде чем вставлять их в SQL. Смотрите PDO.

Как защититься от XSS?

Экранируйте вывод, а не ввод: оборачивайте каждое значение, которое выводится в HTML, в htmlspecialchars($value, ENT_QUOTES, 'UTF-8') или используйте шаблонизатор, который делает это автоматически (Twig, Blade). Внутри <script> используйте json_encode() с JSON_HEX_TAG. Добавьте заголовок Content-Security-Policy как второй уровень защиты.

Как нужно хранить пароли?

Через password_hash($password, PASSWORD_DEFAULT) и проверять через password_verify($password, $hash). Они используют bcrypt (или Argon2id) со случайной солью, которая хранится внутри хеша, и намеренной сложностью (cost). md5() и sha1() не подходят для паролей, потому что они быстрые и без соли. Используйте password_needs_rehash() при входе, чтобы обновлять старые хеши.

Продвинутые вопросы по PHP

Что такое генераторы и когда их использовать?

Функция, содержащая yield, возвращает Generator, который выдаёт значения по одному и только по запросу. Это позволяет обходить большую или бесконечную последовательность, не строя массив в памяти:

Типичные применения: чтение большого файла построчно, потоковая выдача строк из базы данных и ленивые конвейеры. Генераторы поддерживают также ключи (yield $key => $value), делегирование (yield from) и получение значений через send().

Что такое замыкания и что делает use?

Анонимная функция (function () { ... }) это объект Closure. Она не видит внешние переменные, если не перечислить их в use, который копирует значение в момент создания замыкания; use (&$x) захватывает по ссылке. Стрелочные функции (fn ($x) => $x * $factor) захватывают внешние переменные автоматически, по значению, и содержат одно выражение.

Чем отличаются abstract, final и readonly?

abstract помечает класс, объект которого нельзя создать, или метод, который должен реализовать потомок. final запрещает переопределять метод или наследовать класс. readonly (PHP 8.1) делает свойство доступным для записи только один раз и только изнутри класса, обычно в конструкторе; в PHP 8.2 появились readonly-классы, где readonly каждое свойство.

Что такое Composer и что такое PSR-4?

Composer это менеджер зависимостей PHP: composer.json перечисляет пакеты, composer.lock фиксирует точные версии, а vendor/autoload.php загружает всё. PSR-4 это стандарт автозагрузки, который сопоставляет префикс пространства имён с папкой, поэтому App\Mail\Mailer лежит в src/Mail/Mailer.php и загружается при первом использовании. Объясните разницу между install (из lock-файла) и update (новые версии, новый lock-файл).

Что изменилось в PHP 8?

Главные возможности: в 8.0 именованные аргументы, match, nullsafe-оператор ?->, union-типы, продвижение свойств в конструкторе, атрибуты, str_contains() и более разумное сравнение строк с числами; в 8.1 перечисления, readonly-свойства, синтаксис first-class callable (strlen(...)) и файберы; в 8.2 readonly-классы и самостоятельные типы null/true/false; в 8.3 типизированные константы классов, атрибут #[\Override] и json_validate(); в 8.4 хуки свойств, асимметричная видимость (public private(set)), array_find() и new Foo()->method() без оборачивающих скобок. Многие функции теперь ещё и выбрасывают TypeError или ValueError, а не возвращают false с предупреждением.

Как PHP управляет памятью?

У каждого значения есть счётчик ссылок; когда он падает до нуля, память освобождается сразу. Объекты, которые ссылаются друг на друга по кругу, никогда не доходят до нуля, поэтому сборщик циклов запускается всякий раз, когда заполняется его буфер возможных корней циклов (по умолчанию 10 000 записей), и освобождает их (gc_collect_cycles() запускает его по требованию). Массивы и строки копируются при записи: присваивание $b = $a разделяет данные, пока одно из значений не изменится. Поскольку каждый запрос начинается и заканчивается чисто, утечки памяти важны в основном в долгоживущих воркерах и обработчиках очередей.

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

Массив PHP это упорядоченная хеш-таблица: он сохраняет порядок вставки и сопоставляет ключи int или string со значениями, поэтому один и тот же тип служит списком, словарём и стеком. Поиск по ключу (isset($arr[$key])) в среднем занимает постоянное время, а in_array() просматривает каждое значение. Строковые ключи, похожие на целые числа, преобразуются: $a['1'] и $a[1] это один и тот же элемент.

Частые задачи на код на собеседовании

Короткие упражнения, которые часто дают решать вживую. Каждая функция это один из распространённых ответов; запустите их, добавьте свои входные данные (включая пустые) и будьте готовы объяснить временную сложность, которую обычно и проверяет интервьюер.

Часто задаваемые вопросы

Как подготовиться к собеседованию на PHP-разработчика?

Убедитесь, что можете объяснить и написать код для основ, не подглядывая: сравнение и типы, массивы и их функции, ООП (интерфейсы, абстрактные классы, трейты, static), исключения и безопасность (подготовленные запросы, htmlspecialchars, password_hash). Затем знайте один фреймворк (Laravel или Symfony) и Composer достаточно хорошо, чтобы рассказать о проекте, который вы сделали.

Какую версию PHP нужно знать для собеседования?

PHP 8. От вас ждут знания возможностей, добавленных в 8.0 и до 8.3: именованные аргументы, match, nullsafe-оператор ?->, union-типы, продвижение свойств в конструкторе, перечисления, readonly-свойства и синтаксис first-class callable. Поведение PHP 7 упоминайте только там, где оно изменилось, например 0 == "a".

Какие вопросы по PHP задают начинающим?

В основном основы языка: == и ===, echo и print, одинарные и двойные кавычки, isset и empty, include и require, GET и POST, сессии и cookie и простые задачи с массивами вроде разворота, фильтрации или подсчёта значений. Ждите хотя бы одно короткое упражнение на код.

Какие вопросы по PHP задают опытным разработчикам?

Проектирование и то, как всё устроено внутри: интерфейсы и абстрактные классы, трейты, позднее статическое связывание, ссылки, генераторы и память, исключения и обработка ошибок, SQL-инъекции и транзакции, кеширование, автозагрузка Composer и то, как бы вы построили или протестировали функциональность. От ответов ждут компромиссов, а не определений.

Иллюстрация языков программирования Coddy

Учитесь программировать с Coddy

НАЧАТЬ