Skip to content

PHP Tutorial Composer

A Practical Composer Example

Lesson 256 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

Let us put the chapter together. We will build a tiny script that converts Markdown to safe HTML using an installed package, with our own class loaded by Composer.

Step 1: create the project

terminal
BASH
mkdir markdown-demo
cd markdown-demo
composer init --name="demo/markdown-demo" --no-interaction

Composer creates a composer.json that looks like this:

data.json
JSON
{
    "name": "demo/markdown-demo",
    "require": {}
}

Step 2: install a package

terminal
BASH
composer require league/commonmark

Composer downloads the package and its dependencies into vendor/, writes composer.lock and adds the package to composer.json:

data.json
JSON
{
    "name": "demo/markdown-demo",
    "require": {
        "league/commonmark": "^2.10"
    }
}

Step 3: add PSR-4 autoloading for your own code

Edit composer.json and add the autoload section:

data.json
JSON
{
    "name": "demo/markdown-demo",
    "require": {
        "league/commonmark": "^2.10"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

Run:

terminal
BASH
composer dump-autoload

Step 4: write your class

Create src/MarkdownRenderer.php:

src/MarkdownRenderer.php
PHP
<?php

declare(strict_types=1);

namespace App;

use League\CommonMark\CommonMarkConverter;

final class MarkdownRenderer
{
    private CommonMarkConverter $converter;

    public function __construct()
    {
        $this->converter = new CommonMarkConverter([
            "html_input" => "strip",          // remove raw HTML from the input
            "allow_unsafe_links" => false,    // block javascript: links
        ]);
    }

    public function render(string $markdown): string
    {
        return (string) $this->converter->convert($markdown);
    }
}

Two options matter for security. We tell the library to strip raw HTML and to block unsafe links, because Markdown that comes from users must never be able to inject a script.

Step 5: the entry script

Create index.php:

index.php
PHP
<?php

declare(strict_types=1);

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

use App\MarkdownRenderer;

$renderer = new MarkdownRenderer();

echo $renderer->render("# Hello\n\nThis is **PHP**.\n\n<script>alert(1)</script>");

Step 6: run it

terminal
BASH
php index.php
Output
OUTPUT
<h1>Hello</h1>
<p>This is <strong>PHP</strong>.</p>

The script tag in the input is gone. Package and class were found by the autoloader, and there is no require for either.

This output comes from a real run of the same code, with league/commonmark installed through Composer.

What you used

StepIdea
composer init, composer requireDependency management
composer.json autoloadPSR-4 mapping
vendor/autoload.phpOne-line autoloading
composer dump-autoloadRegenerate the autoloader
Safe options on the libraryNever trust user content

What to commit

Text
PLAIN
.gitignore:
vendor/

Commit composer.json, composer.lock, src/ and index.php. Anyone who clones the project runs composer install.

Next steps

  • Add a test with composer require --dev phpunit/phpunit.
  • Add a script: "scripts": {"serve": "php -S localhost:8000"} and run composer serve.
  • Run composer audit and composer outdated regularly.
info
Why this matters in Laravel
Every Laravel command you run (composer require laravel/sanctum, composer update) is exactly what you did here. The framework is a collection of packages plus a PSR-4 mapping for your own code.

Exercise: add another package

Add a second package to the demo: use composer require nesbot/carbon and print today’s date formatted as d F Y with Carbon::now()->format("d F Y"). What changes in composer.json? Which file records the exact version that was installed?

Show the answer

composer.json gets a new "nesbot/carbon": "^x.y" line in require, and composer.lock records the exact version and its dependencies. The new class is available at once, because Composer regenerates vendor/autoload.php: use Carbon\Carbon; and echo Carbon::now()->format("d F Y");.