fa
Feedback
Библиотека собеса по PHP | вопросы с собеседований

Библиотека собеса по PHP | вопросы с собеседований

رفتن به کانال در Telegram

Вопросы с собеседований по PHP и ответы на них. По рекламе: @proglib_adv Учиться у нас: clc.to/5JWKxA Для обратной связи: @proglibrary_feeedback_bot

نمایش بیشتر
3 114
مشترکین
-324 ساعت
-67 روز
-1930 روز
آرشیو پست ها
Расскажите о паттерне Command Command — это поведенческий паттерн, который превращает запрос в отдельный объект, содержащий всю информацию о запросе. Простыми словами: вместо прямого вызова метода вы создаёте объект-команду, которую можно передать, поставить в очередь, отменить или повторить. ▪️ Когда использоватьНужен undo/redoКоманды нужно ставить в очередь, логировать или выполнять отложенноХотите отделить объект, инициирующий операцию, от объекта, выполняющего её ▪️ Минус Усложняет код: каждая операция — отдельный класс.

Расскажите о паттерне Observer Observer — это поведенческий паттерн, который создаёт механизм подписки, позволяя одним объектам следить за изменениями в других. Простыми словами: как подписка на Telegram-канал — когда выходит новый пост, все подписчики получают уведомление автоматически. ▪️ Когда использоватьИзменение одного объекта требует обновления других, и набор зависимых объектов заранее неизвестенХотите избежать жёсткой связи между компонентами ▪️ Минус Подписчики оповещаются в непредсказуемом порядке; утечки памяти, если забыть отписаться.

Расскажите о паттерне Proxy Proxy — это структурный паттерн, который подставляет вместо реального объекта объект-заместитель, контролирующий доступ к оригиналу. Простыми словами: прокси выглядит как оригинал, но перед вызовом может проверить права, закэшировать результат или создать объект лениво. ▪️ Виды проксиProtection Proxy — контроль доступа (Spring Security)Caching Proxy — кэширование результатовLazy Proxy — отложенная инициализация (Hibernate lazy loading)Remote Proxy — доступ к удалённому объекту (RMI) ▪️ Proxy vs Decorator — Proxy: контролирует жизненный цикл и доступ к объекту — Decorator: добавляет поведение, не контролируя доступ ▪️ Минус Увеличивает задержку отклика; усложняет отладку при нескольких слоях проксирования.

Расскажите о паттерне Facade Facade — это структурный паттерн, который предоставляет простой интерфейс к сложной подсистеме, скрывая внутреннюю сложность. Простыми словами: один метод вместо десяти вызовов в разные сервисы. Пульт от телевизора — это фасад к электронике внутри. ▪️ Когда использоватьПодсистема сложная, а клиенту нужен простой входХотите уменьшить связанность между слоямиТипичный пример: сервисный слой в Spring-приложении ▪️ Минус Фасад может стать God Object, если взять на себя слишком много логики.

💬 Обратная связь Как часто вы проходите собеседования? 🔥 — Сейчас активно ищу работу 👍🏼 — Раз в несколько месяцев ❤️ — Раз в полгода-год 😁 — Не прохожу, уже работаю/ещё учусь

✔️ PHP-тест: клон, который мутирует оригинал Пользователь нажал «Повторить заказ». Цены в его старом заказе изменились. 📦 Задание Фича: кнопка «Повторить заказ» в личном кабинете. Копирует предыдущий заказ, применяет промокод, создаёт новый черновик. Оригинал помечается флагом repeated для аналитики. Через неделю — тикет от бухгалтерии: суммы в старых заказах не сходятся с тем, что было при оплате. Проблема только у заказов, которые хотя бы раз «повторяли». Суммы занижены ровно на размер скидки по промокоду.
// src/Order/Order.php
class Order
{
    public function __construct(
        private ?int   $id,
        private int    $userId,
        private array  $items, 
        private string $status,
        private bool   $repeated = false,
    ) {}

    public function getId(): ?int      { return $this->id; }
    public function getItems(): array  { return $this->items; }
    public function getStatus(): string { return $this->status; }

    public function resetForRepeat(): void
    {
        $this->id       = null;
        $this->status   = 'draft';
        $this->repeated = false;
    }

    public function markAsRepeated(): void
    {
        $this->repeated = true;
    }

    public function calculateTotal(): int
    {
        return array_sum(array_map(
            fn(OrderItem $i) => $i->getSubtotal(),
            $this->items
        ));
    }
}

