Pierry Lim

Créer et publier un package PHP avec Composer et Packagist

·Mis à jour le 19 août 2026·12 min de lecture
Développement web
PHP
Outils

Guide complet pour créer et publier un package PHP avec Composer : composer.json, autoload PSR-4, tests, soumission à Packagist et gestion des versions par tags Git.

Terminal affichant la publication d'un package PHP sur Packagist via Composer

Sommaire

Composer et Packagist, deux outils complémentaires

Composer est le gestionnaire de dépendances standard de PHP ; Packagist est le registry central où vivent les packages. L’équivalent exact du couple npm / npmjs.com pour l’écosystème PHP.

  • Composer (l’outil, installé sur votre machine) gère les dépendances d’un projet : installation, autoload, résolution de versions ;
  • Packagist (le site, packagist.org) référence les packages et leurs versions à partir de vos dépôts Git.

Là où npm publie une archive directement (npm publish), Composer fonctionne différemment : vous poussez un tag Git, Packagist l’indexe, et composer require installe depuis ce tag. Il n’y a pas de « publish » au sens npm — la publication est déclenchée par vos tags. Une fois le mécanisme compris, le cycle est même plus simple.

Comme côté JavaScript, l’intérêt reste le même : réutiliser votre code partout sans copier-coller, le versionner proprement, contribuer à l’écosystème et bâtir une preuve de compétence — un atout quand on entreprend, comme le détaille notre guide pour devenir freelance.

Préparer son environnement

  1. PHP 8.3+ et Composer 2 installés :
php -v          # PHP 8.4.x en 2026
composer -V     # Composer 2.x
  1. Un compte Packagist — créez-le sur packagist.org ou connectez-vous avec GitHub.

  2. Un dépôt Git public (GitHub, GitLab…) : c’est la source de vérité du package.

Créer le package

La structure

La structure standard d’une librairie PHP moderne :

mon-package/
├── src/
│   └── Slugify.php
├── tests/
│   └── SlugifyTest.php
├── .gitignore
├── LICENSE
├── README.md
└── composer.json

Initialiser

mkdir mon-package && cd mon-package
git init
composer init

composer init est interactif : nom du package (vendor/name), description, licence, dépendances. Il génère un composer.json propre. Vous pouvez aussi écrire le fichier à la main — nous y revoyons juste après.

Écrire le code

PHP moderne : classes autoloadées en PSR-4, typage strict, final par défaut.

<?php

declare(strict_types=1);

namespace Pixrr\Slugify;

final class Slugify
{
    private const TRIM_CHARS = " \t\n\r\0\x0B-";

    public function slugify(string $text): string
    {
        // Translittération des accents (é -> e)
        $transliterated = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $text);

        // Minuscules, suppression des caractères non alphanumériques
        $lowered = mb_strtolower($transliterated);
        $cleaned = preg_replace('~[^a-z0-9]+~', '-', $lowered) ?? '';

        return trim($cleaned, self::TRIM_CHARS);
    }
}

Les tests

PHPUnit reste le standard. Installez-le en dépendance de développement :

composer require --dev phpunit/phpunit ^12
<?php

declare(strict_types=1);

namespace Pixrr\Tests\Slugify;

use Pixrr\Slugify\Slugify;
use PHPUnit\Framework\TestCase;

final class SlugifyTest extends TestCase
{
    public function testSlugifiesAccents(): void
    {
        self::assertSame('ecrivain-francais', (new Slugify())->slugify('Écrivain Français !'));
    }
}
composer test
# ou : ./vendor/bin/phpunit

Vérifier l’autoload

composer dump-autoload
composer validate

composer validate doit passer avant toute publication — c’est lui qui détecte un composer.json invalide.

Le fichier composer.json

Le fichier complet pour notre exemple :

{
    "name": "pixrr/slugify",
    "description": "Transforme un texte en slug URL-friendly",
    "type": "library",
    "license": "MIT",
    "keywords": ["slug", "slugify", "url"],
    "authors": [
        {
            "name": "Pierry Lim",
            "homepage": "https://pixrr.fr"
        }
    ],
    "require": {
        "php": ">=8.3",
        "ext-iconv": "*",
        "ext-mbstring": "*"
    },
    "require-dev": {
        "phpunit/phpunit": "^12"
    },
    "autoload": {
        "psr-4": {
            "Pixrr\\Slugify\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Pixrr\\Tests\\Slugify\\": "tests/"
        }
    },
    "scripts": {
        "test": "phpunit --fail-on-warning"
    }
}

Points d’attention :

  • name : au format vendor/name. Le vendor est votre nom d’organisation sur Packagist. Sans org, utilisez votre pseudo GitHub.
  • require.php : la version PHP minimale. 8.3 est un bon compromis en 2026 — PHP 8.4 est la version courante, mais 8.3 couvre la majorité des hébergements (notez que PHPUnit 13 exige 8.4).
  • ext-* : déclarez les extensions PHP requises (iconv, mbstring…) — Composer vérifie leur présence à l’installation chez vos utilisateurs. ext-json est natif depuis PHP 8, inutile de le déclarer.
  • autoload PSR-4 : le namespace mappe le dossier src/. C’est la convention moderne, oubliez classmap pour du code neuf.
  • scripts : raccourcis locaux (composer test). Pas publiés, mais améliorent la DX du repo.

Publier sur Packagist

1. Pousser sur GitHub

git add .
git commit -m "feat: initial release"
git remote add origin git@github.com:votre-compte/mon-package.git
git push -u origin main

2. Soumettre le package

