Jump to Category
| ⚙️ Laravel Core & Internals | Eloquent ORM & Database |
| Queues, Caching & Performance | ️ Architecture & Design Patterns |
| APIs & Security | Testing & Ecosystem |
| Advanced PHP Concepts |
Laravel Core & Internals
1. Explain the Laravel service container and the difference between binding and resolving.
The **Service Container** (or IoC container) is a powerful tool for managing class dependencies and performing dependency injection. It’s essentially a registry of class bindings.
- Binding is the act of registering a class or interface with the container, teaching it *how* to create an object. This can be a simple binding, a singleton, or binding an interface to a concrete implementation.
- Resolving is the act of retrieving an instance from the container. The container automatically injects any required dependencies for the class it’s creating.
This decoupling is fundamental to Laravel’s architecture and makes applications flexible and testable.
Read the official documentation on the Service Container.2. What are Service Providers and what is their purpose?
Service Providers are the central place of all Laravel application bootstrapping. Their primary purpose is to register things with the service container. They contain two methods:
- `register()`: Used only to bind things into the container. You should never attempt to resolve any services within this method.
- `boot()`: This method is called after all other service providers have been registered. It allows you to access any service from the container and perform bootstrapping tasks like registering event listeners, publishing configuration, or defining routes.
3. Explain the difference between Facades and helper functions in Laravel.
Both provide a convenient way to access Laravel’s services.
- Facades provide a “static” interface to services available in the service container. Under the hood, they are not truly static but use the container to resolve an object instance. They offer a terse syntax but can be less explicit about where a dependency comes from.
- Helper Functions (e.g., `cache()`, `view()`, `app()`) are global functions that provide easy access to common framework features. They often call the same underlying services as Facades.
The choice is often a matter of style, but dependency injection is generally preferred for its explicitness and testability, especially in constructors.
4. Describe the request lifecycle in a Laravel application.
- The entry point is `public/index.php`.
- The autoloader, application instance, and HTTP kernel are bootstrapped.
- The incoming HTTP request is captured as a `Request` object and sent through the HTTP kernel.
- The request passes through the global middleware stack.
- The router dispatches the request to a controller action or a closure route.
- Route-specific middleware is executed.
- The controller action executes, performs business logic, and returns a `Response` object.
- The response travels back through the middleware stack.
- The HTTP kernel sends the response back to the client.
5. What is contextual binding and when would you use it?
Contextual binding allows you to inject different implementations of an interface into different classes. For example, you might have an `Uploader` interface with two implementations: `S3Uploader` and `LocalUploader`. You can configure the service container to inject `S3Uploader` when `PhotoController` needs an `Uploader`, but inject `LocalUploader` when `AvatarController` needs one. This provides fine-grained control over dependency injection without cluttering your service providers.
Eloquent ORM & Database
6. What is the N+1 query problem and how do you solve it in Eloquent?
The N+1 problem occurs when you fetch a list of parent models (1 query) and then loop through them, lazy-loading a related model for each parent, resulting in N additional queries.
You solve this in Eloquent by **eager loading** the relationships. This loads all the necessary related models in a constant number of queries (typically just two). This is done using the `with()` or `load()` methods. For example: `User::with(‘posts’)->get();`
7. Explain polymorphic relationships in Eloquent and provide a use case.
Polymorphic relationships allow a model to belong to more than one other model on a single association. For example, a `Comment` model might belong to either a `Post` model or a `Video` model. Instead of having `post_id` and `video_id` columns, you would have two columns: `commentable_id` (the ID of the parent) and `commentable_type` (the class name of the parent, e.g., `App\Models\Post`).
This is defined using `morphTo()` on the child model and `morphMany()` or `morphOne()` on the parent models.
Read the docs on Polymorphic Relationships.8. What are global scopes and how do they differ from local scopes?
- Global Scopes allow you to add constraints to all queries for a given model automatically. For example, you could create a `SoftDeletingScope` to automatically add a `where(‘deleted_at’, null)` condition to every query. They are defined in a separate scope class and applied in the model’s `booted` method.
- Local Scopes are reusable query constraints defined on a model with a `scope` prefix (e.g., `scopePopular()`). They must be applied manually to a query, like `Post::popular()->get();`.
9. What are accessors and mutators in Eloquent?
Accessors allow you to format Eloquent attribute values when you retrieve them from a model. For example, you could create a `getFirstNameAttribute` method to automatically capitalize a user’s first name.
Mutators allow you to transform attribute values when you set them on a model. For example, a `setFirstNameAttribute` method could ensure the value is always stored in lowercase, or a `setPasswordAttribute` could automatically hash the password.
10. What is the purpose of Eloquent API Resources?
API Resources provide a transformation layer between your Eloquent models and the JSON responses returned by your API. They allow you to control exactly which attributes are exposed, format them, add metadata, and include conditional attributes or relationships. This keeps your API responses consistent and prevents accidentally leaking sensitive model data.
11. What are database transactions and how do you use them in Laravel?
A database transaction is a sequence of operations performed as a single logical unit of work. All operations must succeed for the transaction to be committed; if any fail, the entire transaction is rolled back.
In Laravel, you can use the `DB::transaction()` closure. It automatically handles committing the transaction if the closure executes successfully and rolling it back if an exception is thrown. Example: `DB::transaction(function () { … });`
Queues, Caching & Performance
12. Explain how the Laravel Queue system works.
The Laravel Queue system allows you to defer the processing of time-consuming tasks, such as sending emails or processing uploads, to a background process. This keeps your web requests fast.
The process is:
- You dispatch a “Job” object onto a queue.
- This job is serialized and stored in a queue driver (e.g., Redis, SQS, database).
- A separate queue worker process (`php artisan queue:work`) continuously polls the queue for new jobs.
- When a job is found, the worker deserializes it and executes its `handle()` method.
13. What is Laravel Octane and how does it improve performance?
Laravel Octane is a first-party package that supercharges your application’s performance by serving it using high-performance application servers like Swoole or RoadRunner. These servers work by:
- Bootstrapping the framework once and keeping it in memory.
- Handling subsequent requests through the same bootstrapped instance, avoiding the overhead of re-bootstrapping on every request.
- Managing a pool of worker processes to handle concurrent requests.
This results in a dramatic increase in requests per second compared to a traditional PHP-FPM setup.
Explore the Laravel Octane documentation.14. Describe different caching strategies you might use in a Laravel application.
- Application Cache: Using `Cache::remember()` to cache the results of expensive operations, like complex database queries or API calls.
- Query Cache: Caching the results of specific database queries. Be mindful of cache invalidation.
- Route Cache: Running `php artisan route:cache` in production to serialize the route registration process into a single file, speeding up registration.
- Config Cache: `php artisan config:cache` merges all configuration files into one cached file.
- HTTP Caching: Using middleware and headers like `ETag` and `Cache-Control` to allow clients and proxies to cache responses.
15. How would you handle a failed job in the queue?
Laravel automatically retries failed jobs up to a specified number of times (`–tries` option). If a job continues to fail, it’s moved to the `failed_jobs` database table. You can then view, retry, or delete these jobs using Artisan commands (`queue:failed`, `queue:retry`). You can also define a `failed()` method on the job class itself to perform specific cleanup actions or send notifications when a job permanently fails.
16. What is job batching?
Job batching, introduced in Laravel 8, allows you to dispatch a group of jobs that should be executed as a batch. You can then define callbacks that execute when all jobs in the batch have completed successfully (`then`), when a job fails (`catch`), or regardless of the outcome (`finally`). This is useful for processing large workloads where you need to perform an action only after the entire set of tasks is finished.
Architecture & Design Patterns
17. Explain the Repository Pattern and its benefits in a Laravel application.
The Repository Pattern is a design pattern that abstracts the data layer, creating a mediator between your domain/business logic and data mapping layers (like Eloquent). You define an interface (e.g., `UserRepositoryInterface`) with methods like `find($id)` or `all()`, and then create a concrete implementation (e.g., `EloquentUserRepository`) that uses Eloquent to fulfill the contract.
Benefits:
- Decouples your business logic from the persistence layer, making it easier to test.
- Allows you to switch out the data source (e.g., from Eloquent to an API) without changing your business logic.
- Centralizes data access logic.
18. What are Actions and when would you use them over Service classes?
Actions are small, single-purpose classes designed to handle one specific business logic task. For example, instead of a `UserService` with many methods, you might have actions like `CreateNewUser`, `UpdateUserProfile`, or `DeactivateUser`.
This approach promotes the Single Responsibility Principle, making classes smaller, more focused, and easier to test. It can be a good alternative to large, god-like Service classes when your application’s business logic is complex and can be broken down into discrete tasks.
19. How can you implement an event-driven architecture in Laravel?
Laravel has a powerful built-in event system. The flow is:
- Define an **Event** class to hold data about what happened (e.g., `OrderPlaced`).
- Define one or more **Listener** classes that will react to that event (e.g., `SendOrderConfirmationEmail`, `UpdateInventory`).
- Register the events and listeners in the `EventServiceProvider`.
- Dispatch the event from your code using the `event()` helper: `event(new OrderPlaced($order));`.
For even greater decoupling, you can make your listeners queueable (`implements ShouldQueue`) to handle them in the background.
20. What are macros and when are they useful?
Macros allow you to add custom functionality to Laravel’s internal components at runtime. Many framework classes use the `Macroable` trait (e.g., `Request`, `Response`, `Collection`). You can add a new method to a class by calling its static `macro` method, usually within a service provider’s `boot` method. This is useful for adding reusable, custom helper methods to framework classes without extending them.
21. What is the difference between a Contract and a Facade?
A **Contract** is a PHP interface that defines the core services offered by the framework (e.g., `Illuminate\Contracts\Queue\Queue`). Relying on contracts for dependency injection allows you to decouple your application from a specific implementation.
A **Facade** provides a “static” proxy to a service bound in the container. `Queue::push()` is a facade that ultimately resolves an object implementing the `Queue` contract.
In short: Contracts are the “what” (the interface), while Facades are one way of accessing the “how” (the implementation).
APIs & Security
22. Compare Laravel Sanctum and Passport. When would you use each?
- Laravel Sanctum is a lightweight authentication system designed for SPAs (Single Page Applications), mobile apps, and simple token-based APIs. It uses API tokens for stateless authentication and can also use Laravel’s existing cookie-based session authentication for SPAs on the same domain.
- Laravel Passport is a full OAuth2 server implementation. It is much more complex and should be used when you need to provide a full authorization server for third-party clients to securely access your users’ data on their behalf (e.g., “Login with MyService”).
For most first-party SPAs and mobile apps, Sanctum is the recommended and simpler choice.
Read the Sanctum documentation.23. How does Laravel’s middleware work with parameters?
You can pass additional parameters to a middleware from your route definition. These parameters are passed to the middleware’s `handle` method after the `$request` and `$next` arguments. For example, in a route you might define `middleware(‘role:admin’)`. The `handle` method would be `public function handle($request, Closure $next, $role)` where `$role` would contain the string “admin”. This is useful for creating flexible, reusable middleware.
24. How does Laravel protect against Cross-Site Scripting (XSS)?
Laravel’s Blade templating engine automatically escapes all output rendered within `{{ }}` syntax by default, converting HTML characters into their entity equivalents. This prevents user-submitted data containing malicious scripts from being executed in the browser. You must explicitly use the `{!! !!}` syntax to render unescaped data, which should be done with extreme caution and only on trusted content.
25. What is Laravel Broadcasting and how does it work?
Laravel Broadcasting allows you to publish server-side events over a WebSocket connection to your client-side application. This enables real-time features like live notifications or chat messages.
It works by dispatching an event that implements the `ShouldBroadcast` interface. Laravel then pushes this event onto a broadcast driver (like Pusher, Ably, or a self-hosted solution like Soketi). On the frontend, Laravel Echo (a JavaScript library) listens on specific channels for these events and reacts accordingly.
Learn about Laravel Broadcasting.Testing & Ecosystem
26. What is the difference between a feature test and a unit test in Laravel?
- Unit Tests (`tests/Unit`) focus on a very small, isolated part of your code, like a single method on a class. They do not boot the Laravel framework and should not interact with a database.
- Feature Tests (`tests/Feature`) test a larger portion of your application’s functionality, such as a full HTTP request cycle to a controller. They boot the entire framework, allowing you to test how various components interact.
27. How does Laravel’s `RefreshDatabase` trait work?
The `RefreshDatabase` trait ensures that each feature test runs against a clean, consistent database state. Before each test, it determines if the database has been migrated. If not, it runs all migrations. Then, it wraps the test within a database transaction. At the end of the test, this transaction is rolled back, effectively undoing any changes made during the test. This is much faster than re-running migrations for every single test.
28. How would you create a custom Artisan command?
You can create a custom command using the Artisan command `php artisan make:command MyCustomCommand`. This generates a new command class in the `app/Console/Commands` directory. In this class, you define the command’s signature (its name and arguments/options) in the `$signature` property and its description in `$description`. The main logic goes into the `handle()` method. Finally, you must register the command in the `$commands` property of `app/Console/Kernel.php`.
Advanced PHP Concepts
29. What is the JIT compiler in PHP 8 and what kind of performance improvements does it offer?
The Just-In-Time (JIT) compiler in PHP 8 can compile parts of your PHP code into native machine code at runtime. While PHP is running, the JIT can identify “hot” code paths and compile them for better performance.
For typical web request workloads, the performance improvement from the JIT is often minimal because the bottleneck is usually I/O, not CPU. However, for long-running, **CPU-intensive** tasks (like scientific computing, image processing, or machine learning), the JIT can provide significant speed boosts.
Read the PHP documentation on JIT configuration.30. What are PHP generators and how are they useful?
Generators provide a simple way to create iterators without needing to implement the `Iterator` interface. A generator function looks like a normal function, but instead of returning a value once, it can `yield` as many values as it needs to. Each time it yields, it pauses execution and returns the value. This allows you to work with very large data sets (like reading a massive log file) without loading the entire set into memory, making them extremely memory-efficient.
31. What are PHP attributes (PHP 8+)?
Attributes are a form of structured metadata that you can add to classes, methods, properties, and parameters, using the `#[AttributeName]` syntax. They are native to the language, replacing the older DocBlock annotation comments (`/** @var … */`). They can be retrieved at runtime using PHP’s Reflection API, allowing frameworks and tools to create declarative APIs for things like routing, validation, or dependency injection.
32. Explain the difference between `require`, `include`, `require_once`, and `include_once`.
- `require`: Includes and evaluates a specific file. If the file cannot be found, it produces a fatal error and stops the script.
- `include`: Also includes and evaluates a file, but if the file is not found, it only produces a warning and the script continues.
- `_once` Variants: `require_once` and `include_once` ensure that the file is included only once during a single script execution. Subsequent attempts to include it will be ignored.
33. What are `WeakMap`s and what problem do they solve?
A `WeakMap` (introduced in PHP 8) is a map that holds “weak” references to objects as keys. This means that the presence of an object as a key in a `WeakMap` does not prevent it from being garbage collected if it has no other references. This is useful for building caches of data associated with specific objects without creating memory leaks by preventing those objects from being destroyed.
34. What is the `…` spread/splat operator used for in PHP?
The `…` operator has two main uses:
- Variadic Functions (Argument Unpacking): In a function definition, it allows a function to accept a variable number of arguments, which are then available as an array inside the function. Example: `function sum(…$numbers)`.
- Argument Spreading: When calling a function, it can unpack an array or Traversable into individual arguments. Example: `sum(…[1, 2, 3])`. As of PHP 8.1, it can also be used to unpack arrays with string keys.
35. What does the `declare(strict_types=1);` directive do?
The `strict_types` directive, when enabled, enforces strict type checking for scalar type declarations (`int`, `float`, `string`, `bool`). By default, PHP uses coercive typing, where it will try to convert types to match a type hint (e.g., passing `”5″` to a function expecting an `int` will work). When `strict_types=1` is active, a `TypeError` will be thrown if the exact type does not match. This must be declared on a per-file basis at the very top of the file.


