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

Питання

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

121 питань

Фасади надають зручний статичний інтерфейс до об'єктів із Service Container.

Cache::put('key', 'value', 60);
Route::get('/', fn () => view('home'));

Попри статичний синтаксис, це не справжні статичні методи: фасад через __callStatic() дістає реальний об'єкт із контейнера й викликає метод уже на ньому. Тому фасади тестовані - їх можна мокати:

Cache::shouldReceive('get')->once()->andReturn('value');

Кожен фасад має «accessor» - рядковий ключ сервісу в контейнері.

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

  • find($id) повертає модель за первинним ключем або null.
  • findOrFail($id) повертає модель або кидає ModelNotFoundException, яку Laravel автоматично перетворює на HTTP 404.
$post = Post::find($id);
if (! $post) { abort(404); } // ручна перевірка

$post = Post::findOrFail($id); // те саме одним рядком

findOrFail робить контролери чистішими. Аналогічна пара для запитів - first() / firstOrFail().

Докладніше в документації: Eloquent: не знайдено / findOrFail

Це «upsert»-методи, що позбавляють від ручних перевірок «існує / не існує».

// знайти за email; якщо нема - створити з усіма атрибутами
User::firstOrCreate(
    ['email' => $email],
    ['name' => $name]
);

// знайти за email; оновити name; якщо нема - створити
User::updateOrCreate(
    ['email' => $email],
    ['name' => $name]
);

Перший масив - умови пошуку, другий - значення для створення/оновлення. Споріднений firstOrNew() повертає незбережений екземпляр.

Докладніше в документації: Eloquent: upsert-методи

Базовий layout оголошує «дірки» через @yield, дочірні шаблони їх заповнюють:

{{-- layouts/app.blade.php --}}
<html><body>
    <main>@yield('content')</main>
</body></html>
{{-- posts/show.blade.php --}}
@extends('layouts.app')

@section('content')
    <h1>{{ $post->title }}</h1>
@endsection

Навіщо: загальна розмітка (шапка, футер, підключення ассетів) описується один раз. Альтернатива - Blade-компоненти (<x-layout> зі слотами), які в нових проєктах часто витісняють @extends.

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

Blade-компоненти - багаторазові елементи UI, які підключаються тегом:

<x-alert type="error" :message="$error" />

Бувають:

  • Анонімні - лише файл resources/views/components/alert.blade.php.
  • Класові - php artisan make:component Alert, з PHP-класом для логіки.

Дані передаються атрибутами, контент - через слоти:

{{-- components/card.blade.php --}}
<div class="card">
    <h2>{{ $title }}</h2>
    {{ $slot }}
</div>

Чистіше за @include, бо мають явний інтерфейс (props) та інкапсуляцію.

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

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

Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
route('posts.show', $post); // у PHP
<a href="{{ route('posts.show', $post) }}">Деталі</a>

Навіщо: якщо URL зміниться (/posts/articles), достатньо поправити маршрут - усі посилання оновляться автоматично. Також redirect()->route('posts.show', $post).

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

Route::resource() одним рядком реєструє 7 маршрутів за RESTful-конвенцією:

Route::resource('posts', PostController::class);
Метод URL Дія
GET /posts index
GET /posts/create create
POST /posts store
GET /posts/{post} show
GET /posts/{post}/edit edit
PUT/PATCH /posts/{post} update
DELETE /posts/{post} destroy
  • apiResource() - те саме без create/edit (для API).
  • ->only([...]) / ->except([...]) обмежують набір.

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

Backed enum - перелік зі скалярним значенням, прив'язаним до кожного кейса:

enum Status: string
{
    case Draft = 'draft';
    case Published = 'published';
}

Інтеграція з Laravel:

// каст у моделі - атрибут стає об'єктом enum
protected $casts = ['status' => Status::class];

// валідація
$request->validate(['status' => [Rule::enum(Status::class)]]);

// Route Model Binding теж резолвить enum з URL

Enum робить «магічні рядки» типобезпечними, а методи на enum (label(), color()) зручно інкапсулюють логіку відображення.

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

Файл приходить через $request->file(); зберігають через фасад Storage:

$request->validate([
    'avatar' => ['required', 'image', 'max:2048'], // до 2 МБ
]);

$path = $request->file('avatar')->store('avatars', 'public');
// або з випадковим унікальним іменем - store() уже так робить

