PHP e PSR: usare il type hinting e i tipi di ritorno per scrivere codice più affidabile

by theArchitect
SHARE
PHP e PSR: usare il type hinting e i tipi di ritorno per scrivere codice più affidabile
© Guida-HTML5.it

Introduzione

Quando si parla di PHP, PSR e coding standard, spesso si pensa subito a formattazione, namespace o autoloading. In realtà, uno degli aspetti più utili e pratici per scrivere codice professionale è l’uso coerente di type hinting e tipi di ritorno secondo le buone pratiche promosse dall’ecosistema PHP moderno.

Questo tema non riguarda solo la leggibilità: un codice tipizzato è più facile da mantenere, più semplice da testare e molto meno soggetto a errori nascosti. In un progetto reale, dichiarare in modo esplicito i tipi di parametri e il tipo restituito di una funzione o di un metodo aiuta il team a capire immediatamente cosa aspettarsi da quel pezzo di codice.

In questo tutorial vedremo un esempio concreto: un piccolo servizio PHP che gestisce la registrazione di un utente. L’obiettivo è mostrare come progettare classi pulite, con metodi tipizzati, valori di ritorno chiari e un uso corretto delle eccezioni e degli oggetti di dominio.

Codice completo

<?php

declare(strict_types=1);

namespace AppService;

use AppExceptionInvalidEmailException;
use AppExceptionInvalidPasswordException;
use AppModelUser;

final class UserRegistrationService
{
    public function register(string $name, string $email, string $password): User
    {
        $this->assertNameIsValid($name);
        $this->assertEmailIsValid($email);
        $this->assertPasswordIsValid($password);

        return new User(
            $name,
            $email,
            password_hash($password, PASSWORD_DEFAULT)
        );
    }

    private function assertNameIsValid(string $name): void
    {
        if (trim($name) === ´´) {
            throw new InvalidArgumentException(´Il nome non può essere vuoto.´);
        }
    }

    private function assertEmailIsValid(string $email): void
    {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidEmailException(´L’email inserita non è valida.´);
        }
    }

    private function assertPasswordIsValid(string $password): void
    {
        if (strlen($password) < 8) {
            throw new InvalidPasswordException(´La password deve contenere almeno 8 caratteri.´);
        }
    }
}
<?php

declare(strict_types=1);

namespace AppModel;

final class User
{
    public function __construct(
        private string $name,
        private string $email,
        private string $passwordHash
    ) {
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getEmail(): string
    {
        return $this->email;
    }

    public function getPasswordHash(): string
    {
        return $this->passwordHash;
    }
}
<?php

declare(strict_types=1);

namespace AppException;

final class InvalidEmailException extends RuntimeException
{
}
<?php

declare(strict_types=1);

namespace AppException;

final class InvalidPasswordException extends RuntimeException
{
}
<?php

declare(strict_types=1);

use AppServiceUserRegistrationService;

require_once __DIR__ . ´/vendor/autoload.php´;

$service = new UserRegistrationService();

try {
    $user = $service->register(
        ´Mario Rossi´,
        ´[email protected]´,
        ´PasswordSicura123´
    );

    echo ´Utente registrato: ´ . $user->getEmail();
} catch (Throwable $e) {
    echo ´Errore: ´ . $e->getMessage();
}

Spiegazione

Il codice precedente mostra un approccio molto utile in un progetto PHP moderno: ogni metodo esplicita i tipi di input e output. Questo è uno dei modi più efficaci per rendere il codice chiaro e robusto.

1. declare(strict_types=1)

La direttiva declare(strict_types=1) dice a PHP di applicare controlli più rigorosi sui tipi. In pratica, evita conversioni automatiche ambigue. Per esempio, se un metodo accetta una stringa, PHP non proverà a trasformare automaticamente un intero in stringa in modo silenzioso.

Questo comportamento è molto utile perché riduce i bug difficili da individuare. In un progetto grande, la tipizzazione rigorosa aiuta a scoprire errori già in fase di sviluppo, non in produzione.

2. Tipi nei parametri

Nel metodo register(string $name, string $email, string $password): User, tutti i parametri sono dichiarati come stringhe. Questo comunica chiaramente al chiamante cosa deve passare.

Se qualcuno prova a inviare un array o un valore nullo, il problema emerge subito. Questo è un vantaggio enorme rispetto al PHP “dinamico” tradizionale, dove gli errori potevano restare nascosti fino all’esecuzione di una certa condizione.

3. Tipo di ritorno

Il metodo register() restituisce un oggetto User. Non restituisce un valore generico, non restituisce un array, non restituisce null: restituisce sempre un oggetto ben definito.

Questa scelta rende il codice più prevedibile e più facile da usare. Chi chiama il metodo sa già che riceverà un oggetto con metodi come getEmail() e getName().

4. Eccezioni specifiche

Il tutorial usa eccezioni diverse per errori diversi:

