Passer au contenu principal
Un package Laravel n’est pas terminé une fois publié. Pour le maintenir sur plusieurs années tout en suivant les évolutions de Laravel, de PHP et des packages tiers, il faut faire tourner en continu non seulement les tests, mais aussi l’analyse statique.
Cette page complète Développement de packages Laravel, Tester des packages Laravel avec Orchestra Testbench et Gestion de la compatibilité de versions de package. Ajouter de l’analyse statique à votre stratégie d’implémentation, de tests et de versionnage rend le package plus facile à maintenir sur le long terme.

Qu’est-ce que l’analyse statique

L’analyse statique consiste à détecter les incohérences de types et les bugs potentiels sans exécuter le code. Comme les packages Laravel utilisent beaucoup de mécanismes dynamiques (service container, façades, Eloquent), l’analyse statique attrape tôt des problèmes que les seuls tests d’exécution laissent passer. L’introduction de l’analyse statique offre en particulier les bénéfices suivants :
  • Sûreté de typage améliorée — les arguments ou valeurs de retour incorrects sont détectés avant la revue.
  • Détection précoce des bugs — les appels à des méthodes inexistantes ou les oublis de nullable sont repérés avant les tests.
  • Meilleure auto-complétion IDE — un PHPDoc soigné et l’usage des Generics améliorent la précision.
  • Stabilité de la maintenance longue durée — plus facile de repérer ce qui casse à chaque montée de Laravel ou PHP.

Installer PHPStan

Commencez par mettre en place une base d’analyse avec PHPStan seul. PHPStan 2.x est plus strict qu’auparavant sur mixed et les nullables, ce qui est aussi l’occasion de nettoyer l’API publique de votre package.
1

Ajouter PHPStan aux dépendances de dev

composer require --dev phpstan/phpstan:^2.0
2

Analyser d'abord les répertoires ciblés directement

Pour un package, on commence souvent par src et tests.
vendor/bin/phpstan analyse src tests
3

Fixer la commande dans les scripts Composer

Pour utiliser la même commande en local et en CI, définir un script dans composer.json facilite l’exploitation.
{
    "scripts": {
        "analyse": "phpstan analyse"
    }
}

Installer Larastan

Avec PHPStan seul, les spécificités Laravel (résolution via le container, façades, relations Eloquent) sont mal comprises. Utilisez donc Larastan, l’extension Laravel de PHPStan, en complément.
1

Ajouter Larastan

Le package actuel s’appelle larastan/larastan. Dans d’anciens articles, on trouve encore nunomaduro/larastan.
composer require --dev larastan/larastan:^3.0
2

Pour du développement de package, installer aussi Testbench

Larastan démarre le conteneur d’application Laravel pour résoudre les types. Pour analyser un package Laravel isolément, orchestra/testbench peut être nécessaire.
composer require --dev orchestra/testbench
3

Inclure extension.neon

Dans phpstan.neon, incluez la configuration de Larastan.
includes:
    - vendor/larastan/larastan/extension.neon

Configurer phpstan.neon

phpstan.neon centralise le niveau d’analyse, les chemins ciblés, les exclusions et les règles d’exception. Pour un package Laravel, plutôt que de viser 100 % dès le départ, il est plus réaliste de mettre en place une configuration que vous pourrez faire progresser. Voici un exemple de phpstan.neon.
includes:
    - vendor/larastan/larastan/extension.neon

parameters:
    level: 5

    paths:
        - src
        - tests

    excludePaths:
        analyse:
            - vendor
            - workbench
            - bootstrap/cache/*

    ignoreErrors:
        -
            message: '#Call to an undefined method Illuminate\\Support\\HigherOrderCollectionProxy::#'
            path: tests/Fixtures/*

Choisir un niveau entre 0 et 9

PHPStan se met en place graduellement. Commencez par le niveau que votre code base peut supporter, puis augmentez-le au fur et à mesure des corrections.
NiveauÉtape adaptée
0-3Réduire d’abord les appels de classes / fonctions / méthodes inconnues
4-6Fiabiliser les arguments, valeurs de retour et types de propriétés de l’API publique
7-9Traiter strictement nullable, union et mixed en phase de maintenance longue durée
PHPStan 2.x propose aussi le niveau 10, mais pour un package Laravel, il est réaliste de stabiliser d’abord 5-7 avant de passer à 8-9. Pour un nouveau package, démarrer directement à un niveau élevé évite de refaire le travail.

paths

paths déclare explicitement les répertoires à analyser. Pour un package, il est efficace d’inclure tests en plus de src, car les types y sont facilement bancals.

excludePaths

N’excluez que les endroits à faible valeur pour l’analyse statique : fichiers générés, caches, Workbench de vérification. Une exclusion trop large masque des erreurs que vous voudriez pourtant voir.

ignoreErrors

ignoreErrors est un dernier recours. Filtrez le message par regex et associez toujours un path pour limiter la portée. Cela facilite le retour arrière quand Laravel ou Larastan s’améliorent.

Annotations de type courantes

La précision de PHPStan et Larastan dépend beaucoup de la manière d’écrire les PHPDoc. Dans un package Laravel, il est particulièrement rentable de bien renseigner @param, @return, @var et les Generics (@template).
<?php

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;

/**
 * @template TModel of Model
 */
