Introduction

Symfony is a set of standalone PHP libraries plus a framework that wires them together, and you can use either half.

Syntaxcomposer require symfony/string # one component, no framework

Symfony is two things under one name. First, a set of standalone PHP libraries called components: one for HTTP messages, one for routing, one for strings, one for running console commands. Each is a Composer package. You can install one into any PHP project with no framework involved. Second, a framework: packages that assemble those components into an application, so a request arriving at your server becomes a response produced by code you wrote.

Why it is split

A monolithic framework gives you one box; you take all of it or none. Symfony's components are released as separate packages and depend on each other sparingly. That is why other projects use them without being Symfony applications. It also means two kinds of documentation exist. A component page shows you building an object by hand with new. A framework page shows the same object already configured for you. Both are correct, and they answer different questions.

What the framework adds

The framework contributes the parts that only make sense together: a single entry point for every request, configuration that changes per environment, a command line tool, and a service container — an object that builds and holds your application's objects for you. The container is Stage 2; nothing here depends on it.

Where this course goes

Stage 1 ends with a page served by a controller you wrote. Stage 7 ends with that same application containerised on Kubernetes, with migrations applied safely during a rolling deploy. The course documents Symfony 8.1 on PHP 8.5. Symfony 8.1 requires PHP 8.4 or higher.

Example

Example · php
<?php
// scripts/slugify.php
declare(strict_types=1);

// A Symfony component used on its own: no framework, no container,
// no configuration files. Installed with:
//   composer require symfony/string

use Symfony\Component\String\Slugger\AsciiSlugger;

require __DIR__ . '/../vendor/autoload.php';

$slugger = new AsciiSlugger();

echo $slugger->slug('Wôrķšƥáçè ~~sèťtïñğš~~'), "\n";
// Output: Workspace-settings

// Second argument is the separator. Third is the locale used when
// transliterating characters that have language-specific readings.
echo $slugger->slug('Wôrķšƥáçè ~~sèťtïñğš~~', '_'), "\n";
// Output: Workspace_settings

When to use it

  • Decide whether a task needs one Symfony component or a whole Symfony application.
  • Read a Symfony documentation page and tell whether it describes the component or the framework wiring.
  • Add YAML parsing or a console entry point to a legacy PHP codebase without restructuring it.

More examples

Two different composer.json files

The first project has one library and no framework. The second has symfony/framework-bundle, which is the package that turns components into an application. Reach for the first shape when you want one job done inside an existing codebase, and the second when you are building an application from scratch.

Example · json
{
    "_comment": "composer.json of a plain PHP project using one component",
    "require": {
        "php": ">=8.4",
        "symfony/string": "^8.1"
    }
}

{
    "_comment": "composer.json of a Symfony application",
    "require": {
        "php": ">=8.4",
        "symfony/console": "8.1.*",
        "symfony/dotenv": "8.1.*",
        "symfony/framework-bundle": "8.1.*",
        "symfony/runtime": "8.1.*",
        "symfony/yaml": "8.1.*"
    }
}

The same slug work inside a controller

The same component, now reached through a route. GET /slug-demo returns 200 with the body Workspace-settings. The component did not change; the framework only decided which method runs for which URL.

Example · php
<?php
// src/Controller/ArticleSlugController.php
declare(strict_types=1);

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\String\Slugger\AsciiSlugger;

class ArticleSlugController extends AbstractController
{
    #[Route('/slug-demo', name: 'app_slug_demo')]
    public function demo(): Response
    {
        // Built here with new, because the service container has not
        // been introduced yet. Stage 2 replaces this with the slugger
        // handed to the constructor instead.
        $slugger = new AsciiSlugger();

        return new Response((string) $slugger->slug('Wôrķšƥáçè ~~sèťtïñğš~~'));
    }
}

Component packages are independent of each other

Useful when you have an existing application that is not a Symfony application and you want one capability from Symfony, such as reading YAML safely or building a command line tool, without adopting a framework.

Example · bash
# Each component is its own package with its own version constraint.
# Installing one does not drag the framework in.

composer require symfony/yaml
composer require symfony/filesystem
composer require symfony/console

# The framework is one more package, which happens to depend on many
# of the components above.
composer require symfony/framework-bundle

Discussion

  • Be the first to comment on this lesson.