Питання на співбесіді: HTTP та Request
Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів
3 питання
Через об'єкт 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').
Валідацію можна писати просто в контролері:
public function store(Request $request)
{
$data = $request->validate([
'title' => ['required', 'string', 'max:255'],
'body' => ['required'],
]);
}
Для двох правил цього досить. Коли їх десяток, а та сама форма ще й редагується, контролер розпухає, а правила дублюються між store() і update().
Form Request виносить це в окремий клас:
php artisan make:request StorePostRequest
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->can('create', Post::class);
}
/**
* @return array<string, list<string>>
*/
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'body' => ['required', 'string'],
'published_at' => ['nullable', 'date'],
];
}
public function messages(): array
{
return ['title.required' => 'Вкажіть заголовок вакансії.'];
}
}
Використання - тип у сигнатурі:
public function store(StorePostRequest $request)
{
// сюди виконання дійде лише з валідними даними
$post = Post::create($request->validated());
}
Що це дає: валідація й перевірка прав відбуваються до входу в метод; контролер лишається про свою справу; правила лежать в одному місці й перевикористовуються; prepareForValidation() дозволяє нормалізувати вхід (обрізати пробіли, привести формат) до перевірки.
Деталь, яку часто пропускають: authorize(), що повертає false, дає 403 - тобто Form Request закриває і валідацію, і доступ.
Http - обгортка над Guzzle з розумними значеннями за замовчуванням, але саме за замовчуванням і ховаються проблеми.
Базовий виклик:
$response = Http::withToken($token)
->timeout(5)
->retry(3, 200)
->get('https://api.example/vacancies', ['page' => 1]);
if ($response->failed()) {
// ...
}
$data = $response->json();
Чотири речі, без яких у прод виходити не варто:
1. Таймаут. За замовчуванням запит може висіти 30 секунд, тримаючи PHP-воркер. Чужий сервіс, що «підвис», кладе ваш застосунок, а не свій. timeout(5) і connectTimeout(2) обовʼязкові.
2. Повтори з паузою. retry(3, 200) рятує від разових збоїв, але повторювати можна лише ідемпотентні запити: повтор POST про створення платежу створить його двічі.
3. Обробка помилки. Http не кидає виняток на 4xx/5xx - повертає відповідь із failed() === true. Код, що одразу робить ->json()['id'], отримає null і піде далі, ніби все гаразд. Або перевіряйте явно, або ставте ->throw().
4. Ізоляція від збоїв. Виклик чужого API під час обробки запиту робить вашу доступність залежною від чужої. Такі виклики належать у чергу, а на повторювані збої добре лягає circuit breaker.
У тестах - Http::fake(), щоб мережі не було зовсім:
Http::fake(['api.example/*' => Http::response(['id' => 1], 200)]);
Http::assertSent(fn ($request) => $request->url() === 'https://api.example/vacancies');