Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Питання

Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів

171 питань

Soft Deletes - «м'яке» видалення: запис не стирається фізично, а отримує мітку часу в колонці deleted_at. Такі записи автоматично виключаються з усіх запитів.

class Post extends Model
{
    use SoftDeletes; // + $table->softDeletes() у міграції
}

$post->delete(); // ставить deleted_at
Post::withTrashed()->get(); // включно з видаленими
$post->restore(); // відновити
$post->forceDelete(); // видалити назавжди

Навіщо: можливість відновлення, аудит, збереження посилальної цілісності.

Докладніше в документації: Soft Deletes

Через об'єкт Request, який Laravel автоматично впроваджує в метод контролера:

public function store(Request $request)
{
    $name = $request->input('name', 'default');
    $email = $request->string('email'); // типізовані хелпери
    $active = $request->boolean('active');
    $all = $request->only(['name', 'email']);
}

Динамічний доступ $request->name теж працює, але його уникають через можливі колізії з параметрами маршруту. Для файлів - $request->file('avatar'), для перевірки наявності - $request->has('key').

Докладніше в документації: HTTP-запити

Artisan - CLI Laravel. Він прискорює рутину: генерацію класів, міграції, очищення кешу, запуск черг тощо.

php artisan list # усі команди
php artisan make:model Post -mfsc # модель + міграція, фабрика, сідер, контролер
php artisan migrate
php artisan queue:work
php artisan tinker # інтерактивна REPL-консоль

Під капотом Artisan побудований на Symfony Console. Можна писати власні команди через make:command.

Докладніше в документації: Artisan Console

Сесії зберігають стан користувача між запитами. Laravel дає єдиний API поверх різних драйверів (file, cookie, database, redis), що налаштовуються в config/session.php.

session(['cart_id' => 42]); // записати
$id = session('cart_id');   // прочитати
$request->session()->forget('cart_id'); // видалити
session()->flush();         // очистити все

Для продакшену з кількома серверами зазвичай обирають redis або database, щоб сесія була спільною між інстансами.

Докладніше в документації: Сесії

Flash Data - дані, що живуть у сесії лише до наступного запиту й потім автоматично видаляються. Класичне застосування - повідомлення про результат дії після редиректу.

return redirect('/dashboard')->with('status', 'Профіль оновлено!');
@if (session('status'))
    <div class="alert">{{ session('status') }}</div>
@endif

Під капотом - session()->flash('key', $value). Метод reflash() продовжує життя flash-даних ще на один запит.

Докладніше в документації: Flash-дані сесії

Права описують у Gate або Policy, а перевіряють у трьох місцях: контролері, шаблоні й формі запиту.

У контролері - authorize(), який кидає 403 сам:

public function update(Request $request, Post $post)
{
    $this->authorize('update', $post);

    // сюди дійде лише той, кому можна
}

Або через фасад, коли потрібна саме перевірка, а не зупинка:

if (Gate::allows('update', $post)) {
    // ...
}

if ($request->user()->cannot('update', $post)) {
    abort(403);
}

У Blade - директиви, які ховають те, чого не можна:

@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}">Редагувати</a>
@endcan

@cannot('update', $post)
    <span>Тільки перегляд</span>
@endcannot

У маршруті - middleware can:

Route::put('/posts/{post}', [PostController::class, 'update'])
    ->middleware('can:update,post');

Важливо: @can у шаблоні лише ховає кнопку. Це зручність для користувача, а не захист - без перевірки в контролері запит усе одно можна надіслати вручну. Перевірка на сервері обовʼязкова завжди, навіть коли кнопки не видно.

Докладніше в документації: Авторизація

У сучасному Laravel ассети збирає Vite. У шаблоні підключають директивою @vite:

@vite(['resources/css/app.css', 'resources/js/app.js'])

Під час розробки (npm run dev) Vite віддає файли з hot-reload; на продакшені (npm run build) - зібрані файли з хешами в імені для cache busting.

Для статичних файлів із public/ використовують хелпер asset('images/logo.png').

Докладніше в документації: Vite та ассети

Вони перетворюють атрибути моделі «на льоту». У сучасному Laravel обидва описуються одним методом, що повертає Attribute:

protected function name(): Attribute
{
    return Attribute::make(
        get: fn (string $value) => ucfirst($value), // accessor (читання)
        set: fn (string $value) => strtolower($value), // mutator (запис)
    );
}
  • Accessor форматує значення при отриманні ($user->name).
  • Mutator форматує значення перед збереженням у БД.

Корисно для форматування, нормалізації або роботи з Value Objects.

Докладніше в документації: Accessors та Mutators

Достатньо викликати paginate() замість get() - Laravel сам читає номер сторінки з query-параметра ?page=:

