Основы языка PHP
Базовая семантика PHP — нестрогое и строгое сравнение и приведение типов, include и require, работа с null через isset/empty и операторы объединения с null, строковые литералы и heredoc, области видимости переменных и ссылки, а также выражение match.
16 вопросов
JuniorТеорияОчень частоЧем различаются isset, empty и is_null при проверке переменной?
Чем различаются isset, empty и is_null при проверке переменной?
isset истинно, когда переменная существует и не равна null; это языковая конструкция, поэтому на неопределённой переменной она молчит. empty истинно для любого ложного значения — '', 0, '0', [], null. is_null — обычная функция, проверяющая только null.
Типичные ошибки
- ✗Считать, что
isset($x)истинно, когда в$xлежитnull - ✗Применять
emptyк числовому вводу, где0и'0'считаются отсутствующими - ✗Вызывать
is_nullдля возможно неопределённой переменной и получать warning
Уточняющие вопросы
- →Почему
issetпринимает сразу несколько аргументов и что он возвращает в этом случае? - →Чем из трёх вы отличите отсутствующее поле формы от пустого?
JuniorТеорияОчень частоЧем оператор == отличается от === при сравнении значений в PHP?
Чем оператор == отличается от === при сравнении значений в PHP?
== — нестрогое сравнение: операнды могут приводиться к общему типу, поэтому 1 == '1' и null == false истинны. === — строгое: истинно, только если совпадают и тип, и значение. Для объектов === означает тот же экземпляр.
Типичные ошибки
- ✗Считать, что
===сравнивает содержимое объектов, тогда как он требует тот же экземпляр - ✗Думать, что
null == falseложно, раз типы различаются - ✗Применять
==к пользовательскому вводу, где числовые строки'1e3' == '1000'сравниваются численно
Уточняющие вопросы
- →Как
==сравнивает два объекта одного класса и что вместо этого требует===? - →Какое сравнение
in_arrayиспользует по умолчанию и как сделать его строгим?
JuniorТеорияЧастоЧем передача переменной по ссылке через & отличается от передачи по значению?
Чем передача переменной по ссылке через & отличается от передачи по значению?
По умолчанию PHP передаёт аргументы по значению: функция получает свою копию, и присваивание внутри не трогает переменную снаружи. Параметр &$x связывает оба имени с одним значением, поэтому записи внутри видны снаружи. Объекты передают хэндл по значению.
Типичные ошибки
- ✗Говорить, что объекты передаются по ссылке, тогда как по значению копируется сам хэндл
- ✗Ожидать, что обычный параметр-массив будет изменён вызываемой функцией на месте
- ✗Забыть
&в циклеforeach ($items as &$item)и удивляться, что ничего не изменилось
Уточняющие вопросы
- →Почему после
foreachс итерацией по ссылке нужно делатьunsetпеременной цикла? - →Что произойдёт с объектом вызывающего кода, если функция переприсвоит параметр-объект?
JuniorТеорияЧастоЧем выражение match отличается от switch в PHP 8?
Чем выражение match отличается от switch в PHP 8?
match — выражение: возвращает значение, сравнивает ветви строго через ===, не проваливается вниз и бросает UnhandledMatchError, если ничего не совпало и нет default. switch — инструкция: ничего не возвращает, сравнивает через == и проваливается вниз до break.
Типичные ошибки
- ✗Ожидать от
matchнестрогого сравнения, чтобыmatch('1')попал в ветвь1 - ✗Опустить
defaultи удивитьсяUnhandledMatchErrorво время выполнения - ✗Писать
breakвнутри ветвиmatch, будто она может провалиться вниз
Уточняющие вопросы
- →Как выразить проверку диапазона, например класса HTTP-статуса, через
match? - →Когда
switchвсё же уместнее, несмотря на нестрогое сравнение?
MiddleТеорияЧастоКогда isset и array_key_exists расходятся по одному и тому же ключу массива?
Когда isset и array_key_exists расходятся по одному и тому же ключу массива?
Они расходятся ровно тогда, когда ключ есть, но хранит null: isset($a['k']) ложно, а array_key_exists('k', $a) истинно. isset не отличает отсутствующий ключ от сохранённого null, и ?? следует тому же правилу. Функции же нужен существующий массив.
Типичные ошибки
- ✗Проверять через
issetнеобязательное поле, которое законно может бытьnull - ✗Считать, что
??отличает отсутствующий ключ от сохранённого значенияnull - ✗Вызывать
array_key_existsна неопределённом массиве и получать TypeError
Уточняющие вопросы
- →Чем из двух вы отличите отсутствующее поле JSON от явного
null? - →Как
issetведёт себя на вложенном пути$a['b']['c'], когда$a['b']отсутствует?
MiddleТеорияЧастоЧто делает global $config внутри функции и почему лучше передать параметр?
Что делает global $config внутри функции и почему лучше передать параметр?
global $config; импортирует одно имя из глобальной области как ссылку, поэтому присваивание переписывает и $GLOBALS['config']. Параметр же объявляет зависимость в сигнатуре и позволяет тесту подсунуть заглушку. global прячет эту связанность.
Типичные ошибки
- ✗Думать, что
globalкопирует значение, тогда как он привязывает ссылку на$GLOBALS - ✗Считать, что
unset($config)послеglobalудаляет саму запись в глобальной области - ✗Оставлять
globalв новом коде, раз значение «и так нужно везде»
Уточняющие вопросы
- →Что произойдёт с
$GLOBALS['config'], если функция вызоветunset($config)послеglobal? - →Как внедрение значения через конструктор меняет способ тестирования кода?
MiddleТеорияЧастоЧто меняет третий аргумент in_array и почему это важно?
Что меняет третий аргумент in_array и почему это важно?
in_array по умолчанию сравнивает через ==, поэтому in_array(0, ['0']) истинно: числовая строка сравнивается как число. Третий аргумент true переключает поиск на ===. array_search и array_keys принимают тот же флаг.
Типичные ошибки
- ✗Проверять пользовательский токен по белому списку в нестрогом режиме по умолчанию
- ✗Считать
in_arrayстрогим по умолчанию, разmatchстрог - ✗Забыть, что
array_searchтребует того же флага, чтобы вернуть надёжный ключ
Уточняющие вопросы
- →Как выбрать между строгим
in_arrayи проверкойissetпо перевёрнутому массиву? - →Что возвращает
array_search, не найдя значение, и почему это ловушка?
MiddleТеорияЧастоЧем ?? отличается от ?: и что делает присваивание ??=?
Чем ?? отличается от ?: и что делает присваивание ??=?
$a ?? $b даёт $a, если он задан и не равен null, иначе $b, и гасит warning о неопределённом ключе. ?: смотрит на истинность и warning выдаёт: 0 ?? 5 даёт 0, а 0 ?: 5 даёт 5. $a ??= $b присваивает, только если $a отсутствует или равен null.
Типичные ошибки
- ✗Ожидать, что
??откатится на0или'', которые заданы и не равныnull - ✗Применять
?:к$_GET['page']и получать warning о неопределённом ключе - ✗Читать
??=как безусловное присваивание, а не как присваивание только при null
Уточняющие вопросы
- →Как
??ведёт себя на глубоко вложенном ключе вроде$a['b']['c']? - →Что делает
??, когда значение в массиве есть, но равноnull?
MiddleТеорияЧастоЧто такое приведение типов в PHP и где движок преобразует значение?
Что такое приведение типов в PHP и где движок преобразует значение?
Приведение типов — неявное преобразование операнда к типу, которого ждёт операция: '5' + 3 даёт int 8, 5 . '3' даёт строку '53', а if ($x) приводит к bool, где '', '0' и 0 ложны. strict_types ограничивает аргументы и возвраты, но не операторы.
Типичные ошибки
- ✗Ожидать, что
declare(strict_types=1)не даст'5' + 3преобразовать строку - ✗Считать
'0'истинным, раз это непустая строка - ✗Полагать, что числовая строка сохраняет строковый тип после арифметики
Уточняющие вопросы
- →Какие строковые значения ложны в булевом контексте и почему
'0'среди них? - →Что именно меняет
declare(strict_types=1)и где он не действует?
JuniorТеорияИногдаПочему функция в PHP не видит переменную, объявленную в вызывающем коде?
Почему функция в PHP не видит переменную, объявленную в вызывающем коде?
Тело каждой функции открывает свою область видимости; неявного захвата внешней области, как в JavaScript, нет. Внешние значения передают явно — параметрами, через список use замыкания или через global. Повсюду видны только суперглобальные массивы.
Типичные ошибки
- ✗Ожидать неявного захвата внешней области внутри замыкания, как в JavaScript
- ✗Думать, что
globalимпортирует все внешние переменные, а не одно названное имя - ✗Считать, что переменная, объявленная выше в файле, видна внутри тела функции
Уточняющие вопросы
- →Как список
useу замыкания захватывает значение и когда к нему добавляют&? - →Какие переменные видны внутри функции вообще без передачи снаружи?
JuniorТеорияИногдаЧем в PHP различаются include, require и их варианты с _once?
Чем в PHP различаются include, require и их варианты с _once?
Оба подключают другой файл и выполняют его в этом месте. Если файла нет, include выдаёт warning и скрипт продолжается; require даёт fatal error и останавливает его. Варианты с _once пропускают файл, чей путь уже был подключён.
Типичные ошибки
- ✗Считать, что
includeтоже прерывает скрипт при отсутствии файла - ✗Думать, что
_onceкэширует вывод файла, а не отслеживает разрешённый путь - ✗Опираться на
require_onceв коде приложения вместо автозагрузчика Composer
Уточняющие вопросы
- →Что возвращает
includeи как подключаемый файл может управлять этим значением? - →Почему в современных проектах
requireпочти не пишут вне точки входа Composer?
JuniorТеорияИногдаЧто делает nullsafe-оператор ?-> , когда левый операнд равен null?
Что делает nullsafe-оператор ?-> , когда левый операнд равен null?
$a?->b() вычисляется в null вместо ошибки, когда $a равен null, и остаток цепочки замыкается накоротко — аргументы пропущенного вызова не вычисляются. Он защищает только от null: отсутствующий метод по-прежнему даёт Error.
Типичные ошибки
- ✗Ожидать, что
?->проглотит исключения или ошибку отсутствующего метода, а не толькоnullслева - ✗Думать, что аргументы пропущенного вызова всё равно вычисляются
- ✗Расставить
?->повсюду и спрятатьnull, который должен был стать настоящей ошибкой
Уточняющие вопросы
- →Как
?->ведёт себя в длинной цепочке вида$a?->b()->c()? - →Почему
?->запрещён слева от присваивания?
JuniorТеорияИногдаЧем строка в одинарных кавычках отличается в PHP от строки в двойных?
Чем строка в одинарных кавычках отличается в PHP от строки в двойных?
Строка в двойных кавычках разбирается: $name и {$obj->prop} подставляются, а escape вроде \n превращаются в реальные символы. Строка в одинарных кавычках буквальна — escape там только \' и \\. Разница в производительности между формами пренебрежимо мала.
Типичные ошибки
- ✗Ожидать, что
'Hello $name'в одинарных кавычках подставит переменную - ✗Верить, что одинарные кавычки дают ощутимый выигрыш в скорости в реальных приложениях
- ✗Забыть
{}вокруг сложного выражения вроде{$obj->prop}внутри двойных кавычек
Уточняющие вопросы
- →Когда внутри строки в двойных кавычках нужна форма с фигурными скобками
{$obj->prop}? - →Какие escape-последовательности всё же работают внутри строки в одинарных кавычках?
MiddleТеорияИногдаЧто делает $$name в PHP и почему в командах его не приветствуют?
Что делает $$name в PHP и почему в командах его не приветствуют?
$$name берёт значение $name как имя другой переменной, разрешая его во время выполнения, а ${'row_' . $i} собирает имя из строкового выражения. Он достаёт только текущую область видимости. Такое имя ломает статический анализ, переименование в IDE и grep.
Типичные ошибки
- ✗Думать, что
$$nameможет прочитать переменную из области вызывающей функции - ✗Писать
$$arr['k']без фигурных скобок, где разбор неоднозначен - ✗Тянуться к переменным переменным там, где уместен обычный ассоциативный массив
Уточняющие вопросы
- →Почему
$$arr['k']требует фигурных скобок и между какими двумя разборами выбирает парсер? - →Как переписать блок на
$$nameчерез массив?
JuniorТеорияРедкоВ чём разница между строками heredoc и nowdoc в PHP?
В чём разница между строками heredoc и nowdoc в PHP?
Оба — многострочные литералы, открываемые через <<<. Heredoc берёт голый идентификатор и ведёт себя как строка в двойных кавычках: переменные подставляются, escape обрабатываются. Nowdoc берёт идентификатор в кавычки — <<<'SQL' — и ведёт себя как строка в одинарных.
Типичные ошибки
- ✗Ожидать, что nowdoc подставит
$переменныетак же, как heredoc - ✗Отступать закрывающий идентификатор иначе, чем тело, из-за чего сдвигается отступ строки
- ✗Класть heredoc с пользовательскими данными прямо в SQL вместо привязки параметров
Уточняющие вопросы
- →Как отступ закрывающего идентификатора влияет на итоговую строку?
- →Когда вы осознанно выберете nowdoc вместо строки в одинарных кавычках?
MiddleТеорияРедкоКак PHP 8.0 изменил нестрогое сравнение числа со строкой?
Как PHP 8.0 изменил нестрогое сравнение числа со строкой?
PHP 8.0 сначала проверяет, числовая ли строка. Если да, стороны сравниваются как числа, поэтому 100 == '1e2' истинно. Если нет, число приводится к строке и они сравниваются как строки — поэтому 0 == 'abc' теперь ложно, а PHP 7 давал истину.
Типичные ошибки
- ✗Считать, что
0 == 'abc'по-прежнему истинно, как было до PHP 8 - ✗Думать, что изменение сделало
==строгим —'1' == '01'всё ещё истинно - ✗Верить, что правило затрагивает
===, который никогда ничего не преобразовывал
Уточняющие вопросы
- →Какие строки считаются числовыми в PHP 8 и ломает ли это концевой пробел?
- →Почему правило до 8.0 делало наивную проверку токена через
==дырой в безопасности?