<? phpukraine СТАТТІ
Пошук по платформі
КАРʼЄРА 15 вересня 2026 · 8 хв читання

Перша робота PHP-розробника у 2026: що просять у junior-вакансіях насправді

У каталозі порталу 78 активних вакансій від 63 компаній, і junior-позначку мають шість із них. Я прочитав ці шість по тексту оголошень і поклав поруч частоти технологій з усього каталогу: junior-вимоги виявились верхніми чотирма рядками загального списку, з яких прибрали все дороге.

РP
Редакція phpukraine
Редакція платформи

Каталог порталу збирає PHP-вакансії з DOU, Djinni і robota.ua, розкладає їх на поля (рівень, фреймворк, формат, англійська, теги) і тримає активними, поки оголошення живе на джерелі. Зараз в ньому 78 активних вакансій від 63 компаній, опубліковані з 3 серпня по 3 вересня 2026. Це вся вибірка, з якою я працюю нижче. Жодних «за нашими спостереженнями»: усе, що тут є, можна перерахувати самому на /jobs.

Перше число задає тон усьому іншому. За рівнями 78 вакансій діляться так: middle 28, senior 28, lead 8, без позначки рівня 8, junior 6.

Шість оголошень, і два з них справді без досвіду

Шість це мало, і я не буду вдавати, що з шести можна порахувати відсотки ринку. Зате шість оголошень читаються цілком, рядок за рядком, і з цього виходить більше користі, ніж з будь-якої агрегації.

Джерела розподілились так: три з robota.ua, два з DOU, одне з Djinni. Шість різних компаній, повторів немає.

Тепер найнеприємніше. З шести junior-оголошень чотири просять або рік комерційного досвіду, або підтверджене портфоліо комерційних проєктів. Одне з них у заголовку каталогу junior, а в тексті прямо називає шуканий рівень Middle: парсер взяв рівень з вимоги «комерційний досвід 1+ роки з PHP», а компанія словом «junior» себе не описує взагалі. Ще одне шукає Strong Junior від року досвіду. Ще одне вимагає «не менше 1 років на позиції Junior Back-end». Четверте просить proven experience і сильне портфоліо.

Без комерційного досвіду в каталозі відкриті дві позиції з шести. Одна з них WordPress в офісі, з вимогами «вища профільна освіта» і «знання платформи WordPress». Друга віддалена, backend або fullstack, де PHP один з п'яти прийнятних варіантів поряд з Python, Java, C# і Node.js, а замість досвіду просять портфоліо чи власні проєкти.

Звідси й практичний висновок про вхід у професію станом на сьогодні: позначка junior у вакансії найчастіше означає «рік уже відпрацював десь».

Чотири теги, які повторюються

Теги в каталозі витягуються з тексту оголошення. По шести junior-вакансіях частоти такі: MySQL 4, REST API 4, Docker 3, Git 3, далі PostgreSQL 2, PHP 2, Microservices 2, і одиничні згадки RabbitMQ, PHPUnit, CI/CD, AWS, Redis, ACF.

Тепер той самий підрахунок по всіх 78 вакансіях: REST API 46, MySQL 42, Docker 42, Git 33, PostgreSQL 27, Redis 24, PHP 8 23, RabbitMQ 20, Microservices 20, CI/CD 20.

Верхівка збігається. Чотири речі, які повторюються в junior-оголошеннях, це чотири речі, які найчастіше повторюються в усьому каталозі незалежно від грейду. Ніякого окремого «junior-стека» в даних немає. Різниця в глибині, а не в переліку.

Що це означає на рівні коду: одного ендпоінта достатньо, щоб показати три з чотирьох пунктів одразу.

final class OrderController
{
    public function index(Request $request): JsonResponse
    {
        $data = $request->validate([
            'status' => ['required', Rule::enum(OrderStatus::class)],
            'per_page' => ['integer', 'between:1,100'],
        ]);

        $orders = Order::query()
            ->select(['id', 'number', 'status', 'total_cents', 'created_at'])
            ->where('status', $data['status'])
            ->orderByDesc('id')
            ->paginate($data['per_page'] ?? 20);

        return OrderResource::collection($orders)->response();
    }
}

Валідація входу окремо від запиту, вибираються тільки потрібні колонки, пагінація замість get() на всю таблицю. Під це потрібен складений індекс (status, id), щоб і фільтр, і сортування читалися з одного індексу, а EXPLAIN на цьому запиті показував index scan замість сортування всієї вибірки. Формулювання з того самого оголошення на Djinni звучить як «розумієш індекси й пишеш чисті запити», і мається на увазі приблизно цей рівень, а не оптимізація планів на мільйонних таблицях.

Чого в junior-оголошеннях немає жодного разу

Redis згадується в 24 вакансіях каталогу і в одній junior. Kafka у 12 і в жодній junior. Kubernetes у 7 і в жодній. High Load, Elasticsearch, GraphQL, Swoole на вході не зустрічаються взагалі.

Середня кількість тегів на junior-оголошення 4.8, по всьому каталогу 5.7. Список вимог на вході не коротший в рази, він коротший на одну позицію, і саме ця позиція зазвичай і є найдорожчою для вивчення.

Черги згадані в одному junior-оголошенні з шести проти 23 з 78 загалом, причому в тому єдиному вони в розділі «буде плюсом» з припискою, що підкажуть. SOLID просить одне junior-оголошення з шести, тоді як по всьому каталогу 29 з 78.

Англійська, формат і гроші