$posts = Post::latest()->paginate(15);
@foreach ($posts as $post) ... @endforeach
{{ $posts->links() }}   {{-- кнопки навігації --}}
  • paginate() рахує загальну кількість (показує «сторінка X з Y»).
  • simplePaginate() - лише «вперед/назад», без COUNT(*), швидше на великих таблицях.
  • cursorPaginate() - курсорна пагінація, найефективніша для нескінченного скролу.

Докладніше в документації: Пагінація

Найпростіше - повернути масив або модель: Laravel сам віддасть JSON із правильним заголовком.

public function show(Post $post)
{
    return $post;                       // JSON усієї моделі
}

public function stats()
{
    return ['total' => Post::count()];  // JSON масиву
}

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

API Resource - це шар між моделлю та JSON, який описує форму відповіді явно:

php artisan make:resource PostResource
class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'published_at' => $this->published_at?->toIso8601String(),
            'author' => new UserResource($this->whenLoaded('author')),
        ];
    }
}

Використання:

public function show(Post $post)
{
    return new PostResource($post);
}

public function index()
{
    return PostResource::collection(Post::paginate());
}

collection() разом із пагінацією сам додає блоки links і meta.

Що це дає: структура відповіді описана в одному місці, поля з бази не протікають назовні, дати мають єдиний формат, а whenLoaded() додає звʼязок лише тоді, коли його справді завантажили - і тим самим не створює N+1.

Докладніше в документації: Eloquent: API Resources

Route Model Binding автоматично резолвить параметр маршруту в екземпляр моделі - не треба вручну робити findOrFail().

Route::get('/posts/{post}', [PostController::class, 'show']);

// $post - вже знайдена модель
public function show(Post $post)
{
    return view('posts.show', compact('post'));
}

За замовчуванням пошук іде за id. Прив'язати за іншим стовпцем: {post:slug}. Якщо запис не знайдено - автоматично 404.

Докладніше в документації: Route Model Binding

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

Створити завдання:

php artisan make:job SendWelcomeEmail
class SendWelcomeEmail implements ShouldQueue
{
    use Queueable;

    public function __construct(public User $user)
    {
    }

    public function handle(): void
    {
        Mail::to($this->user)->send(new WelcomeMail($this->user));
    }
}

Інтерфейс ShouldQueue - це і є те, що відправляє завдання в чергу, а не виконує одразу.

Поставити в чергу:

SendWelcomeEmail::dispatch($user);
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));

Запустити воркер:

php artisan queue:work

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

Що виносити не варто: те, результат чого користувач має побачити просто зараз. Черга - асинхронна, і відповідь її не дочекається.

Головна пастка новачка: у завдання передається модель, а Laravel серіалізує лише її ключ і перечитує запис у воркері. Якщо між постановкою й виконанням запис видалили, завдання впаде. Тому в чергу передають ідентифікатори або готові дані, а не громіздкі обʼєкти.

Докладніше в документації: Черги

Згенерувати клас і описати логіку в handle():

php artisan make:command SendReports
class SendReports extends Command
{
    protected $signature = 'reports:send {--month=}';
    protected $description = 'Розіслати місячні звіти';

    public function handle(): int
    {
        $this->info('Відправка...');
        return self::SUCCESS;
    }
}

Аргументи й опції описуються в $signature. Команду можна запускати вручну або ставити в розклад через Schedule::command('reports:send')->monthly().

Докладніше в документації: Власні команди Artisan

Factory (фабрика) генерує фейкові дані моделей через Faker. Незамінна в тестах і сідерах.

class PostFactory extends Factory
{
    public function definition(): array
    {
        return [
            'title' => fake()->sentence(),
            'body'  => fake()->paragraphs(3, true),
        ];
    }
}
Post::factory()->count(10)->create(); // 10 записів у БД
Post::factory()->published()->make(); // стан + без збереження

«Стани» (states) дозволяють описати варіації, наприклад ->published() чи ->trashed().

Докладніше в документації: Фабрики моделей

Локалізація дає багатомовність. Рядки перекладів лежать у lang/{locale} (наприклад, lang/uk/messages.php або JSON-файли).

// lang/uk/messages.php
return ['welcome' => 'Ласкаво просимо, :name'];
{{ __('messages.welcome', ['name' => $user->name]) }}
  • app()->setLocale('uk') перемикає мову (зазвичай у middleware).
  • trans_choice() обирає форму за кількістю (1 яблуко / 2 яблука / 5 яблук).

Докладніше в документації: Локалізація

Питання з реальних співбесід Laravel і PHP - 171 питання у 41 темі, розібраних із відповідями. Нижче - розбивка за рівнями та темами, якщо хочете звузити підготовку.

Рівні
Junior 52 Middle 57 Senior 62

Готуєтесь до співбесіди не просто так: зараз на сайті 167 відкритих вакансій Laravel і PHP. Переглянути вакансії