PHPFrameworks Overview (Laravel/Symfony)

Frameworks Overview (Laravel/Symfony)

Every non-trivial web application ends up needing the same set of pieces: something that decides which code runs for a given URL, something that talks to a database without hand-writing raw SQL for every query, something that renders HTML from templates instead of string-concatenating it, some mechanism for wiring dependencies together instead of constructing every object inline wherever it's needed, and defenses against a handful of well-known security mistakes like cross-site request forgery and unescaped output. A framework is, at its core, a pre-built, pre-integrated bundle of answers to exactly those recurring problems, so a project doesn't have to design and wire all of them together from scratch before it can do anything useful. This page is about what that bundle typically contains, how the two dominant full-stack PHP frameworks — Laravel and Symfony — differ in philosophy, where smaller alternatives fit, and when skipping a framework entirely is still the right call.

What a framework actually bundles
  • Routing — mapping an incoming URL and HTTP method to the code that should handle it, instead of one PHP file per URL.

  • An ORM or database layer — representing rows as objects with methods, instead of hand-written SQL scattered through the codebase.

  • Templating — separating HTML structure from PHP logic, with automatic escaping to avoid accidentally outputting unsafe data.

  • A dependency injection container — building objects and their dependencies centrally, so application code asks for what it needs instead of constructing it inline.

  • Security defaults — CSRF tokens on forms, automatic output escaping, password hashing helpers — enabled out of the box rather than left for every project to remember.

None of these are individually hard to build in isolation — a router is a handful of pattern-matching rules, a template engine is a loop that fills placeholders. What a framework provides is all of them already built, already tested against real-world edge cases, and already wired to work together, which is a meaningfully different proposition than assembling five separate libraries and gluing them together correctly on a deadline.

Laravel: convention over configuration

Laravel's guiding philosophy is that a developer shouldn't have to make a decision, or write configuration, for something that already has an obviously sensible default. A new Laravel project already knows where controllers live, how routes are typically organized, what a database migration file looks like, and how a model relates to its database table, all without a line of setup — the defaults are simply followed unless a project deliberately opts out of them. This shows up concretely in artisan, Laravel's command-line tool, which can generate a controller, a model, a migration, or a test file with one command, each pre-filled with the conventional structure Laravel expects.

Illustrative artisan usage — generating scaffolding

Bash
php artisan make:model Order -m
php artisan make:controller OrderController
php artisan route:list

Laravel's ORM, Eloquent, follows the ActiveRecord pattern: a model class corresponds to a database table, and an instance of that class corresponds to a row, with the querying, saving, and relationship logic built into the model itself rather than living in a separate query-builder object a developer has to pass around.

Illustrative Eloquent-style query — not real Laravel source

PHP
<?php

$order = Order::where('status', 'pending')
    ->where('customer_id', $customerId)
    ->first();

if ($order) {
    $order->status = 'shipped';
    $order->save();
}

The appeal is that a developer familiar with Laravel's conventions can be productive in an unfamiliar Laravel codebase almost immediately, because so much of the structure is predictable rather than project-specific.

Symfony: explicit, component-based, enterprise-oriented

Symfony takes a more deliberately explicit approach — configuration tends to be spelled out rather than inferred from convention, and the framework is built as a collection of individually usable components rather than one monolithic package. That granularity is Symfony's most distinctive trait: components like Symfony Console (for building command-line tools) or Symfony HttpFoundation (for representing HTTP requests and responses as objects) can be installed and used entirely on their own, inside a project that isn't running the Symfony framework at all. This isn't a hypothetical — plenty of PHP tooling that has nothing to do with "Symfony the framework" still depends on individual Symfony components, precisely because they're usable standalone rather than bundled inseparably into a full framework.

Illustrative shape of a Symfony route definition — not real Symfony source

PHP
<?php

#[Route('/orders/{id}', methods: ['GET'])]
public function show(int $id): Response
{
    $order = $this->orderRepository->find($id);

    return $this->render('orders/show.html.twig', [
        'order' => $order,
    ]);
}

This more explicit, modular style tends to suit larger, longer-lived applications with teams that value being able to see exactly what's configured where, and it's part of why Symfony has a strong reputation in enterprise contexts where predictability and long-term maintainability outweigh the convenience of Laravel-style implicit defaults.

Smaller options: Slim and lightweight frameworks

Not every project needs an ORM, a templating engine, and a full dependency injection container — a small JSON REST API might need nothing more than routing and a way to return a response. Micro-frameworks like Slim exist for exactly that gap: they provide routing and basic request/response handling without the rest of a full framework's machinery, which keeps the application lighter and avoids paying for features that would otherwise sit unused.

Illustrative shape of a Slim-style route — not real Slim source

PHP
<?php

$app->get('/status', function ($request, $response) {
    $response->getBody()->write(json_encode(['status' => 'ok']));
    return $response->withHeader('Content-Type', 'application/json');
});

Choosing a micro-framework over a full one is a real trade-off, not just a smaller version of the same thing — a project that starts on Slim and later grows into needing a full ORM, templating, and authentication system will likely end up assembling most of what a full framework already bundled, just piece by piece and later than if it had started with one.

When plain PHP is still the right call

None of this means a framework is always the correct choice. A small internal script that runs once a day and touches one table doesn't need routing, an ORM, or a DI container — plain PHP with a couple of Composer packages for the specific things it actually needs is faster to write and easier to reason about than stripping down a framework to fit. The same is true of small internal tools with a handful of users, where the operational overhead of a framework's conventions outweighs any benefit it would provide.

There's a second, more important reason to write plain PHP deliberately: while learning. A framework's entire value proposition is hiding mechanics that are worth understanding directly first — routing, autoloading, and how a request actually turns into a response are exactly the things a framework does automatically and invisibly. Learning those mechanics by building them by hand, even crudely, first makes it far easier to understand what a framework is actually doing under its conventions later, rather than treating the framework's behavior as an opaque black box to be memorized.

Frameworks don't replace understanding fundamentals
A developer who only ever writes Eloquent queries, having never written a raw SQL query or thought about what an N+1 query problem is, will eventually hit a case where the ORM's abstraction leaks — a slow endpoint, an unexpected extra query, or an edge case the ORM doesn't model cleanly. The fundamentals a framework abstracts away don't stop mattering just because they're hidden most of the time.
  • Frameworks bundle routing, an ORM/database layer, templating, dependency injection, and security defaults so they don't need assembling from scratch per project.

  • Laravel favors convention over configuration, with artisan scaffolding and the Eloquent ORM's ActiveRecord-style API.

  • Symfony favors explicit configuration and component-based design — many of its components, like Console or HttpFoundation, are usable entirely standalone.

  • Micro-frameworks like Slim provide routing and request/response handling for small APIs without a full framework's extra machinery.

  • Plain PHP is still the right call for small scripts, internal tools, and — deliberately — while learning fundamentals a framework would otherwise hide.

Tip
Before reaching for a full framework on a new project, write at least one small application in plain PHP with Composer for dependencies — enough to hand-route a couple of URLs and query a database directly. It makes a framework's conventions read as "a well-organized version of things I've already done by hand" rather than as unexplained magic to trust blindly.