Domande per colloqui Laravel e PHP: le Top 25 nel 2026
Le 25 domande piu frequenti nei colloqui Laravel e PHP. Eloquent ORM, middleware, Artisan, code, test e architettura con risposte dettagliate ed esempi di codice.

I colloqui tecnici su Laravel valutano la padronanza del framework PHP piu diffuso, la comprensione dell'ORM Eloquent, dell'architettura MVC e la capacita di costruire applicazioni robuste e manutenibili. Questa guida affronta le 25 domande piu frequenti, dai fondamenti di Laravel fino ai pattern avanzati di deploy in produzione.
Gli intervistatori apprezzano i candidati capaci di spiegare le scelte architetturali di Laravel. Comprendere perche il framework adotta determinate convenzioni (Convention over Configuration, Service Container) fa una reale differenza durante i colloqui.
Fondamenti di Laravel
Domanda 1: Il Request Lifecycle in Laravel
Il ciclo di vita di una richiesta in Laravel attraversa diversi livelli prima di raggiungere il controller. La comprensione di questo ciclo e essenziale per il debug e l'ottimizzazione delle prestazioni.
// Entry point for all HTTP requests
require __DIR__.'/../vendor/autoload.php';
// Load the Laravel application
$app = require_once __DIR__.'/../bootstrap/app.php';
// The HTTP kernel handles the request
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);Il ciclo completo: index.php → autoload → bootstrap → service providers → middlewares → routing → controller → response → terminate. Ogni passaggio puo essere intercettato e personalizzato.
Domanda 2: Cos'e il Service Container e come funziona la Dependency Injection?
Il Service Container e il cuore di Laravel. Gestisce l'istanziazione delle classi e risolve automaticamente le dipendenze tramite constructor injection.
// Service with automatically injected dependencies
namespace App\Services;
use App\Contracts\PaymentGatewayInterface;
use App\Repositories\OrderRepository;
use Illuminate\Support\Facades\Log;
class PaymentService
{
public function __construct(
private PaymentGatewayInterface $gateway, // Interface resolved by container
private OrderRepository $orders // Concrete class auto-resolved
) {}
public function processPayment(int $orderId, float $amount): bool
{
$order = $this->orders->find($orderId);
try {
$result = $this->gateway->charge($amount, $order->customer);
$order->markAsPaid($result->transactionId);
return true;
} catch (PaymentException $e) {
Log::error('Payment failed', ['order' => $orderId, 'error' => $e->getMessage()]);
return false;
}
}
}// Binding an interface to a concrete implementation
public function register(): void
{
// Simple binding: new instance on each injection
$this->app->bind(
PaymentGatewayInterface::class,
StripeGateway::class
);
// Singleton: same instance shared everywhere
$this->app->singleton(
CacheService::class,
fn($app) => new CacheService($app['config']['cache.driver'])
);
}La dependency injection disaccoppia le classi e facilita gli unit test attraverso il mocking.
Domanda 3: Qual e la differenza tra Facades e Dependency Injection?
Le Facades offrono una sintassi statica per accedere ai servizi del container, mentre la dependency injection rende le dipendenze esplicite.
// Using Facades: concise syntax but implicit dependencies
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class ReportController extends Controller
{
public function generate()
{
// Facades: static access to services
$data = Cache::remember('report_data', 3600, fn() => $this->fetchData());
Log::info('Report generated');
return view('report', compact('data'));
}
}
// Dependency Injection: explicit and testable dependencies
use Illuminate\Contracts\Cache\Repository as CacheContract;
use Psr\Log\LoggerInterface;
class ReportController extends Controller
{
public function __construct(
private CacheContract $cache,
private LoggerInterface $logger
) {}
public function generate()
{
// Same functionality, explicit dependencies
$data = $this->cache->remember('report_data', 3600, fn() => $this->fetchData());
$this->logger->info('Report generated');
return view('report', compact('data'));
}
}Nelle classi di business la dependency injection e preferibile per la testabilita. Le Facades sono adatte per helper e codice ad-hoc.
Domanda 4: Come funzionano i Service Providers in Laravel?
I Service Providers sono il punto di configurazione centrale dell'applicazione. Ogni provider registra servizi, configura binding e inizializza componenti.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\PaymentService;
use App\Contracts\PaymentGatewayInterface;
use App\Gateways\StripeGateway;
class PaymentServiceProvider extends ServiceProvider
{
// Register method: bindings and registrations
// Don't access other services here (not yet loaded)
public function register(): void
{
$this->app->singleton(PaymentGatewayInterface::class, function ($app) {
return new StripeGateway(
config('services.stripe.key'),
config('services.stripe.secret')
);
});
}
// Boot method: initialization after all providers
// Full access to all application services
public function boot(): void
{
// Register macros, event listeners, routes, etc.
$this->loadRoutesFrom(__DIR__.'/../routes/payment.php');
$this->loadViewsFrom(__DIR__.'/../resources/views', 'payment');
// Publish files for packages
$this->publishes([
__DIR__.'/../config/payment.php' => config_path('payment.php'),
], 'payment-config');
}
}Ordine di esecuzione: prima tutti i metodi register(), poi tutti i metodi boot(). Questo ordine garantisce che le dipendenze siano disponibili durante la fase di boot.
Eloquent ORM
Domanda 5: Le relazioni Eloquent e le loro differenze
Eloquent fornisce diversi tipi di relazione per modellare le associazioni tra tabelle. Ogni tipo ha casi d'uso specifici.
class User extends Model
{
// A user has one profile (1:1)
public function profile(): HasOne
{
return $this->hasOne(Profile::class);
}
// A user has many articles (1:N)
public function articles(): HasMany
{
return $this->hasMany(Article::class);
}
// A user has many roles via pivot table (N:N)
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class)
->withPivot('assigned_at') // Additional pivot columns
->withTimestamps(); // created_at/updated_at on pivot
}
// A user has many comments through articles (HasManyThrough)
public function comments(): HasManyThrough
{
return $this->hasManyThrough(
Comment::class, // Final model
Article::class // Intermediate model
);
}
}
// app/Models/Article.php
class Article extends Model
{
// An article belongs to a user (inverse of hasMany)
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
// Polymorphic relationship: an article can have tags, like other models
public function tags(): MorphToMany
{
return $this->morphToMany(Tag::class, 'taggable');
}
}Le relazioni polimorfiche (morphOne, morphMany, morphToMany) permettono a un model di essere associato a piu tipi di model diversi attraverso un'unica relazione.
Domanda 6: Il problema N+1 e come risolverlo con l'Eager Loading
Il problema N+1 si verifica quando una query principale genera N query aggiuntive per caricare le relazioni. E la causa piu comune di rallentamenti nelle applicazioni Laravel.
// ❌ PROBLEM: N+1 queries
// 1 query for articles + 1 query PER article for the author
$articles = Article::all();
foreach ($articles as $article) {
echo $article->author->name; // SQL query on each iteration!
}
// ✅ SOLUTION 1: with() - Eager Loading
// Only 2 queries (articles + users with IN clause)
$articles = Article::with('author')->get();
foreach ($articles as $article) {
echo $article->author->name; // Already loaded, no query
}
// ✅ SOLUTION 2: Nested Eager Loading
// Loads articles, their authors, and author roles
$articles = Article::with(['author.roles', 'comments.user'])->get();
// ✅ SOLUTION 3: Eager Loading with constraints
$articles = Article::with([
'comments' => function ($query) {
$query->where('approved', true)
->orderBy('created_at', 'desc')
->limit(5);
}
])->get();
// ✅ SOLUTION 4: Default Eager Loading in the model
class Article extends Model
{
// These relationships are always loaded automatically
protected $with = ['author', 'category'];
}Con php artisan telescope:prune e Laravel Telescope e possibile individuare i problemi N+1 durante lo sviluppo.
Domanda 7: Creare e utilizzare i Query Scopes
I Query Scopes incapsulano condizioni di query riutilizzabili a livello di model, rendendo il codice piu leggibile e DRY.
class Article extends Model
{
// Global Scope: automatically applied to ALL queries
protected static function booted(): void
{
// Excludes soft-deleted articles by default
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('status', 'published');
});
}
// Local Scope: called explicitly via scopeScopeName
public function scopePopular(Builder $query, int $minViews = 1000): Builder
{
return $query->where('view_count', '>=', $minViews);
}
public function scopeByAuthor(Builder $query, User $author): Builder
{
return $query->where('user_id', $author->id);
}
public function scopeRecent(Builder $query, int $days = 7): Builder
{
return $query->where('created_at', '>=', now()->subDays($days));
}
public function scopeWithStats(Builder $query): Builder
{
return $query->withCount('comments')
->withSum('reactions', 'score');
}
}
// Usage: fluent scope chaining
$articles = Article::popular(500)
->recent(30)
->byAuthor($user)
->withStats()
->orderByDesc('comment_count')
->paginate(20);
// Ignore a Global Scope
$allArticles = Article::withoutGlobalScope('published')->get();Gli scope locali migliorano la leggibilita e centralizzano la logica delle query. Gli scope globali sono adatti per la multi-tenancy o il soft delete.
Pronto a superare i tuoi colloqui su Laravel?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Middleware e Routing
Domanda 8: Come funzionano i Middlewares in Laravel?
I middleware filtrano le richieste HTTP in ingresso e possono modificare le risposte in uscita. Ogni richiesta attraversa uno stack di middleware.
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckSubscription
{
public function handle(Request $request, Closure $next, string $plan = 'basic'): Response
{
$user = $request->user();
// Check before the controller
if (!$user || !$user->hasActiveSubscription($plan)) {
if ($request->expectsJson()) {
return response()->json(['error' => 'Subscription required'], 403);
}
return redirect()->route('subscription.plans');
}
// Pass to next middleware or controller
$response = $next($request);
// Modify response after the controller
$response->headers->set('X-Subscription-Plan', $user->subscription->plan);
return $response;
}
}
// bootstrap/app.php (Laravel 11+)
return Application::configure(basePath: dirname(__DIR__))
->withMiddleware(function (Middleware $middleware) {
// Global middleware (all requests)
$middleware->append(LogRequestMiddleware::class);
// Aliases for use in routes
$middleware->alias([
'subscription' => CheckSubscription::class,
'role' => EnsureUserHasRole::class,
]);
// Middleware groups
$middleware->group('api', [
ThrottleRequests::class.':api',
SubstituteBindings::class,
]);
});// Applying middlewares to routes
Route::middleware(['auth', 'subscription:premium'])->group(function () {
Route::get('/dashboard', DashboardController::class);
Route::resource('projects', ProjectController::class);
});L'ordine dei middleware e determinante: vengono eseguiti dall'alto verso il basso in ingresso e dal basso verso l'alto in uscita.
Domanda 9: Route Model Binding e le sue varianti
Il Route Model Binding inietta automaticamente i model Eloquent nei controller in base ai parametri dell'URL.
// Implicit binding: Laravel automatically resolves by ID
Route::get('/articles/{article}', [ArticleController::class, 'show']);
// Binding by slug instead of ID
Route::get('/articles/{article:slug}', [ArticleController::class, 'show']);
// Binding with relationship (automatic scope)
Route::get('/users/{user}/articles/{article}', function (User $user, Article $article) {
// Laravel automatically verifies that the article belongs to the user
return $article;
})->scopeBindings();class Article extends Model
{
// Customize the default resolution key
public function getRouteKeyName(): string
{
return 'slug'; // Resolves by slug instead of id
}
// Customize the resolution query
public function resolveRouteBinding($value, $field = null): ?Model
{
return $this->where($field ?? 'slug', $value)
->where('status', 'published')
->firstOrFail();
}
}// Explicit custom binding
public function boot(): void
{
Route::bind('article', function (string $value) {
return Article::where('slug', $value)
->published()
->with('author')
->firstOrFail();
});
}Il Route Model Binding riduce il codice boilerplate e centralizza la logica di risoluzione.
Code e Jobs
Domanda 10: Implementare Jobs e Code in Laravel
Le code permettono di differire l'esecuzione di operazioni pesanti in background, migliorando la reattivita dell'applicazione.
namespace App\Jobs;
use App\Models\Podcast;
use App\Services\AudioProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// Number of attempts before final failure
public int $tries = 3;
// Timeout in seconds
public int $timeout = 600;
// Delay between attempts (exponential backoff)
public array $backoff = [30, 60, 120];
public function __construct(
public Podcast $podcast
) {}
public function handle(AudioProcessor $processor): void
{
// The job executes in the background
$processor->transcode($this->podcast->audio_path);
$processor->generateWaveform($this->podcast);
$this->podcast->update(['status' => 'processed']);
}
// Failure handling
public function failed(\Throwable $exception): void
{
$this->podcast->update(['status' => 'failed']);
// Admin notification, logging, etc.
}
// Conditions for retrying the job
public function retryUntil(): \DateTime
{
return now()->addHours(24);
}
}// Dispatching the job
ProcessPodcast::dispatch($podcast); // Default queue
ProcessPodcast::dispatch($podcast)->onQueue('audio'); // Specific queue
ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(10)); // Delay
// Job chaining (sequential execution)
Bus::chain([
new ProcessPodcast($podcast),
new GenerateThumbnail($podcast),
new NotifySubscribers($podcast),
])->dispatch();
// Job batch (parallel execution with tracking)
Bus::batch([
new ProcessPodcast($podcast1),
new ProcessPodcast($podcast2),
new ProcessPodcast($podcast3),
])->then(function (Batch $batch) {
// All jobs succeeded
})->catch(function (Batch $batch, \Throwable $e) {
// First failure
})->finally(function (Batch $batch) {
// All jobs finished (success or failure)
})->dispatch();Il worker si avvia con php artisan queue:work --queue=high,default per elaborare piu code in ordine di priorita.
Domanda 11: Differenza tra Jobs, Events e Listeners
Tutti e tre i concetti disaccoppiano il codice, ma con intenti diversi.
// Jobs: single task to execute
// Used for heavy or deferred operations
class SendWelcomeEmail implements ShouldQueue
{
public function handle(Mailer $mailer): void
{
$mailer->send(new WelcomeEmail($this->user));
}
}
// Events: notification that something happened
// The event contains only data, not logic
class UserRegistered
{
public function __construct(
public User $user,
public string $source
) {}
}
// Listeners: react to events
// An event can have multiple listeners
class SendWelcomeNotification implements ShouldQueue
{
public function handle(UserRegistered $event): void
{
$event->user->notify(new WelcomeNotification());
}
}
class TrackRegistration
{
public function handle(UserRegistered $event): void
{
Analytics::track('user_registered', [
'user_id' => $event->user->id,
'source' => $event->source,
]);
}
}protected $listen = [
UserRegistered::class => [
SendWelcomeNotification::class, // Queued
TrackRegistration::class, // Sync
CreateDefaultSettings::class, // Sync
],
];
// Triggering the event
event(new UserRegistered($user, 'web'));
// Or
UserRegistered::dispatch($user, 'web');Gli eventi favoriscono un'architettura disaccoppiata: il codice che lancia l'evento non conosce le sue conseguenze.
Sicurezza e Autenticazione
Domanda 12: Come protegge Laravel dagli attacchi CSRF?
Laravel genera automaticamente un token CSRF univoco per sessione e lo verifica ad ogni richiesta POST, PUT, PATCH e DELETE.
// In Blade forms
<form method="POST" action="/profile">
@csrf {{-- Generates a hidden field with the token --}}
@method('PUT') {{-- HTTP method spoofing --}}
<input type="text" name="name" value="{{ $user->name }}">
<button type="submit">Update</button>
</form>
// For AJAX requests, the token is in the meta tag
<meta name="csrf-token" content="{{ csrf_token() }}">
// Axios configuration to automatically send the token
axios.defaults.headers.common['X-CSRF-TOKEN'] =
document.querySelector('meta[name="csrf-token"]').content;// Exclude routes from CSRF verification (external webhooks)
return Application::configure(basePath: dirname(__DIR__))
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/webhook', // Stripe webhook authenticated by signature
'api/*', // API authenticated by token
]);
});La protezione CSRF non va mai disattivata globalmente. Le eccezioni vanno usate solo per endpoint autenticati con altri meccanismi.
Domanda 13: Implementare l'autenticazione con Laravel Sanctum
Laravel Sanctum offre un'autenticazione leggera per SPA, app mobile e API basate su token.
// Installation and configuration
// php artisan install:api (Laravel 11+)
// app/Models/User.php
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}class AuthController extends Controller
{
public function login(Request $request): JsonResponse
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required',
]);
if (!Auth::attempt($credentials)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$user = Auth::user();
// Create a token with abilities (permissions)
$token = $user->createToken('api-token', [
'articles:read',
'articles:write',
'profile:update',
]);
return response()->json([
'user' => $user,
'token' => $token->plainTextToken,
]);
}
public function logout(Request $request): JsonResponse
{
// Revoke the current token
$request->user()->currentAccessToken()->delete();
// Or revoke all tokens
// $request->user()->tokens()->delete();
return response()->json(['message' => 'Logged out']);
}
}
// routes/api.php
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', fn(Request $r) => $r->user());
Route::post('/logout', [AuthController::class, 'logout']);
// Ability verification
Route::middleware('ability:articles:write')->group(function () {
Route::post('/articles', [ArticleController::class, 'store']);
});
});Sanctum supporta anche l'autenticazione tramite cookie per SPA sullo stesso dominio, con protezione CSRF automatica.
Domanda 14: Proteggere un'API con Policies e Gates
Policies e Gates centralizzano la logica di autorizzazione, separando le regole di business dai controller.
namespace App\Policies;
use App\Models\Article;
use App\Models\User;
class ArticlePolicy
{
// Pre-check: admins have all rights
public function before(User $user, string $ability): ?bool
{
if ($user->isAdmin()) {
return true; // Allow everything
}
return null; // Continue to specific method
}
public function view(?User $user, Article $article): bool
{
// Published articles visible to all
if ($article->status === 'published') {
return true;
}
// Drafts visible only to author
return $user?->id === $article->user_id;
}
public function update(User $user, Article $article): bool
{
return $user->id === $article->user_id;
}
public function delete(User $user, Article $article): bool
{
return $user->id === $article->user_id
&& $article->comments()->count() === 0;
}
}class ArticleController extends Controller
{
public function update(Request $request, Article $article)
{
// Check policy, throws 403 if unauthorized
$this->authorize('update', $article);
$article->update($request->validated());
return redirect()->route('articles.show', $article);
}
}
// In Blade
@can('update', $article)
<a href="{{ route('articles.edit', $article) }}">Edit</a>
@endcan
// Gates for non-model authorizations
Gate::define('access-admin', function (User $user) {
return $user->role === 'admin';
});
// Usage
if (Gate::allows('access-admin')) {
// ...
}Le Policies sono legate a un model, i Gates servono per autorizzazioni generali.
Validazione e Form
Domanda 15: Creare regole di validazione personalizzate
Laravel offre diversi approcci per creare validazioni personalizzate, in base alla complessita e alle esigenze di riutilizzo.
// Custom rule as a class (reusable)
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class StrongPassword implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$errors = [];
if (strlen($value) < 12) {
$errors[] = 'at least 12 characters';
}
if (!preg_match('/[A-Z]/', $value)) {
$errors[] = 'at least one uppercase letter';
}
if (!preg_match('/[a-z]/', $value)) {
$errors[] = 'at least one lowercase letter';
}
if (!preg_match('/[0-9]/', $value)) {
$errors[] = 'at least one digit';
}
if (!preg_match('/[@$!%*?&#]/', $value)) {
$errors[] = 'at least one special character';
}
if (!empty($errors)) {
$fail("The password must contain: " . implode(', ', $errors) . '.');
}
}
}// Form Request with complex validation
namespace App\Http\Requests;
use App\Rules\StrongPassword;
use Illuminate\Foundation\Http\FormRequest;
class RegisterRequest extends FormRequest
{
public function authorize(): bool
{
return true; // Or authorization logic
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'unique:users,email'],
'password' => ['required', 'confirmed', new StrongPassword()],
'company' => ['required_if:account_type,business', 'string'],
'vat_number' => [
'nullable',
'string',
// Closure for inline validation
function ($attribute, $value, $fail) {
if ($value && !$this->isValidVatNumber($value)) {
$fail('The VAT number is invalid.');
}
},
],
];
}
public function messages(): array
{
return [
'email.unique' => 'This email address is already in use.',
'password.confirmed' => 'The passwords do not match.',
];
}
protected function prepareForValidation(): void
{
// Normalization before validation
$this->merge([
'email' => strtolower(trim($this->email)),
]);
}
}I Form Request centralizzano validazione, autorizzazione e messaggi di errore, alleggerendo i controller.
Pronto a superare i tuoi colloqui su Laravel?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Testing
Domanda 16: Strutturare i test in Laravel
Laravel fornisce PHPUnit con helper dedicati per testare i diversi livelli dell'applicazione.
namespace Tests\Feature;
use App\Models\Article;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ArticleControllerTest extends TestCase
{
use RefreshDatabase; // Resets DB between each test
public function test_guest_can_view_published_articles(): void
{
$article = Article::factory()->published()->create();
$response = $this->get('/articles/' . $article->slug);
$response->assertStatus(200);
$response->assertSee($article->title);
}
public function test_authenticated_user_can_create_article(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->post('/articles', [
'title' => 'My new article',
'content' => 'Test content',
]);
$response->assertRedirect();
$this->assertDatabaseHas('articles', [
'title' => 'My new article',
'user_id' => $user->id,
]);
}
public function test_user_cannot_update_others_article(): void
{
$owner = User::factory()->create();
$other = User::factory()->create();
$article = Article::factory()->for($owner)->create();
$response = $this->actingAs($other)
->put('/articles/' . $article->id, [
'title' => 'Modified title',
]);
$response->assertStatus(403);
}
}namespace Tests\Unit\Services;
use App\Services\PaymentService;
use App\Contracts\PaymentGatewayInterface;
use App\Repositories\OrderRepository;
use Mockery;
use Tests\TestCase;
class PaymentServiceTest extends TestCase
{
public function test_process_payment_charges_correct_amount(): void
{
// Mock dependencies
$gateway = Mockery::mock(PaymentGatewayInterface::class);
$gateway->shouldReceive('charge')
->once()
->with(99.99, Mockery::any())
->andReturn((object) ['transactionId' => 'tx_123']);
$orders = Mockery::mock(OrderRepository::class);
$orders->shouldReceive('find')
->with(1)
->andReturn($this->createOrder());
$service = new PaymentService($gateway, $orders);
$result = $service->processPayment(1, 99.99);
$this->assertTrue($result);
}
}I test Feature (HTTP, integrazione) e i test Unit (classi isolate con mock) vanno separati chiaramente.
Domanda 17: Utilizzare Factories e Seeders in modo efficace
Le Factory generano dati di test realistici, i Seeder popolano il database.
namespace Database\Factories;
use App\Models\Article;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArticleFactory extends Factory
{
protected $model = Article::class;
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => fake()->sentence(6),
'slug' => fake()->unique()->slug(),
'content' => fake()->paragraphs(5, true),
'status' => 'draft',
'view_count' => fake()->numberBetween(0, 10000),
'created_at' => fake()->dateTimeBetween('-1 year'),
];
}
// States for different configurations
public function published(): static
{
return $this->state(fn(array $attr) => [
'status' => 'published',
'published_at' => fake()->dateTimeBetween('-6 months'),
]);
}
public function draft(): static
{
return $this->state(['status' => 'draft', 'published_at' => null]);
}
public function popular(): static
{
return $this->state(['view_count' => fake()->numberBetween(10000, 100000)]);
}
// Relationship configuration
public function configure(): static
{
return $this->afterCreating(function (Article $article) {
// Create tags after article creation
$article->tags()->attach(
\App\Models\Tag::factory()->count(3)->create()
);
});
}
}
// Usage in tests
$article = Article::factory()->published()->create();
$articles = Article::factory()->count(10)->for($user)->create();
$articleWithComments = Article::factory()
->has(Comment::factory()->count(5))
->create();Gli state permettono di creare varianti senza duplicare la logica della factory.
Architettura e Pattern
Domanda 18: Implementare il Repository Pattern in Laravel
Il Repository Pattern astrae l'accesso ai dati e facilita il testing permettendo il mocking delle query.
namespace App\Contracts;
use App\Models\Article;
use Illuminate\Pagination\LengthAwarePaginator;
interface ArticleRepositoryInterface
{
public function find(int $id): ?Article;
public function findBySlug(string $slug): ?Article;
public function getPublished(int $perPage = 20): LengthAwarePaginator;
public function getByAuthor(int $userId, int $perPage = 20): LengthAwarePaginator;
public function create(array $data): Article;
public function update(Article $article, array $data): Article;
public function delete(Article $article): bool;
}namespace App\Repositories;
use App\Contracts\ArticleRepositoryInterface;
use App\Models\Article;
use Illuminate\Pagination\LengthAwarePaginator;
class EloquentArticleRepository implements ArticleRepositoryInterface
{
public function __construct(
private Article $model
) {}
public function find(int $id): ?Article
{
return $this->model->with('author')->find($id);
}
public function findBySlug(string $slug): ?Article
{
return $this->model
->where('slug', $slug)
->with(['author', 'tags'])
->firstOrFail();
}
public function getPublished(int $perPage = 20): LengthAwarePaginator
{
return $this->model
->published()
->with('author')
->orderByDesc('published_at')
->paginate($perPage);
}
public function create(array $data): Article
{
return $this->model->create($data);
}
public function update(Article $article, array $data): Article
{
$article->update($data);
return $article->fresh();
}
public function delete(Article $article): bool
{
return $article->delete();
}
}
// Binding in the ServiceProvider
$this->app->bind(
ArticleRepositoryInterface::class,
EloquentArticleRepository::class
);Il Repository Pattern e utile per applicazioni complesse, ma puo risultare eccessivo per progetti semplici. Il rapporto costi/benefici va valutato caso per caso.
Domanda 19: Transazioni e concorrenza in Laravel
Le transazioni garantiscono l'integrita dei dati durante operazioni multiple. Laravel ne semplifica la gestione.
use Illuminate\Support\Facades\DB;
class OrderService
{
public function processOrder(Cart $cart, User $user): Order
{
// Transaction with closure: automatic rollback on exception
return DB::transaction(function () use ($cart, $user) {
// Create the order
$order = Order::create([
'user_id' => $user->id,
'total' => $cart->total(),
'status' => 'pending',
]);
// Create order items
foreach ($cart->items as $item) {
$order->items()->create([
'product_id' => $item->product_id,
'quantity' => $item->quantity,
'price' => $item->product->price,
]);
// Decrement stock with pessimistic locking
$product = Product::lockForUpdate()->find($item->product_id);
if ($product->stock < $item->quantity) {
throw new InsufficientStockException($product);
}
$product->decrement('stock', $item->quantity);
}
// Clear the cart
$cart->clear();
return $order;
}, attempts: 3); // 3 attempts in case of deadlock
}
public function updateOrderStatus(Order $order, string $status): void
{
// Optimistic locking with version/timestamp
$updated = DB::table('orders')
->where('id', $order->id)
->where('updated_at', $order->updated_at) // Version check
->update([
'status' => $status,
'updated_at' => now(),
]);
if ($updated === 0) {
throw new ConcurrencyException('The order was modified in the meantime');
}
}
}lockForUpdate() impedisce le letture concorrenti durante la transazione. Va usato con parsimonia per evitare deadlock.
Domanda 20: Implementare il caching in modo efficace in Laravel
Il caching migliora drasticamente le prestazioni evitando query ripetitive.
// Caching strategies
use Illuminate\Support\Facades\Cache;
class ArticleService
{
public function getPopularArticles(): Collection
{
// Cache-Aside: check cache, otherwise load and store
return Cache::remember('articles:popular', 3600, function () {
return Article::published()
->popular()
->with('author')
->limit(10)
->get();
});
}
public function getArticle(string $slug): Article
{
// Cache by dynamic key
return Cache::remember("article:{$slug}", 1800, function () use ($slug) {
return Article::where('slug', $slug)
->with(['author', 'comments.user'])
->firstOrFail();
});
}
public function updateArticle(Article $article, array $data): Article
{
$article->update($data);
// Cache invalidation after modification
Cache::forget("article:{$article->slug}");
Cache::forget('articles:popular');
// Tags for grouped invalidation (Redis only)
Cache::tags(['articles', "user:{$article->user_id}"])->flush();
return $article;
}
public function getArticleWithLock(int $id): Article
{
// Atomic lock to avoid cache stampede
return Cache::lock("article-lock:{$id}", 10)->block(5, function () use ($id) {
return Cache::remember("article:{$id}", 3600, fn() => Article::findOrFail($id));
});
}
}'stores' => [
'redis' => [
'driver' => 'redis',
'connection' => 'cache',
'lock_connection' => 'default',
],
],I tag della cache consentono un'invalidazione raggruppata efficiente. In caso di scadenza simultanea di molte chiavi, si rischia un cache stampede.
Prestazioni e Ottimizzazione
Domanda 21: Ottimizzare le prestazioni di un'applicazione Laravel
L'ottimizzazione copre diversi livelli: query, cache, configurazione e infrastruttura.
$articles = Article::query()
->select(['id', 'title', 'slug', 'published_at', 'user_id']) // Specific columns
->with(['author:id,name,avatar']) // Selective eager loading
->withCount('comments') // Count in one query
->published()
->latest('published_at')
->cursorPaginate(20); // Cursor pagination (more performant)
// 2. Chunking for mass operations
Article::query()
->where('status', 'published')
->chunkById(1000, function ($articles) {
foreach ($articles as $article) {
// Processing in batches of 1000
ProcessArticle::dispatch($article);
}
});
// 3. Mass update without models
Article::where('published_at', '<', now()->subYear())
->update(['status' => 'archived']); // Single SQL query# Optimization commands for production
php artisan config:cache # Cache configuration
php artisan route:cache # Cache routes
php artisan view:cache # Compile Blade views
php artisan event:cache # Cache event mappings
php artisan optimize # Run all optimizations
# Optimized autoloader
composer install --optimize-autoloader --no-devQueste ottimizzazioni possono ridurre il tempo di avvio del 50% o piu in produzione.
Domanda 22: Debug e profiling di un'applicazione Laravel
Laravel offre diversi strumenti per identificare problemi di prestazioni e bug.
// Laravel Telescope for development debugging
// Captures requests, jobs, exceptions, etc.
// Query debugging
DB::enableQueryLog();
$articles = Article::with('author')->get();
$queries = DB::getQueryLog();
dump($queries); // Shows all SQL queries
// Debug bar integrated with Blade
@dump($variable) // Display and continue
@dd($variable) // Dump and die
// Structured logging
use Illuminate\Support\Facades\Log;
Log::channel('slack')->critical('Payment failed', [
'user_id' => $user->id,
'amount' => $amount,
'error' => $exception->getMessage(),
'trace' => $exception->getTraceAsString(),
]);
// Context logging
Log::withContext(['request_id' => request()->id()]);
Log::info('Processing order', ['order_id' => $order->id]);'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['daily', 'slack'],
'ignore_exceptions' => false,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
'days' => 14,
],
],Telescope e adatto allo sviluppo, uno strumento APM (New Relic, Datadog) al monitoraggio continuo in produzione.
Deploy e Produzione
Domanda 23: Gestire le migrazioni in produzione senza downtime
Le migrazioni in produzione richiedono particolare attenzione per evitare interruzioni del servizio.
// Safe migration: add a nullable column first
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
// Step 1: Add nullable column
$table->string('role')->nullable()->after('email');
});
}
// Step 2: Data migration (separate job)
// php artisan tinker
// User::whereNull('role')->update(['role' => 'user']);
// Step 3: Second migration for constraint
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('role')->nullable(false)->default('user')->change();
});
}// For column deletions (3 deployments)
// Deployment 1: Stop using the column in code
// Deployment 2: Delete the column
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('deprecated_field');
});
// Migration with timeout for large tables
public function up(): void
{
DB::statement('SET lock_timeout TO \'5s\'');
Schema::table('large_table', function (Blueprint $table) {
$table->index('status'); // Concurrent index if PostgreSQL
});
}La strategia expand-contract consente di aggiungere colonne senza downtime: aggiungere nullable → migrare i dati → rendere non-nullable.
Domanda 24: Configurare Laravel per l'alta disponibilita
Un'architettura ad alta disponibilita richiede la separazione dei componenti stateless e la gestione dello stato condiviso.
'driver' => env('SESSION_DRIVER', 'redis'),
'connection' => 'session',
// config/cache.php - Shared cache
'default' => env('CACHE_DRIVER', 'redis'),
// config/queue.php - Redis queues for distribution
'default' => env('QUEUE_CONNECTION', 'redis'),
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'retry_after' => 90,
'block_for' => null,
],
],
// config/filesystems.php - S3 storage for files
'disks' => [
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
],
],// Health check endpoint for load balancer
Route::get('/health', function () {
try {
DB::connection()->getPdo();
Cache::store('redis')->ping();
return response()->json(['status' => 'healthy']);
} catch (\Exception $e) {
return response()->json(['status' => 'unhealthy'], 503);
}
});Ogni istanza deve essere stateless. Sessioni, cache e code devono utilizzare Redis o uno store condiviso.
Domanda 25: Best practice per il deploy di Laravel
Un deploy robusto combina automazione, controlli e rollback agevole.
# deploy.sh - Typical deployment script
#!/bin/bash
set -e
echo "Pulling latest code..."
git pull origin main
echo "Installing dependencies..."
composer install --no-dev --optimize-autoloader
echo "Running migrations..."
php artisan migrate --force
echo "Caching configuration..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
echo "Restarting queue workers..."
php artisan queue:restart
echo "Clearing old cache..."
php artisan cache:clear
echo "Deployment complete!"APP_ENV=production
APP_DEBUG=false
APP_KEY=base64:... # Generated with php artisan key:generate
LOG_CHANNEL=stack
LOG_LEVEL=warning
# Never expose credentials in plain text
# Use secret managers (Vault, AWS Secrets Manager)Checklist per il deploy:
php artisan config:cache- Cache della configurazionephp artisan route:cache- Cache delle rottephp artisan view:cache- Compilazione delle vistecomposer install --no-dev- Dipendenze di produzione- Test automatizzati prima del deploy
- Health check configurati
- Monitoraggio e alerting attivi
Conclusione
Queste 25 domande coprono gli aspetti essenziali dei colloqui su Laravel e PHP, dal Service Container ai pattern di deploy in produzione.
Checklist di preparazione:
- Service Container e dependency injection
- Eloquent ORM: relazioni, scopes, eager loading
- Middleware, routing e sicurezza
- Code, jobs ed eventi asincroni
- Testing: test Feature, test Unit, Factory
- Pattern avanzati: Repository, Transazioni, Caching
- Deploy: migrazioni, ottimizzazione, alta disponibilita
Ogni domanda merita un approfondimento con la documentazione ufficiale di Laravel. Gli intervistatori apprezzano i candidati che conoscono le sfumature del framework e sanno giustificare le proprie scelte tecniche.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Tag
Condividi
Articoli correlati

Laravel 11: Creare un'applicazione completa da zero
Guida completa a Laravel 11: installazione, modelli Eloquent, autenticazione con Breeze, controller, rotte, autorizzazione con le policy, REST API con Sanctum, test con Pest e deploy in produzione.

Domande per colloqui Django e Python: Le Top 25 nel 2026
Le 25 domande piu comuni nei colloqui su Django e Python. ORM, view, middleware, DRF, signal e ottimizzazione con risposte dettagliate ed esempi di codice.

Domande Colloquio Rust: Guida Completa 2026
Le 25 domande più comuni nei colloqui Rust. Ownership, borrowing, lifetimes, traits, async e concurrency con risposte dettagliate ed esempi di codice.