$user->update(['avatar_path' => $path]);
  • store() повертає шлях для збереження в БД.
  • Публічний URL - Storage::url($path) (потребує php artisan storage:link).
  • Валідатори image, mimes:pdf,docx, max: (в КБ) убезпечують від небажаних файлів.

Докладніше в документації: Зберігання файлів

Верифікація email підтверджує, що користувач справді володіє вказаною адресою. Laravel має це з коробки.

// 1. Модель реалізує контракт
class User extends Authenticatable implements MustVerifyEmail {}

// 2. Маршрути захищають middleware
Route::get('/dashboard', ...)->middleware(['auth', 'verified']);

Як працює: після реєстрації Laravel шле лист із підписаним URL (signed URL), перехід за яким ставить email_verified_at. Middleware verified не пускає непідтверджених користувачів. Подія Registered автоматично тригерить відправку листа.

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

Service Container (IoC-контейнер) керує залежностями класів і виконує dependency injection. Він уміє автоматично будувати об'єкти, рекурсивно резолвлячи їхні залежності через type-hints конструктора.

// біндинг інтерфейсу до реалізації (зазвичай у Service Provider)
$this->app->bind(PaymentGateway::class, StripeGateway::class);

// тепер усюди, де просять PaymentGateway, прийде StripeGateway
public function __construct(private PaymentGateway $gateway) {}
  • bind() - нова реалізація щоразу.
  • singleton() - один екземпляр на весь життєвий цикл запиту.
  • app(PaymentGateway::class) - ручне резолвлення.

Це серце Laravel: контролери, middleware, події - усе резолвиться через контейнер.

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

N+1 виникає, коли ви завантажуєте N моделей одним запитом, а потім у циклі звертаєтесь до їхнього зв'язку - це генерує ще N запитів.

$posts = Post::all(); // 1 запит
foreach ($posts as $post) {
    echo $post->author->name; // +1 запит на кожен пост → N запитів
}

Рішення - eager loading через with():

$posts = Post::with('author')->get(); // лише 2 запити загалом

Вкладені та умовні зв'язки:

Post::with(['author', 'comments.user'])->get();        // вкладений eager
Post::with(['comments' => fn ($q) => $q->latest()])->get(); // умовний

Лічильники без завантаження зв'язку - withCount() (без N+1 і без вантаження самих рядків):

$posts = Post::withCount('comments')->get(); // доступ через $post->comments_count

Виявлення: Model::preventLazyLoading(! app()->isProduction()) у boot() кидає виняток на ледачих завантаженнях поза продакшеном; також допомагають Telescope і Debugbar.

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

Service Providers - центральне місце бутстрапу застосунку. Саме тут реєструються біндинги контейнера, слухачі подій, middleware, маршрути та публікація конфігів.

class AppServiceProvider extends ServiceProvider
{
    // лише біндинги в контейнер
    public function register(): void
    {
        $this->app->singleton(Parser::class);
    }

    // виконується після реєстрації всіх провайдерів
    public function boot(): void
    {
        Gate::define('admin', fn ($u) => $u->is_admin);
    }
}

Правило: у register() - лише біндинги (інші сервіси можуть бути ще не зареєстровані); у boot() - усе інше.

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

Події дають слабке зв'язування: одна частина застосунку «оголошує», що щось сталося, інші - реагують, нічого не знаючи одна про одну.

event(new OrderShipped($order)); // диспатч

// слухач
class SendShipmentNotification
{
    public function handle(OrderShipped $event): void
    {
        // ...
    }
}
  • Слухача, що реалізує ShouldQueue, обробляють асинхронно в черзі.
  • У сучасному Laravel слухачі автоматично виявляються за type-hint у методі handle - ручна реєстрація не обов'язкова.

Приклад: подія UserRegistered → слухачі «надіслати лист», «нарахувати бонус», «оновити статистику».

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

Queue дозволяє відкласти важку роботу (Job) у фон, щоб не змушувати користувача чекати.

class ProcessPodcast implements ShouldQueue
{
    public function handle(): void { /* важка робота */ }
}

ProcessPodcast::dispatch($podcast)->onQueue('media');
  • Драйвери черг: database, redis, sqs (config/queue.php).
  • Воркер обробляє завдання: php artisan queue:work.
  • Підтримка повторів ($tries, backoff), затримок (->delay()), middleware для завдань.

Типове застосування: email, обробка зображень, виклики зовнішніх API, генерація звітів.

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