// src/Order/OrderItem.php
class OrderItem
{
    public function __construct(
        private int $productId,
        private int $qty,
        private int $price,
    ) {}

    public function getProductId(): int { return $this->productId; }
    public function getQty(): int       { return $this->qty; }
    public function getPrice(): int     { return $this->price; }

    public function getSubtotal(): int
    {
        return $this->qty * $this->price;
    }

    public function applyDiscount(int $percent): void
    {
        $this->price = (int) round(
            $this->price * (1 - $percent / 100)
        );
    }
}

// src/Order/RepeatOrderHandler.php
class RepeatOrderHandler
{
    public function __construct(
        private OrderRepository $orders,
        private PromoService    $promo,
    ) {}

    public function handle(int $originalId, ?string $promoCode): Order
    {
        $original = $this->orders->findById($originalId);

        $copy = clone $original;
        $copy->resetForRepeat();

        if ($promoCode !== null) {
            $discount = $this->promo->resolve($promoCode);

            foreach ($copy->getItems() as $item) {
                $item->applyDiscount($discount->percent);
            }
        }

        $this->orders->save($copy);

        $original->markAsRepeated();
        $this->orders->save($original);

        return $copy;
    }
}

// src/Repository/OrderRepository.php
class OrderRepository
{
    public function __construct(private PDO $pdo) {}

    public function save(Order $order): void
    {
        if ($order->getId() === null) {
            $this->insert($order);
        } else {
            $this->update($order);
        }
    }

    private function update(Order $order): void
    {
        $this->pdo->prepare(
            'UPDATE orders SET status = ?, repeated = ? WHERE id = ?'
        )->execute([$order->getStatus(), (int) $order->isRepeated(), $order->getId()]);

        $this->pdo->prepare('DELETE FROM order_items WHERE order_id = ?')
            ->execute([$order->getId()]);

        foreach ($order->getItems() as $item) {
            $this->pdo->prepare(
                'INSERT INTO order_items (order_id, product_id, qty, price) VALUES (?, ?, ?, ?)'
            )->execute([$order->getId(), $item->getProductId(), $item->getQty(), $item->getPrice()]);
        }
    }
}
🔹 Задачи — Объяснить, каким образом цены в оригинальном заказе оказались изменены в базе — Исправить код так, чтобы оригинал гарантированно не мутировал Ставьте → 🔥 если нравится формат. Если нет → 🌚 💬 Решения пишите в комменты под спойлер — сравним подходы.

Расскажите о паттерне Decorator Decorator — это структурный паттерн, позволяющий на лету расширять поведение объекта, не изменяя его класс. Исходный объект помещается внутрь другого — декоратора, — который перехватывает вызовы и дополняет их нужной функциональностью. Принцип тот же, что у матрёшки: каждый новый слой добавляет что-то своё. ▪️ Когда использоватьНужно добавить поведение объекту без наследованияКомбинации поведений непредсказуемы (логирование + кэш + метрики в любом порядке)Классический пример в JDK: InputStream → BufferedInputStream → GZIPInputStream ▪️ Decorator vs наследование — Наследование: статическое, одно на класс — Decorator: динамическое, можно комбинировать ▪️ Минус Много мелких классов; отладка стека из нескольких обёрток может быть неудобной.

Расскажите о паттерне Composite Composite — это структурный паттерн, который позволяет сгруппировать объекты в древовидную структуру и работать с ней так же, как с единичным объектом. Простыми словами: файл и папка с файлами обрабатываются одинаково — у обоих можно спросить размер, удалить, переместить. ▪️ Когда использоватьДанные образуют древовидную структуру (файловая система, меню, оргструктура)Клиентский код должен одинаково работать с простыми и составными объектами ▪️ Минус Трудно ограничить типы компонентов внутри композита — приходится проверять в runtime.

