Vai al contenuto principale
Un pacchetto Laravel non termina al primo rilascio. Per mantenerlo per anni tenendo il passo con gli aggiornamenti di Laravel, PHP e delle dipendenze, oltre ai test devi far girare in modo continuo anche l’analisi statica.
Questa pagina è una guida complementare a Sviluppo di pacchetti Laravel, Testare pacchetti Laravel con Orchestra Testbench e Gestire la compatibilità tra versioni dei pacchetti. Aggiungere l’analisi statica a implementazione, test e strategia di versioning rende il pacchetto più stabile a lungo termine.

Cos’è l’analisi statica

L’analisi statica rileva incongruenze di tipo e bug potenziali senza eseguire il codice. In un pacchetto Laravel — service container, facade, Eloquent — ci sono molti meccanismi dinamici: verifiche a runtime da sole rischiano di lasciare passare problemi. L’analisi statica li intercetta in anticipo. Introducendola ottieni in particolare questi vantaggi.
  • Migliore type-safety — rilevi argomenti o valori di ritorno sbagliati già prima della review
  • Bug scoperti prima — trovi chiamate a metodi inesistenti o nullable dimenticati prima dei test
  • Autocompletamento IDE migliore — sistemando PHPDoc e generics l’accuratezza dell’IDE aumenta
  • Manutenzione a lungo termine più stabile — durante gli upgrade Laravel/PHP individui prima cosa si rompe

Setup di PHPStan

Prima predisponi la base di analisi con solo PHPStan. PHPStan 2.x gestisce mixed e nullable in modo più rigido: è una buona occasione per sistemare le API pubbliche del pacchetto.
1

Aggiungere PHPStan come dipendenza di sviluppo

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

Prima analizza direttamente le directory target

Nei pacchetti spesso si parte da src e tests.
vendor/bin/phpstan analyse src tests
3

Fissarlo come script Composer

Definisci uno script in composer.json così CI e locale usano lo stesso comando.
{
    "scripts": {
        "analyse": "phpstan analyse"
    }
}

Setup di Larastan

Nei pacchetti Laravel, il solo PHPStan non capisce del tutto meccanismi Laravel-specifici come risoluzione dal container, facade e relazioni Eloquent. Perciò affianchi Larastan, l’estensione Laravel di PHPStan.
1

Aggiungere Larastan

Il nome attuale del pacchetto è larastan/larastan. Negli articoli vecchi potresti trovare nunomaduro/larastan.
composer require --dev larastan/larastan:^3.0
2

Per lo sviluppo di pacchetti installa anche Testbench

Larastan avvia il container Laravel per risolvere i tipi. Nell’analisi standalone di un pacchetto Laravel a volte serve orchestra/testbench.
composer require --dev orchestra/testbench
3

Includere extension.neon

In phpstan.neon includi la configurazione di Larastan.
includes:
    - vendor/larastan/larastan/extension.neon

Configurazione di phpstan.neon