Sur Packagist, cliquez sur Submit et collez l’URL de votre dépôt : https://github.com/votre-compte/mon-package. Packagist lit votre composer.json, vérifie le nom vendor/name et crée la page du package sur https://packagist.org/packages/pixrr/slugify.

3. Activer l’auto-update GitHub webhook

Par défaut, la page Packagist doit être rafraîchie manuellement. Configurez le GitHub webhook (Service Hook → Packagist) : à chaque push, Packagist re-indexe automatiquement. Sur la page du package, un badge indique si l’auto-update est actif — activez-le dès la soumission, c’est gratuit et indispensable dès que vous publiez régulièrement.

⚠️ Le premier tag compte : tant qu’il n’y a pas de tag Git, le package apparaît sur Packagist mais n’est pas installable (composer require échoue avec « no stable version »). C’est la différence majeure avec npm : la publication d’une version = un tag.

4. Publier une première version

git tag 1.0.0
git push origin 1.0.0

Quelques secondes plus tard, la version 1.0.0 est installable :

composer require pixrr/slugify

Gérer les versions avec les tags Git

Packagist reprend le versioning sémantique (MAJOR.MINOR.PATCH) via vos tags :

  • 1.0.1 : correction de bug ;
  • 1.1.0 : fonctionnalité rétrocompatible ;
  • 2.0.0 : breaking change.

La contrainte par défaut de composer require est ^1.0 : accepte toutes les 1.x, bloque la 2.0. Vos utilisateurs contrôlent finement les montées de version via le fichier composer.lock.

git tag 1.1.0 && git push origin 1.1.0
# Packagist indexe la nouvelle version en quelques secondes

Pré-release ? Utilisez 1.2.0-beta1 ou v1.2.0-BETA1 : ces versions ne s’installent pas par défaut et n’apparaissent qu’en composer require pixrr/slugify:1.2.0-beta1 explicite. Pour un dev-main, voyez la FAQ.

Bonnes pratiques

  • composer validate en CI : le moindre composer.json invalide bloque l’installation chez vos utilisateurs. Un job GitHub Actions qui valide, teste et lance Psalm ou PHPStan à chaque push évite les mauvaises surprises.
  • Taggez depuis un état vert : ne poussez un tag que si la CI est verte sur le commit. Un tag sur du code cassé se voit immédiatement chez vos utilisateurs.
  • README et LICENSE obligatoires : comme sur npm, le README est la vitrine sur Packagist ; sans licence (MIT de préférence), personne n’a le droit d’utiliser le code.
  • Déclarez les extensions (ext-iconv, ext-mbstring…) : les oublier provoque des erreurs runtime chez les utilisateurs dont l’hébergement ne les fournit pas.
  • Marquez la stabilité : restez en 1.0.0 tant que l’API bouge ; pré-release (beta, RC) pour les breaking changes à venir.
  • Pas de vendor/ versionné : ne versionnez jamais vendor/ (.gitignore). Packagist n’archive que ce qui est dans le dépôt Git ; vendor/ est reconstruit chez chaque utilisateur.
  • Symfony/Drupal bundles : si vous visez un écosystème précis, suivez leurs conventions (recipe Symfony, module Drupal) — un plugin Symfony se publie comme un package Composer normal puis s’active via flex.

FAQ

Combien coûte Packagist ?

Rien. Packagist est gratuit et open source, pour la publication comme le téléchargement. Il existe un packagist.com payant pour les packages privés (dashboard, permissions) — l’équivalent exact des plans npm payants.

Puis-je publier sans Git/GitHub ?

Packagist indexe n’importe quel dépôt Git (GitLab, Bitbucket, VPS perso…), tant qu’il est accessible publiquement et contient un composer.json valide à la racine. Mais l’auto-update webhook est le plus simple sur GitHub ; ailleurs, un appel API ou le bouton « Update » manuel font l’affaire.

Comment marche dev-main ?

Chaque branche du dépôt crée une version dev-<branche> installable via composer require pixrr/slugify:dev-main. Utile pour tester un fix avant release — le lock l’épinglera avec un hash de commit.

Mon package doit-il être sur GitHub pour être installé ?

Non — il doit être sur Packagist pour composer require pixrr/slugify (registry central). Mais vous pouvez aussi déclarer n’importe quel dépôt Git directement dans votre composer.json via la clé repositories (utile pour du privé, ou un fork temporaire).

Quelle est la différence avec npm publish ?

npm publish envoie une archive au registry. Composer/Packagist n’envoie rien : vous taggez Git, Packagist indexe le tag. Avantage : impossible de publier un fichier non versionné ; inconvénient : la distribution d’un build généré (JS compilé) nécessite le plugin asset-packagist ou un mirror npm.

Conclusion

Publier en PHP, c’est trois étapes : un composer.json valide avec autoload PSR-4, un dépôt Git public, une soumission Packagist avec webhook — puis chaque tag Git devient une version installable. Les mêmes exigences de rigueur que npm s’appliquent : sémantique de version, README, licence, CI qui valide avant de tagger.

Pour prolonger : notre guide npm pour publier un package JavaScript couvre l’équivalent côté Node.js, et écrire des tests unitaires efficacement approfondit la couche tests de votre package. Dernier point si vous monétisez vos packages : la facturation électronique obligatoire en 2026 s’applique aussi aux éditeurs PHP.


Article rédigé par Pierry Lim, développeur full-stack freelance spécialisé Symfony et React.

Travaillons ensemble

Vous cherchez un développeur freelance pour créer un site web ou une application sur mesure ? Contactez-moi pour discuter de votre projet et obtenir un devis personnalisé.