🧑‍💻 Приглашаем на открытый урок курса «PHP-разработчик. Продвинутый уровень» 19 мая в 20:00 — Работа с очередями в Laravel:
🧑‍💻 Приглашаем на открытый урок курса «PHP-разработчик. Продвинутый уровень» 19 мая в 20:00 — Работа с очередями в Laravel: от настройки до решения типичных проблем Разберём, как очереди помогают ускорить приложение и вынести тяжёлые задачи в фон без потери стабильности. Обсудим настройку и обработку задач, типичные ошибки, повторы при сбоях, защиту от дублирования и мониторинг выполнения. Вы поймёте, как работают фоновые процессы в Laravel, научитесь правильно настраивать очереди и делать приложение быстрее и надёжнее. 🚀Открытый урок проходит в преддверии старта курса «PHP-разработчик. Продвинутый уровень» 19 мая в 20:00 МСК. Регистрация: https://clc.to/6HSSeg Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Расскажите о паттерне Bridge Bridge — это структурный паттерн, который разделяет абстракцию и реализацию так, чтобы они могли изменяться независимо друг от друга. Простыми словами: вместо одной толстой иерархии наследования вы разбиваете её на две независимые — «что делать» и «как делать» — и связываете их композицией. ▪️ Когда использоватьЕсть две ортогональные оси изменения (тип × реализация)Хотите избежать «взрыва» подклассовНужно переключать реализацию в runtime ▪️ Bridge vs Strategy — Strategy: меняет один алгоритм внутри объекта — Bridge: разделяет целые иерархии абстракции и реализации ▪️ Минус Усложняет код, если оси изменения всего одна — тогда достаточно обычного полиморфизма.

Расскажите о паттерне Builder Builder — это порождающий паттерн, который позволяет создавать сложные объекты пошагово, разделяя процесс конструирования и представление. Простыми словами: вместо конструктора с десятком параметров, вы собираете объект по частям, вызывая понятные методы. ▪️ Когда использоватьОбъект имеет множество параметров (особенно необязательных)Нужна immutable-объект с удобным созданиемХотите избежать telescoping constructor (конструктор в конструкторе) ▪️ Builder vs конструктор — Конструктор: подходит, если параметров 2–3 и все обязательные — Builder: если параметров больше 4 или есть необязательные ▪️ Минус Дублирование полей между классом и билдером. Lombok @Builder решает это автоматически.

Расскажите о паттерне Flyweight Flyweight — это структурный паттерн, который позволяет вместить большее количество объектов в отведённую оперативную память за счёт разделения общего состояния между объектами. Простыми словами: вместо создания тысяч похожих объектов, вы создаёте несколько объектов-легковесов с общими данными и передаёте уникальные данные извне при использовании. ▪️ Когда использоватьПриложение создаёт огромное количество однотипных объектовОбъекты потребляют много памятиБольшую часть состояния можно вынести за пределы объектаПриложение не зависит от идентичности объектов (можно переиспользовать) ▪️ МинусыУсложнение кода из-за разделения состоянияFlyweight должен быть immutable для безопасного переиспользования

🗓 14 мая в 19:00 (Мск) встречаемся в онлайне. Тема: Почему AI-продукты на базе LLM ломаются и как сделать, чтобы работало. В кружке выше Эмиль Сатаев рассказал, какие именно проблемы с LLM в проде будем разбирать. Что в программе:
- Разберем реальные кейсы стартапов и ограничения LLM. - Обсудим рабочие архитектуры: RAG, human-in-the-loop, контроль качества. - Ответим на ваши вопросы и разберем кейсы участников.
🎁 Бонусы: в конце вебинара подарим промокод на скидку 10.000 ₽ на курсы и разыграем подписки на полезные AI-сервисы. 👉 Зарегистрироваться на вебинар

Расскажите о паттерне Prototype Prototype — это порождающий паттерн, который позволяет копировать объекты, не вдаваясь в подробности их реализации. Простыми словами: вместо создания объекта с нуля через конструктор, вы клонируете уже существующий экземпляр. ▪️ Когда использоватьСоздание объекта затратно (сложная инициализация, обращение к БД, парсинг файлов)Нужно избежать привязки к конкретным классам при создании копийОбъекты различаются только состоянием, а не поведением ▪️ Важно: Shallow vs Deep Copy Shallow copy — копируются только примитивы, ссылки на объекты остаются теми же Deep copy — создаются копии вложенных объектов ▪️ Альтернативы clone — Магический __clone() — Статический метод: Report::copy($original) — Сериализация: unserialize(serialize($obj)) ▪️ Минус Клонирование объектов с циклическими ссылками может быть сложным.

