Framework Core
A framework does not speed up development in the abstract — it takes over one concrete cycle: turning an HTTP request into an HTTP response. Between the bytes on the socket and the response you send back stands a pipeline, and it is the same pipeline in Laravel and in Symfony. The kernel builds a request object and pushes it through the middleware layers. The router picks a controller action from the verb-plus-path pair. The container reads the constructor's type hints and recursively builds both the controller and everything it needs. The action coordinates — it validates the input, asks the models for data, checks permissions — and hands the result to a template engine. Knowing a framework means being able to name what happens at each of these steps, and knowing exactly where you may hook into the pipeline.
Almost every trap in this topic grows out of treating one of those steps as magic. The container guesses nothing: it resolves a type hint by reflection, and on an interface with two implementations it fails loudly — that is correct behaviour, not a bug. Cache::get() is not a static method: behind it sit __callStatic and the container, and what you pay is that the class's real dependencies vanish from its constructor. Middleware is not a set of hooks but a pipeline of decorators in which the order of the layers carries meaning. A compiled Blade view is plain PHP with no sandbox at all, so {!! !!} around user text is a ready-made XSS. A JWT is signed but not encrypted, and there is nothing to revoke it with before it expires. And a logged-in user is not yet a user who is allowed to do anything. The layer-by-layer breakdown is below.
Topic map
- MVC on a request — how the router, the controller, the model and the view divide a single request between them, and why the controller must stay thin.
- Routing and controllers — how the verb-plus-path pair selects an action, what a resource controller generates, and why
#[Route]attributes are compiled into a route table. - The service container and autowiring — how the container builds the dependency graph by reflection, why it fails loudly on an ambiguous interface, and what a facade actually hides.
- Middleware and events — the decorator pipeline around
$next, the semantics of layer order, Symfony kernel listeners, and the price of implicit control flow. - Templating with Blade and Twig — why a compiled
Bladeview is plain PHP, how{{ }}differs from{!! !!}, and howTwigenforces escaping discipline. - Input validation — how a
FormRequestruns before the action body, why a failure throws, and how the Symfony validator differs. - API authentication — server-side state versus a self-contained
JWT, the revocation problem, and choosing betweenSanctumandPassport. - Authorization — policies and voters — how "who are you" differs from "may you do this", why
authorize()throws, and how the voting strategy decides the outcome in Symfony.
Common Mistakes and Traps
| Mistake | Consequence |
|---|---|
| Keeping business rules inside the controller action | The action grows into a god object; the logic cannot be reused and cannot be tested without HTTP |
Forgetting methods: in a #[Route] attribute | One action starts answering every verb, DELETE included |
| Expecting the container to pick one of two implementations of an interface | It never picks one silently — it throws; only an explicit binding fixes it (a Symfony alias, Laravel contextual binding) |
Resolving a service inside a provider's register() | The provider of that dependency may not have registered yet — the failure depends on load order |
Believing Cache::get() is a static method | It is __callStatic over the container; the class's real dependencies vanish from its constructor and the tests drift into static mocking |
Not calling $next($request) in a middleware | The request is silently swallowed: the pipeline is cut and the controller never runs |
| Treating middleware order as cosmetic | auth before throttle lifts the rate limit off unauthenticated password guessing |
Expecting a failed queued (ShouldQueue) listener to roll the action back | The order is already saved — only the side effect failed, and you must compensate by hand |
Rendering user-supplied HTML through {!! !!} | There is no escaping — this is a ready-made XSS |
Assuming a compiled Blade view runs in a sandbox | The template compiles to plain PHP and can call anything at all |
Reading $request->all() in the action instead of validated() | Unvalidated keys reach the domain — mass assignment and garbage in the database |
Expecting rules() to hand you an error list instead of throwing | A failure throws ValidationException (422 for an API, redirect back for a form) and the action body never runs |
Thinking a JWT payload is encrypted | It is only signed — the payload decodes with plain base64, and nothing revokes the token before exp |
| Treating a logged-in user as an allowed one — and "hiding the button" instead of checking on the server | Auth::check() in place of a policy lets a user edit someone else's objects: the request goes straight through, bypassing your UI |
Interview relevance
The framework core comes up at every level, but what is probed is not API knowledge. What is probed is whether you can walk a request through the whole pipeline out loud: who built the request object, in what order the layers ran, who selected the action and on what basis, where the controller's dependencies came from, where validation happened and where the permission check did. A candidate who says "the container reads the constructor's type hints by reflection and builds the graph recursively, and on an interface with two implementations it throws" is immediately apart from the one who answers "Laravel just injects everything itself".
Typical checks:
- The
MVCroles on a concrete request, and why business logic does not belong in the action. - What exactly selects the action — and what
Route::resource/apiResourcegenerates. - How autowiring resolves a dependency, and what happens with two implementations of an interface.
- The difference between
register()andboot()in a service provider. - What a facade is under the hood and what the honest criticism of it is.
- The mechanics of middleware —
$next, short-circuiting, the semantics of order — and how a Symfony kernel listener differs. - How
Bladediffers fromTwigin what a template is allowed to do at all. - What a
FormRequestdoes before the action body and what happens when validation fails. - Revoking access: a session versus a
JWT; whenSanctumand whenPassport. - The difference between authentication and authorization; policies versus voters and the decision strategy.
Common wrong answer: "The container finds the right implementation itself, and if there are several it takes the first one." That is usually where the conversation opens up: the container never chooses for you, it throws — and in Symfony the throw arrives at cache warm-up, that is, at deploy time rather than on live traffic. The second classic failure is "authorize() returns false, I check it in an if": it does not return false, it throws an AuthorizationException that becomes a 403, and after a denial the action body does not run at all.