phpstan.neon è il file centrale che raccoglie livello di analisi, path da analizzare, path da escludere e regole di eccezione. Per un pacchetto Laravel è più realistico partire da un setup che puoi far salire nel tempo, piuttosto che puntare al 100% da subito. Esempio di 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/*

Come scegliere il livello 0–9

PHPStan si introduce in modo graduale. Parti dal livello che la codebase attuale riesce a superare e alza man mano che sistemi le cose.
LivelloFase indicata
0–3Vuoi ridurre chiamate a classi, funzioni o metodi sconosciuti
4–6Vuoi sistemare argomenti, valori di ritorno e proprietà dell’API pubblica
7–9Fase di manutenzione a lungo termine: gestisci nullable, union, mixed in modo rigido
PHPStan 2.x ha anche il livello 10, ma nei pacchetti Laravel è realistico stabilizzare prima 5–7 e poi passare a 8–9. Per un pacchetto nuovo, partire già alto riduce il lavoro di ritorno.

paths

In paths indichi esplicitamente le directory da analizzare. Includere non solo src ma anche tests (dove i tipi tendono a rilassarsi) è efficace.

excludePaths

Escludi solo i luoghi in cui l’analisi statica ha poco valore: file generati, cache, Workbench di verifica. Escludere troppo nasconde gli errori che invece vorresti vedere.

ignoreErrors

ignoreErrors è l’ultima risorsa. Restringi il messaggio con una regex e limita l’impatto con path. Così quando Laravel o Larastan miglioreranno, sarà più facile ripristinare.

Annotazioni di tipo frequenti

L’accuratezza di PHPStan e Larastan cambia molto in base a come scrivi il PHPDoc. Nei pacchetti Laravel vale la pena sistemare in particolare @param, @return, @var e i 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;
    }
}
In questo esempio passi a PHPStan queste informazioni.
  • @param class-string<TModel> — indica che la stringa non è arbitraria ma il nome di una classe Model
  • @return TModel|null — comunica che find() restituisce un tipo Model concreto
  • @var Collection<int, TModel> — esplicita i tipi key/value della collection
  • @template TModel of Model — descrive un generic repository riutilizzabile

Punti specifici di Laravel

La “magic” comoda di Laravel non è visibile all’analisi statica così com’è. Devi aggiungere informazioni di tipo dal lato pacchetto per portarle nella forma che l’analizzatore comprende.

Facade

Nei facade custom, integrando i metodi richiamati dagli utenti con PHPDoc, ottieni benefici sia per IDE sia per analisi statica.
<?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';
    }
}

Magic method

Le API che si basano su __call() o su Macroable sono comode, ma è facile che il tipo salti. Se sono API pubbliche, aggiungere wrapper con argomenti e valori di ritorno chiari è più sicuro.
Continuare ad aggiungere ignoreErrors solo per far tacere l’analisi statica finisce per nascondere i veri modi in cui facade e macro si rompono. Prima prova con metodi espliciti, value object tipizzati e PHPDoc.

Tipizzazione dei modelli Eloquent

Per relazioni e proprietà dinamiche di Eloquent, la combinazione di @property e generics sulle relation è 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);
    }
}

Esecuzione automatica in CI

Esegui l’analisi statica anche in CI, non solo in locale. In particolare, se il pacchetto supporta più versioni di Laravel, usare la stessa logica della test matrix di Gestire la compatibilità tra versioni dei pacchetti permette di controllare in parallelo compatibilità e type-safety. Esempio di .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
In questo esempio uso la stessa tabella Laravel/Testbench della test matrix. Controllando la stessa combinazione sia con test sia con analisi statica, riduci il rischio di uno stato “gira ma i tipi sono rotti”.

Falsi positivi frequenti e come gestirli

Davanti a un warning di analisi statica chiediti prima “manca qualche informazione di tipo?”. Spesso un falso positivo è in realtà un PHPDoc mancante.

@phpstan-ignore-next-line

Utile come workaround temporaneo, ma limitalo alle righe di cui puoi spiegare tu stesso il motivo.
// @phpstan-ignore-next-line la macro di Laravel viene registrata a runtime
$builder->whereLike('name', $keyword);

ignoreErrors

Da considerare solo quando lo stesso errore appare in più punti. Restringi sempre il path e non usare regex generici che nascondono tutto.
parameters:
    ignoreErrors:
        -
            message: '#Call to an undefined method Illuminate\\Database\\Eloquent\\Builder::whereLike\(\)#'
            path: tests/Fixtures/*

Ordine di priorità

  1. Aggiungi PHPDoc
  2. Esplicita i tipi di ritorno di facade e relation
  3. Sostituisci mixed con tipi concreti
  4. Ignora solo i falsi positivi che sai spiegare

Pagine correlate

Sviluppo di pacchetti Laravel

Rivedi le basi di implementazione di un pacchetto, service provider e risorse pubblicate incluse.

Testare pacchetti Laravel con Orchestra Testbench

Rivedi la struttura di test per pacchetti da combinare con l’analisi statica.

Gestire la compatibilità tra versioni dei pacchetti

Rivedi la tabella di compatibilità Laravel/PHP e la strategia matrix di GitHub Actions.
Ultima modifica il 13 luglio 2026