Слово «англійська» чи English не зустрічається в жодному з шести junior-оголошень. У каталозі загалом англійську згадують 32 вакансії з 78, а рівень явно вказаний у 24 (B2 у 12, A2–B1 у 10, C1 у 2). На junior-позиціях поле рівня англійської порожнє в усіх шести.

Читати це варто обережно. Відсутність вимоги в тексті не означає, що на співбесіді не запитають. Але якщо ви відкладаєте відгук, поки не підтягнете англійську, дані каталогу такої відстрочки не виправдовують.

Формат: чотири з шести віддалено, дві в офісі. По всьому каталогу віддалено 55, офіс 11, гібрид 2, у 10 формат не вказаний. Зайнятість: п'ять full-time, одна гіг-контрактом з переходом на повну по мірі розширення задач.

Зарплату вказують дві junior-вакансії з шести (по всьому каталогу 14 з 78), і обидві WordPress: одна фіксовані 795 доларів, друга вилка 800–1300. Два числа це два числа, а не медіана ринку. Рахувати з них нічого не можна, і я не рахую.

Окрема дрібниця, яка суперечить очікуванням: тестове завдання згадане рівно в одному оголошенні з 78, і саме там написано, що воно буває лише у виняткових випадках, коли за кодом і розмовою важко оцінити підхід. Процес найму описують взагалі рідко, тож правильний висновок тут не «тестових не дають», а «наперед ви цього не знаєте».

Symfony на вході не трапляється

За фреймворками 78 активних вакансій діляться так: Laravel 33, Symfony 16, чистий PHP без фреймворку 13, WordPress 6, Yii 6, Drupal 2, Magento 1.

Серед шести junior-позицій: Laravel 4, WordPress 2. Symfony нуль, при шістнадцяти відкритих Symfony-вакансіях у каталозі. Yii, Drupal і Magento на вході теж не трапляються.

Питання не в якості фреймворків, а в тому, куди беруть без досвіду: Laravel і WordPress зараз єдині два входи в каталозі, і якщо ви обираєте, з чого почати заради першої роботи, вибір по цих даних складається сам.

Портфоліо важить більше, ніж перелік

Два junior-оголошення з шести просять посилання на GitHub, два прямо пишуть, що пет-проєкти зараховуються. По всьому каталогу GitHub згадують 10 вакансій з 78, і майже всі згадки на junior-рівні. Це єдина вимога, де вхідні позиції випереджають старші.

Формулювання з одного оголошення я перекажу близько до тексту: додайте посилання на код чи приклади проєктів, навіть пет-проєкт покаже підхід краще, ніж перелік технологій. У репозиторії за хвилину видно рівно дві речі: чи є типи і чи можна це протестувати.

final readonly class ImportPrices
{
    public function __construct(
        private PriceFeed $feed,
        private PriceRepository $prices,
    ) {}

    public function __invoke(string $supplier): ImportResult
    {
        $imported = 0;
        $skipped = 0;

        foreach ($this->feed->rows($supplier) as $row) {
            if ($row->priceCents <= 0) {
                $skipped++;

                continue;
            }

            $this->prices->upsert($supplier, $row->sku, $row->priceCents);
            $imported++;
        }

        return new ImportResult($imported, $skipped);
    }
}

Клас нічого не знає ні про HTTP, ні про консоль, залежності приходять через конструктор, тож тест пишеться без бази й без мережі:

it('skips rows with a non-positive price', function () {
    $feed = new FakeFeed([
        new PriceRow('SKU-1', 1200),
        new PriceRow('SKU-2', 0),
    ]);

    $result = (new ImportPrices($feed, new InMemoryPrices()))('supplier-1');

    expect($result->imported)->toBe(1)
        ->and($result->skipped)->toBe(1);
});

Це рівно те, що перевіряють на технічній розмові з переглядом коду, яку описує єдине junior-оголошення з розписаним процесом найму.

Як користуватись цими числами

Каталог оновлюється, і шість junior-вакансій сьогодні не означають шість завтра. Тому корисніше не запам'ятовувати цифри, а відкривати /jobs?level=junior раз на тиждень і дивитися на поточний зріз самому: при такому обсязі нові оголошення видно за хвилину, а конкуренція за них вирішується швидкістю відгуку.

З постійного, що дають дані: MySQL, REST API, Docker і Git повторюються і на вході, і далі, тож це вимоги, які супроводжуватимуть вас наступні кілька років, а зовсім не «мінімум для junior». Redis, черги, Kafka і Kubernetes на вході не питають взагалі, і витрачати на них час до першої роботи немає з чого. Symfony-позицій без досвіду в каталозі немає, тож першою роботою реалістично буде Laravel або WordPress. І головне число: з шести junior-вакансій дві не вимагають комерційного досвіду, а решта чотири вимагають рік або портфоліо. Портфоліо ви можете зробити самі вже цього місяця, рік досвіду ні.

ПИШЕТЕ ПРО PHP?Опублікуйте розбір або історію з проєкту на платформіРедактор із чеклістом, редактура, авторська сторінка. Републікація з блогу отримує canonical на оригінал. Відкрити редактор →
РP
Редакція phpukraine
Редакція платформи
Матеріали, які готує команда платформи на основі власних даних: каталогу вакансій, зарплатного звіту й банку питань. Кожна цифра в них рахується з бази, а не береться з голови.
оновлено 15 вересня 2026 · ліцензія CC-BY-SA-4.0
ДАЛІ ПО ТЕМІ
ЧИТАТИ ДАЛІ
← Усі статті