Библиотека собеса по PHP | вопросы с собеседований
3.16K subscribers
191 photos
6 videos
126 links
Вопросы с собеседований по PHP и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/9f3affba

Для обратной связи: @proglibrary_feeedback_bot
Download Telegram
Как работает сборщик мусора?

PHP использует два механизма управления памятью: счётчик ссылок (refcount) и циклический сборщик мусора (GC).

Каждая переменная хранит zval с refcount — счётчиком, сколько переменных ссылаются на это значение. Когда refcount падает до 0, память освобождается немедленно.

Проблема возникает при цикличных ссылках:
php$a = [];
$a[] = &$a; // $a ссылается сама на себя
unset($a); // refcount стал 1, а не 0 — утечка


После unset refcount не обнуляется, потому что объект ссылается на самого себя. Простой счётчик это не поймает.

Для таких случаев PHP (с версии 5.3) имеет cyclic garbage collector. Он периодически запускается (или при достижении порога ~10 000 потенциальных "мусорных" zval'ов) и обходит граф ссылок, выявляя изолированные циклы.

Управление вручную:

gc_collect_cycles(); // принудительный запуск
gc_disable(); // отключить, если GC мешает производительности
gc_enable();
gc_status(); // статистика


На практике — актуально в долгоживущих процессах (Swoole, RoadRunner, воркеры), где объекты с взаимными ссылками (например, parent/children в дереве) могут постепенно съедать память. Решение — либо weak references (WeakReference::create($obj)), либо явная очистка связей перед unset.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41🔥1
Что такое Fibers в PHP 8.1 и чем они отличаются от async/await в других языках?

Fiber — примитив для кооперативной многозадачности. Позволяет приостановить выполнение функции в произвольной точке через Fiber::suspend() и возобновить позже, передав значение обратно.

Главное отличие от async/await: Fibers не заражают сигнатуры. В JS как только где-то await — вся цепочка выше должна быть async. В PHP Fiber::suspend() можно вызвать на любой глубине стека, не меняя сигнатуры вызывающих функций.

Второе отличие — Fibers это низкоуровневый примитив, event loop в них не встроен. Сами по себе они не дают параллелизма — это строительный блок, поверх которого ReactPHP, Revolt и Amp строят настоящую неблокирующую конкурентность.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍4🔥3
В чём разница между interface и abstract class?

Interface — это контракт. Только сигнатуры методов, никакой реализации (до PHP 8 — вообще, в 8+ можно константы). Класс может имплементировать сколько угодно интерфейсов.

Abstract class — частичная реализация. Можно миксовать абстрактные методы с готовыми, хранить состояние (свойства). Наследование — только одно.

🔹 Когда interface:
— описываешь поведение, не связанное иерархией (Loggable, Serializable, Cacheable)
— хочешь возможность имплементировать несколько контрактов

🔹 Когда abstract class:
— есть общий код, который не хочешь дублировать
— классы реально связаны иерархически (BaseRepository, BaseCommand)

На практике — предпочитай интерфейс + trait вместо абстрактного класса. Получаешь гибкость множественного наследования поведения без жёсткой иерархии.
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3🔥1
Чем PHP-FPM отличается от RoadRunner/Swoole?

PHP-FPM — это share-nothing. Nginx принимает запрос, передаёт его свободному worker-процессу, тот поднимается с нуля (или берётся из пула), отрабатывает, умирает (или возвращается в пул чистым). Всё: globals, static, состояние контейнера — сброшено.

RoadRunner — это Go-сервер, который держит PHP-воркеры живыми между запросами через бинарный протокол (на основе goridge). Swoole — PHP-расширение, которое само реализует event loop и корутины прямо в процессе. Оба дают одно: bootstrap выполняется один раз, дальше worker просто принимает запросы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
Как работает Service Container в Laravel и зачем он нужен?

Это IoC-контейнер, который управляет зависимостями и их разрешением. Главная задача — инверсия управления: ты не создаёшь объекты через new, а просишь контейнер их предоставить.

Работает в два шага: binding и resolving.

// Binding — регистрируем, как создавать
app()->bind(PaymentInterface::class, StripePayment::class);

// Resolving — контейнер сам строит граф зависимостей
$payment = app(PaymentInterface::class);


Когда ты тайпхинтишь зависимость в конструкторе контроллера, контейнер видит это через Reflection API и автоматически подтягивает нужные классы, рекурсивно разрешая все вложенные зависимости.

Есть три вида байндингов

bind — новый инстанс при каждом резолве
singleton — один инстанс на весь request lifecycle
instance — регистрируешь уже созданный объект
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥41👍1
Что такое preloading в PHP и какие у него ограничения?

Preloading (PHP 7.4+) — механизм, при котором PHP загружает файлы в память один раз при старте PHP-FPM и держит их там на весь срок жизни процесса. Последующие запросы используют уже скомпилированный opcode без обращения к диску.

▪️ Что даёт

— Устраняет overhead на парсинг и компиляцию горячих классов
— Реальный прирост на больших фреймворках (Laravel, Symfony) — 10–30% к RPS

▪️ Ограничения

— При любом изменении файла нужен рестарт PHP-FPM, иначе изменения не подхватятся.
— Preloaded классы нельзя пересоздать или переопределить в рантайме
— Если preloaded класс зависит от другого файла, тот тоже должен быть preloaded, иначе ошибка при старте
— Не работает с circular dependencies между файлами
— Работает только с OPcache
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1🤔1
✔️ PHP-тест: Fibers + замыкания в Laravel

Классическая ловушка с утечкой состояния 👇

📦 Задание

Написали систему обработки платёжных webhook'ов. В логах периодически замечают, что у одной транзакции записывается merchant_id другой. Баг плавающий, воспроизводится только под нагрузкой. Найдите проблему и исправьте:

class MerchantContext
{
private static ?string $currentMerchantId = null;

public static function set(string $id): void
{
self::$currentMerchantId = $id;
}

public static function get(): ?string
{
return self::$currentMerchantId;
}

public static function clear(): void
{
self::$currentMerchantId = null;
}
}

class WebhookProcessor
{
public function handle(WebhookPayload $payload): void
{
MerchantContext::set($payload->merchantId);

$fiber = new Fiber(function () use ($payload): void {
$result = $this->validateSignature($payload);

// симулируем I/O — запрос к внешнему сервису
Fiber::suspend();

$this->auditLogger->log(
'Webhook processed for: ' . MerchantContext::get(),
['amount' => $payload->amount]
);
});

$fiber->start();
// ... другие файберы запускаются здесь
$fiber->resume();
}
}


🔹 Задачи

— Объяснить, почему MerchantContext::get() после resume() может вернуть merchant_id другого запроса
— Исправить так, чтобы контекст не терялся при переключении между файберами

Ставьте → 🔥 если нравится формат. Если нет → 🌚

💬 Решения пишите в комменты под спойлер — сравним подходы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍1🤔1
Что такое Closure и зачем нужен use?

Closure — это анонимная функция. Объект класса Closure под капотом.
use захватывает переменные из внешнего скоупа внутрь замыкания.

$discount = 10;

$price = fn($amount) => $amount - $discount; // не работает

$price = function($amount) use ($discount) {
return $amount - $discount; // работает
};
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1😢1🥱1👾1
Какие HTTP-методы есть?

GET: этот метод используется для запроса содержимого указанного ресурса.

POST: обычно используется для отправки данных формы или для выполнения какой-то операции на сервере, которая может изменить состояние сервера или добавить новые данные.

PUT: используется для создания или обновления ресурса на сервере.

DELETE: удалить указанный ресурс с сервера.

PATCH: используется для частичного обновления ресурса.

HEAD: метод полезен, когда клиенту нужны только заголовки, а не фактическое содержимое.

OPTIONS: получить информацию о возможностях сервера относительно ресурса или сервера в целом. Это может включать доступные методы, поддерживаемые заголовки и другую метаинформацию.

TRACE: используется для тестирования соединения между клиентом и сервером. Когда сервер получает запрос TRACE, он возвращает весь запрос обратно клиенту, что позволяет клиенту увидеть, как запрос проходит через промежуточные узлы.

CONNECT: используется для установки виртуального соединения с сервером, обеспечивая прозрачное шифрование SSL через промежуточный узел.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
В чем разница между '==' и '===' ?

Нестрогое сравнение («==»): При использовании двойного знака равенства PHP сравнивает значения операндов после их преобразования в общий тип данных. Например, 5 == '5' вернет true, потому что PHP преобразует строку '5' в целое число 5 перед сравнением.

Строгое сравнение («===»): При использовании тройного знака равенства PHP сравнивает не только значения операндов, но и их типы данных. Это означает, что для того чтобы выражение было истинным, значения операндов должны быть одинаковыми и одного типа. Например, 5 === '5' вернет false, потому что типы операндов различны.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
☝️ Уже сегодня: ИИ-агенты в продакшене — инженерный подход к интеграции LLM

Индустрия активно обсуждает потенциал нейросетей, способных автоматизировать бизнес-процессы и заменить целые отделы. Однако реальное внедрение агентов в production вскрывает серьёзные проблемы: разработчикам приходится бороться с непредсказуемыми галлюцинациями моделей, нестабильными API и сложной интеграцией в существующую архитектуру.

Сегодня в 19:00 МСК в рамках нашего курса «Разработка AI-агентов» мы проведём открытый вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке. Будем говорить о нейросетях с позиции жёсткой инженерии.

Разберём три реальных кейса из сурового банковского энтерпрайза, напишем и запустим агента прямо в эфире, честно обсудим грабли, на которые наступает бизнес при интеграции LLM.

Тем, кто придёт на эфир, дадим промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.

👉 Занять место на вебинаре
🥱1
Часовая готовность: создаём ИИ-агента в прямом эфире

В 19:00 МСК в рамках нашего курса «Разработка AI-агентов» стартует вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке.

Будет live-демо работающего агента, реальные метрики из корпоративной среды и честный разбор архитектурных граблей — без воды и «успешного успеха».

Всем зрителям эфира дадим эксклюзивный промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.

👉 Занять место на вебинаре
🥱1
Чем отличается абстрактный класс от интерфейса?

Интерфейс — чистый контракт. Только сигнатуры методов и константы, никакой реализации. Класс может реализовывать сколько угодно интерфейсов.

Абстрактный класс — уже частичная реализация: может содержать конкретные методы, свойства, конструктор. Наследоваться можно только от одного.

Правило выбора простое: если нужно описать что умеет объект — интерфейс. Если нужно вынести общую логику и состояние — абстрактный класс.

В хорошей архитектуре они часто работают вместе: абстрактный класс реализует интерфейс частично, потомки добивают остальное.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Что такое trait и зачем он нужен, если есть абстрактные классы?

Trait — механизм горизонтального переиспользования кода. PHP не поддерживает множественное наследование, trait это обходит: он буквально копирует методы в класс на этапе компиляции. Класс может использовать несколько трейтов одновременно.

Хорошо подходит для сквозной функциональности: логирование, soft delete, timestamps, работа с UUID. Плохо — когда трейт начинает зависеть от свойств класса, которые в нём не объявлены. Это скрытая связанность, и трейтами легко злоупотребить. Если видишь трейт с $this->connection без объявления свойства — это запах.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🥱2🔥1😁1
Что такое PSR-4?

Стандарт автозагрузки классов от PHP-FIG. Описывает как неймспейс маппится на структуру директорий. Composer реализует его из коробки через секцию autoload в composer.json.

Суть: App\Services\PaymentService должен лежать в src/Services/PaymentService.php, если корневой неймспейс App\ смаплен на src/. Без этого стандарта каждый фреймворк изобретал свой автолоадер. PSR-4 заменил устаревший PSR-0 и сейчас де-факто обязателен в любом современном PHP-проекте.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3
✔️ PHP-тест: Static state + OPcache + Preloading

Классический баг, который ломает прод и не воспроизводится локально 👇

📦 Задание

Команда добавила preloading в production для ускорения.

Через день в логах появились странные ошибки: у разных пользователей в одном запросе перемешиваются данные — кто-то видит чужие настройки, кто-то получает null там, где не должен.

На dev-машинах не воспроизводится. Найдите проблему в коде:
// preload.php 
require_once 'src/Config.php';
require_once 'src/UserContext.php';
require_once 'src/RequestPipeline.php';

// config/app.php
class Config
{
private static array $data = [];
private static bool $loaded = false;

public static function load(string $env): void
{
if (self::$loaded) {
return;
}
self::$data = parse_ini_file("config/{$env}.ini");
self::$loaded = true;
}

public static function get(string $key): mixed
{
return self::$data[$key] ?? null;
}
}

// src/UserContext.php
class UserContext
{
private static ?array $current = null;

public static function set(array $user): void
{
self::$current = $user;
}

public static function get(): ?array
{
return self::$current;
}

public static function clear(): void
{
self::$current = null;
}
}

// src/RequestPipeline.php
class RequestPipeline
{
private static array $middlewareResults = [];

public static function addResult(string $key, mixed $value): void
{
self::$middlewareResults[$key] = $value;
}

public static function getResult(string $key): mixed
{
return self::$middlewareResults[$key] ?? null;
}

public static function reset(): void
{
self::$middlewareResults = [];
}
}

// public/index.php
Config::load($_ENV['APP_ENV'] ?? 'production');

$user = Auth::check($_SERVER['HTTP_AUTHORIZATION'] ?? '');
UserContext::set($user);

RequestPipeline::addResult('ip', $_SERVER['REMOTE_ADDR']);
RequestPipeline::addResult('ua', $_SERVER['HTTP_USER_AGENT'] ?? '');

$app->handle(ServerRequest::fromGlobals());


🔹 Задачи

— Объяснить, почему при preloading статические свойства классов ведут себя иначе, чем без него, и как это связано с жизненным циклом worker-процесса.
— Объяснить, чем классы отличаются по характеру утечки
— Предложить архитектурное решение: как правильно управлять request-scoped состоянием в long-running процессах

Ставьте → 🔥 если нравится формат. Если нет → 🌚

💬 Решения пишите в комменты под спойлер — сравним подходы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍2🤔2🥱1
Самый востребованный навык в ИТ в 2026-м — навык создания ИИ-агентов

Мы полностью переработали курс «Разработка AI-агентов» под реалии 2026 года. Никакой долгой теории — с самого начала пишем код. Обучать и делиться набитыми шишками будут эксперты-практики из Газпромбанка, Альфа-Банка и других бигтехов.

В программе:

— архитектура автономных систем с тестированием, ReAct-циклами и контролем токенов;
— практическая работа с актуальными фреймворками LangGraph, AutoGen, MCP и CrewAI;
— настройка продвинутого RAG для парсинга документов и точного поиска;
— внедрение решений с учётом действующего законодательства (152-ФЗ);
— дипломная работа, за основу которой можно взять свой рабочий проект или задачу, которую предложим мы.

Эксперты поделятся инсайтами из реального продакшна — тем, о чём вам никогда не расскажет ни одна нейросеть.

Запись первого открытого вебинара, на котором мы вместе с руководителем AI-направления в Альфа-Банке Полиной Полуниной пилили агента в прямом эфире.


Ах да, чуть не забыли! Дарим промокод AGENTSWEB на скидку 10 000 рублей и два курса сверху при покупке до 15 марта 🎁

Стать AI-инженером
🥱21
Что такое Composer?

Composer — это инструмент для управления зависимостями в PHP-приложениях. Он позволяет легко устанавливать, обновлять и управлять библиотеками и фреймворками, которые используются в проекте.

🔹 Основные функции Composer

▪️ Установка зависимостей: Composer позволяет определить необходимые библиотеки и их версии в файле composer.json, а затем установить их с помощью команды composer install.

▪️ Обновление зависимостей: после установки библиотек, можно обновить их до последних версий, указанных в файле composer.json, с помощью команды composer update.

▪️ Автозагрузка классов: Composer автоматически создает файл автозагрузки, который позволяет использовать классы из установленных зависимостей без необходимости явного подключения файлов.

▪️ Автоматическое разрешение зависимостей: Composer управляет разрешением зависимостей, учитывая совместимость версий между различными библиотеками.

▪️ Создание собственных пакетов: Composer позволяет создавать собственные пакеты для повторного использования в различных проектах и их публикации в репозитории Packagist для общего использования.
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1🔥1
Зачем использовать yield вместо return с массивом?

yield превращает функцию в генератор. Вместо того чтобы собрать все данные в массив и вернуть целиком, функция отдаёт значения по одному, по мере запроса.

Главный профит — память. Если обрабатываешь CSV на 500 тысяч строк, с массивом ты загрузишь всё в RAM разом. С генератором в памяти живёт одна строка. Генератор реализует интерфейс Iterator, с ним работает foreach. Минус — нельзя перемотать назад, обойти можно только один раз. Используй когда данных много, порядок линейный, и случайный доступ не нужен.
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3🔥1
Кажется, мы окончательно перешли от игрушек к суровому AgentOps

Приглашаем на наш обновлённый курс по разработке ИИ-агентов. Никакой воды про «будущее нейросетей», только инженерный подход.

На курсе мы:

— пошагово строим готовые системы на LangGraph, CrewAI и MCP;
— настраиваем кэширование и роутинг, чтобы бот не сожрал токены;
— разбираемся со стейтом, учимся дебажить через time-travel и прикручиваем human-in-the-loop;
— выводим RAG в прод так, чтобы безопасники не завернули архитектуру из-за 152-ФЗ.

В пекло скучные лекции про общую инфраструктуру — сразу фокусируемся на агентных фреймворках и написании кода. Занятия ведут бывалые лиды из Газпромбанка и Альфы, набившие шишки на реальных задачах.

Кстати, на днях мы пилили агента в прямом эфире, если пропустили — есть запись вебинара.


Сегодня последний день, когда можно забрать курс по старым ценам. Базовый тариф сейчас стоит 49 000 ₽ (вместо 62 990 ₽), продвинутый трек — 99 000 ₽ (вместо 124 990 ₽). Если не хочется отдавать всю сумму сразу, есть рассрочка. Торопитесь — на потоке осталось всего 5 мест!

Зафиксировать цену и перейти к сборке своих агентов
Что такое PSR и зачем это нужно?

PSR (PHP Standards Recommendations) — набор стандартов от PHP-FIG, которые обеспечивают совместимость кода между проектами и пакетами.

Ключевые стандарты:

• PSR-1 / PSR-12 — стиль кода (отступы, имена классов, методов)
• PSR-4 — автозагрузка: пространство имён → путь к файлу
• PSR-3 — интерфейс логгера (LoggerInterface)
• PSR-7 — HTTP-сообщения (Request / Response)
• PSR-11 — контейнер зависимостей (ContainerInterface)
• PSR-15 — HTTP middleware

Без PSR библиотеки несовместимы, composer не может их объединить, а команды пишут в разных стилях. PSR — это общий язык PHP-экосистемы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1