Расскажите о паттерне Prototype Prototype — это порождающий паттерн, который позволяет копировать объекты, не вдаваясь в подробности их реализации. Простыми словами: вместо создания объекта с нуля через конструктор, вы клонируете уже существующий экземпляр. ▪️ Когда использоватьСоздание объекта затратно (сложная инициализация, обращение к БД, парсинг файлов)Нужно избежать привязки к конкретным классам при создании копийОбъекты различаются только состоянием, а не поведением ▪️ Важно: Shallow vs Deep Copy Shallow copy — копируются только примитивы, ссылки на объекты остаются теми же Deep copy — создаются копии вложенных объектов ▪️ Альтернативы clone() — Copy constructor: new Report(original) — Статический метод: Report.copy(original) — Сериализация: для очень сложных объектов ▪️ Минус Клонирование объектов с циклическими ссылками может быть сложным.

✔️ PHP-тест: Идемпотентность, которой нет Пользователь нажал «Оплатить» один раз. Деньги списались дважды. 📦 Задание Фича: интеграция с платёжным шлюзом. Платёж создаётся на бэке, пользователь редиректится на страницу шлюза, после оплаты шлюз дёргает webhook. По webhook'у выдаётся доступ к продукту. Жалобы начались через две недели после релиза. Только у части пользователей, только в часы пик. У некоторых списывалось дважды, у других доступ не выдавался вовсе.
// src/Payment/WebhookHandler.php
class WebhookHandler
{
    public function __construct(
        private PaymentRepository $payments,
        private OrderRepository   $orders,
        private AccessService     $access,
        private Mailer            $mailer,
    ) {}

    public function handle(array $payload): void
    {
        $externalId = $payload['payment_id'];
        $status     = $payload['status'];

        if ($status !== 'success') {
            return;
        }

        $payment = $this->payments->findByExternalId($externalId);

        if ($payment === null) {
            return;
        }

        $order = $this->orders->findById($payment->orderId);

        if ($order->status === 'paid') {
            return;
        }

        $this->orders->markAsPaid($payment->orderId);
        $this->access->grantForOrder($order);
        $this->mailer->sendReceipt($order);
    }
}

// src/Repository/OrderRepository.php
class OrderRepository
{
    public function __construct(private PDO $pdo) {}

    public function findById(int $id): Order
    {
        $stmt = $this->pdo->prepare(
            'SELECT * FROM orders WHERE id = ?'
        );
        $stmt->execute([$id]);
        return Order::fromRow($stmt->fetch(PDO::FETCH_ASSOC));
    }

    public function markAsPaid(int $orderId): void
    {
        $stmt = $this->pdo->prepare(
            'UPDATE orders SET status = ? WHERE id = ?'
        );
        $stmt->execute(['paid', $orderId]);
    }
}
🔹 Задачи — Объяснить, как именно возникает двойное списание при одном нажатии пользователя — Исправить WebhookHandler::handle Ставьте → 🔥 если нравится формат. Если нет → 🌚 💬 Решения пишите в комменты под спойлер — сравним подходы.

🦾 Почему ваши AI-продукты на базе LLM ломаются (и как это чинить)? Выкатили ИИ-фичу в прод, а она галлюцинирует, падает или
🦾 Почему ваши AI-продукты на базе LLM ломаются (и как это чинить)? Выкатили ИИ-фичу в прод, а она галлюцинирует, падает или выдает мусор? Приглашаем на открытый вебинар, где разберем реальную боль внедрения LLM-агентов и научимся делать так, чтобы «всё работало». 🗓 Когда: 14 мая в 19:00 МСК ⏱️ Формат: 60 минут мяса + 30 минут ответов на ваши вопросы 🧑🏻‍💻 Кто вещает: Эмиль Сатаев — Backend Platform Developer (8+ лет в разработке). Человек, который своими руками внедряет LLM и агентные системы в реальные коммерческие сервисы. 🎁 Главный бонус для онлайна: Только участникам прямого эфира подарим уникальный промокод на скидку 10.000 ₽ на большой курс AgentOps. 👉 Занять место на вебинаре

Расскажите о паттерне Factory Method Factory Method — порождающий паттерн, который определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов. 🔹 Когда использовать: Когда заранее неизвестны типы и зависимости объектов, или когда нужно делегировать создание объектов подклассам. 🔹 Как работает: Создается абстрактный метод для создания объектов, а конкретные подклассы переопределяют его, возвращая нужные типы. 🔹 Плюсы:избавляет от привязки к конкретным классам;упрощает добавление новых типов продуктов;следует Open/Closed Principle.

Расскажите о паттерне Adapter Adapter (Адаптер) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли "переходника" между двумя интерфейсами. 🔹 Когда использовать: Когда нужно использовать существующий класс, но его интерфейс не соответствует требуемому. Например, при интеграции сторонних библиотек или работе с легаси-кодом.