Питання
Найпопулярніші питання з реальних 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(); // видалити назавжди
Навіщо: можливість відновлення, аудит, збереження посилальної цілісності.
Через об'єкт 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').
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.
Сесії зберігають стан користувача між запитами. 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-даних ще на один запит.
Права описують у 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').
Вони перетворюють атрибути моделі «на льоту». У сучасному 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.
Достатньо викликати 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.
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.
Черга дозволяє відкласти повільну роботу: замість того щоб виконувати її під час запиту й тримати користувача, застосунок ставить завдання в чергу й одразу повертає відповідь. Окремий процес - воркер - виконує її згодом.
Створити завдання:
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().
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 темі, розібраних із відповідями. Нижче - розбивка за рівнями та темами, якщо хочете звузити підготовку.
- Теми
- Eloquent 19 Архітектура 12 Database 10 Performance 7 Routing 5 Безпека 5 Blade 5 API 5
Готуєтесь до співбесіди не просто так: зараз на сайті 167 відкритих вакансій Laravel і PHP. Переглянути вакансії