final class ModelRepository
{
    /**
     * @param class-string<TModel> $modelClass
     */
    public function __construct(private string $modelClass)
    {
    }

    /**
     * @return TModel|null
     */
    public function find(int $id): ?Model
    {
        return $this->modelClass::query()->find($id);
    }

    /**
     * @return Collection<int, TModel>
     */
    public function all(): Collection
    {
        /** @var Collection<int, TModel> $models */
        $models = $this->modelClass::query()->get();

        return $models;
    }
}
Dans cet exemple, on transmet à PHPStan les informations suivantes :
  • @param class-string<TModel> — indique que la chaîne n’est pas quelconque mais un nom de classe Model.
  • @return TModel|null — indique que find() retourne le type concret du modèle.
  • @var Collection<int, TModel> — précise les types de clé et de valeur de la collection.
  • @template TModel of Model — exprime un repository générique réutilisable.

Points d’attention propres à Laravel

La « magie pratique » de Laravel ne se transmet pas telle quelle à l’analyse statique. Il faut ajouter côté package des informations de type que l’outil peut comprendre.

Façades

Pour une façade personnalisée, décrire les méthodes appelées par les utilisateurs en PHPDoc profite à la fois à l’IDE et à l’analyse statique.
<?php

namespace Vendor\Package\Facades;

use Illuminate\Support\Facades\Facade;

/**
 * @method static string issueToken(int $userId)
 */
class Tokenizer extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return 'package.tokenizer';
    }
}

Méthodes magiques

Les API qui reposent sur __call() ou Macroable sont pratiques, mais fragiles pour le typage. Pour une API publique, ajouter des méthodes wrapper explicites — dont les arguments et le retour sont connus — est plus sûr.
Multiplier les ignoreErrors juste pour l’analyse statique cache la manière dont les façades ou macros peuvent réellement casser. Cherchez d’abord à résoudre le problème avec des méthodes explicites, des value objects typés ou des ajouts de PHPDoc.

Typage des modèles Eloquent

Pour les relations et propriétés dynamiques d’Eloquent, combiner @property et les Generics des relations est efficace.
<?php

namespace Vendor\Package\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

/**
 * @property-read Team $team
 */
class Member extends Model
{
    /**
     * @return BelongsTo<Team, self>
     */
    public function team(): BelongsTo
    {
        return $this->belongsTo(Team::class);
    }
}

Exécution automatique en CI

Exécutez l’analyse statique non seulement en local, mais toujours en CI. Pour un package qui prend en charge plusieurs versions de Laravel, appliquer la même approche que la matrice de tests de Gestion de la compatibilité de versions de package permet de surveiller simultanément la compatibilité et la sûreté de typage. Voici un exemple de .github/workflows/static-analysis.yml.
name: Static analysis

on:
  push:
  pull_request:

jobs:
  static-analysis:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        php: [8.2, 8.3, 8.4]
        laravel: ["^12.0", "^13.0"]
        include:
          - laravel: "^13.0"
            testbench: "^10.0"
          - laravel: "^12.0"
            testbench: "^9.0"

    name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - PHPStan

    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: dom, curl, libxml, mbstring, zip
          coverage: none

      - name: Install dependencies
        run: |
          composer require "laravel/framework:${{ matrix.laravel }}" \
                           "orchestra/testbench:${{ matrix.testbench }}" \
                           --no-interaction --no-update
          composer update --prefer-dist --no-interaction

      - name: Run static analysis
        run: vendor/bin/phpstan analyse --error-format=github
Cet exemple utilise la même table de correspondance Laravel / Testbench que la matrice de tests. Surveiller les mêmes combinaisons pour tests et analyse statique aide à éviter les situations où « ça tourne, mais les types sont cassés ».

Faux positifs fréquents et comment les traiter

Face à un avertissement de l’analyse statique, demandez-vous d’abord s’il ne manque pas d’information de type. Ce qui ressemble à un faux positif n’est souvent qu’un PHPDoc incomplet.

@phpstan-ignore-next-line

Utilisable comme contournement temporaire, mais réservez-le aux lignes dont vous pouvez expliquer la raison.
// @phpstan-ignore-next-line macro Laravel enregistrée à l'exécution
$builder->whereLike('name', $keyword);

ignoreErrors

À considérer uniquement quand la même erreur apparaît à plusieurs endroits. Limitez toujours la portée avec un path et n’utilisez pas d’expression régulière trop lâche qui étoufferait tout.
parameters:
    ignoreErrors:
        -
            message: '#Call to an undefined method Illuminate\\Database\\Eloquent\\Builder::whereLike\(\)#'
            path: tests/Fixtures/*

Ordre de priorité des corrections

  1. Ajouter des PHPDoc.
  2. Déclarer explicitement les types de retour des façades et relations.
  3. Remplacer les mixed par des types concrets.
  4. Ignorer seulement les faux positifs que vous pouvez expliquer.

Pages associées

Développement de packages Laravel

Passez en revue les fondations d’un package, service providers et ressources publiées.

Tester des packages Laravel avec Orchestra Testbench

Découvrez l’infrastructure de test à combiner avec l’analyse statique.

Gestion de la compatibilité de versions de package

Passez en revue la table de compatibilité Laravel / PHP et la stratégie de matrice GitHub Actions.
Dernière modification le 13 juillet 2026