  • InvalidArgumentException per il nome vuoto
  • InvalidEmailException per email non valida
  • InvalidPasswordException per password troppo corta

Questa separazione è molto utile perché permette di gestire gli errori in modo più preciso. In un’applicazione reale, potresti mostrare messaggi diversi all’utente oppure registrare gli errori in modo distinto nei log.

5. Oggetto di dominio immutabile

La classe User usa proprietà promosse nel costruttore e non espone metodi per modificare i valori. Questo approccio rende l’oggetto più sicuro e più semplice da ragionare.

Un oggetto immutabile è spesso una scelta eccellente per rappresentare dati di dominio, perché evita modifiche accidentali durante il flusso dell’applicazione.

Best practice

Se vuoi applicare davvero bene i principi dei coding standard PHP in questo ambito, tieni presenti queste buone pratiche:

  • Usa sempre i tipi quando sono noti: parametri, ritorni, proprietà e costruttori dovrebbero essere tipizzati.
  • Abilita strict types: aiuta a evitare conversioni silenziose e comportamenti ambigui.
  • Preferisci tipi specifici: meglio restituire un User che un mixed o un array generico.
  • Usa eccezioni dedicate: rendono il codice più leggibile e la gestione degli errori più precisa.
  • Evita funzioni troppo lunghe: separa la validazione dalla logica di business, come nell’esempio.
  • Non nascondere i problemi con conversioni automatiche: il codice deve fallire in modo chiaro quando riceve dati errati.
  • Scrivi metodi piccoli e con responsabilità singola: ogni funzione dovrebbe fare una sola cosa bene.

Un altro consiglio importante è mantenere coerenza nel progetto: se una classe usa tipi stretti e ritorni espliciti, tutte le altre dovrebbero seguire lo stesso approccio. La qualità del codice non dipende da una singola classe, ma dalla disciplina complessiva del codice base.

Riepilogo

In questo tutorial abbiamo visto un aspetto molto concreto del mondo PHP, PSR e coding standard: l’uso corretto di tipi e valori di ritorno per scrivere codice più chiaro, sicuro e professionale.

I punti chiave sono questi:

  • declare(strict_types=1) migliora la precisione del codice.
  • Type hinting nei parametri rende le API interne più comprensibili.
  • Tipi di ritorno chiariscono cosa produce un metodo.
  • Eccezioni dedicate aiutano a gestire gli errori in modo pulito.
  • Oggetti immutabili riducono gli effetti collaterali.

Questo approccio non è solo “più moderno”: è anche più pratico. Nei progetti reali, il codice tipizzato è più facile da refactorare, più semplice da testare e più affidabile nel tempo.

Approfondisci con risorse ufficiali

  • PHP Manual - Tipi e dichiarazioni: documentazione ufficiale del linguaggio.
  • PHP FIG - standard e raccomandazioni condivise dalla community PHP.
  • PSR-12 - standard di formattazione del codice PHP moderno.
  • PSR-4 - standard di autoloading basato sui namespace.
  • PHP Manual - Eccezioni, classi e funzioni di validazione.

Se vuoi fare un passo ulteriore, il prossimo argomento da studiare è come combinare questi concetti con la progettazione orientata agli oggetti: classi piccole, responsabilità ben separate e dipendenze esplicite. È lì che PHP diventa davvero un linguaggio solido per applicazioni professionali.

SHARE