I principi SOLID nella pratica
Applicate i cinque principi SOLID a classi PHP reali.
I principi SOLID nella pratica è una lezione PHP Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento PHP Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso PHP Academy include 4 lezioni in totale.
Perché SOLID
SOLID comprende cinque principi di progettazione che mantengono il codice PHP orientato agli oggetti flessibile, testabile e resistente al deterioramento. Non sono regole da seguire ciecamente, ma euristiche che riducono l'accoppiamento e chiariscono le responsabilità. In questa lezione applicheremo ogni principio a classi PHP concrete che utilizzereste realmente in produzione.
- Single Responsibility
- Open/Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
Single Responsibility
Una classe dovrebbe avere un solo motivo per cambiare. Una classe che crea un report, lo formatta in HTML e lo invia via email ha tre motivi per cambiare. Separate persistenza, formattazione e trasporto.
Di seguito, Invoice modella solo i dati; il rendering e il salvataggio risiedono altrove.
<?php
final class Invoice {
public function __construct(
public readonly string $number,
public readonly int $cents
) {}
public function total(): float { return $this->cents / 100; }
}
final class InvoiceRenderer {
public function toText(Invoice $i): string {
return sprintf('Invoice %s: $%.2f', $i->number, $i->total());
}
}
$i = new Invoice('INV-1', 12500);
echo (new InvoiceRenderer())->toText($i), PHP_EOL;
SRP: individuare il problema
La tipica violazione dell'SRP è una classe il cui nome contiene and oppure un Manager che fa tutto. Prestate attenzione ai metodi che cambiano per motivi di business non correlati. Se una modifica alle regole fiscali e una modifica al layout PDF interessano entrambe la stessa classe, significa che questa ha troppe responsabilità.
Principio Open/Closed
Le entità software dovrebbero essere aperte all'estensione e chiuse alla modifica. L'aggiunta di un nuovo tipo di sconto non dovrebbe richiedere modifiche a un enorme switch. Utilizzate il polimorfismo: ogni regola deve avere una propria classe che implementa un'interfaccia condivisa.
<?php
interface Discount { public function apply(float $total): float; }
final class PercentOff implements Discount {
public function __construct(private float $pct) {}
public function apply(float $t): float { return $t * (1 - $this->pct / 100); }
}
final class FlatOff implements Discount {
public function __construct(private float $amount) {}
public function apply(float $t): float { return max(0, $t - $this->amount); }
}
function checkout(float $total, Discount ...$discounts): float {
foreach ($discounts as $d) { $total = $d->apply($total); }
return $total;
}
echo checkout(100, new PercentOff(10), new FlatOff(5)), PHP_EOL; // 85
Sostituzione di Liskov
I sottotipi devono poter essere utilizzati ovunque sia previsto il loro tipo base, senza sorprendere il chiamante. Il celebre esempio Square extends Rectangle viola l'LSP, perché impostare la larghezza non deve modificare silenziosamente l'altezza. È preferibile modellarli come tipi distinti dietro un'interfaccia Shape comune.
<?php
interface Shape { public function area(): float; }
final class Rectangle implements Shape {
public function __construct(private float $w, private float $h) {}
public function area(): float { return $this->w * $this->h; }
}
final class Square implements Shape {
public function __construct(private float $side) {}
public function area(): float { return $this->side ** 2; }
}
$shapes = [new Rectangle(2, 3), new Square(4)];
foreach ($shapes as $s) { echo $s->area(), PHP_EOL; }
LSP e contratti
L'LSP impone vincoli anche ai contratti dei metodi. Un sottotipo può indebolire le precondizioni e rafforzare le postcondizioni, ma mai il contrario. Lanciare un nuovo tipo di eccezione che il tipo base non aveva dichiarato, oppure restituire null quando il tipo base garantisce un oggetto, viola la sostituibilità. I tipi restituiti covarianti e i tipi dei parametri controvarianti di PHP impongono parte di questi vincoli a livello di tipo.
Segregazione delle interfacce
I client non dovrebbero dipendere da metodi che non utilizzano. Un'interfaccia Worker troppo ampia, con work() e eat(), obbliga un RobotWorker a fornire un'implementazione fittizia di eat(). Dividete l'interfaccia in interfacce di ruolo focalizzate, così ogni implementazione si impegna solo a svolgere ciò che fa realmente.
<?php
interface Workable { public function work(): string; }
interface Feedable { public function eat(): string; }
final class Human implements Workable, Feedable {
public function work(): string { return 'coding'; }
public function eat(): string { return 'lunch'; }
}
final class Robot implements Workable {
public function work(): string { return 'welding'; }
}
foreach ([new Human(), new Robot()] as $w) { echo $w->work(), PHP_EOL; }
Inversione delle dipendenze
Le politiche di alto livello dovrebbero dipendere da astrazioni, non da dettagli concreti. Iniettate un'interfaccia, non una classe codificata direttamente. In questo modo potete sostituire un mailer reale con un fake nei test e con un vendor diverso in produzione senza modificare il consumer.
<?php
interface Mailer { public function send(string $to, string $body): void; }
final class SmtpMailer implements Mailer {
public function send(string $to, string $body): void {
echo "SMTP -> $to: $body" . PHP_EOL;
}
}
final class SignupService {
public function __construct(private Mailer $mailer) {}
public function register(string $email): void {
$this->mailer->send($email, 'Welcome!');
}
}
(new SignupService(new SmtpMailer()))->register('a@b.com');
DIP e il container
L'inversione delle dipendenze è il principio; l'iniezione delle dipendenze è una delle tecniche per soddisfarlo. Un container DI (PSR-11) collega il concreto SmtpMailer all'astrazione Mailer nel composition root. Il consumer non scrive mai new SmtpMailer(), quindi la direzione della dipendenza nel codice sorgente punta verso l'astrazione, non verso il dettaglio.
<?php
// Composition root wiring (pseudo-container)
$bindings = [
Mailer::class => fn() => new SmtpMailer(),
];
$resolve = fn(string $id) => $bindings[$id]();
$service = new SignupService($resolve(Mailer::class));
$service->register('user@example.com');
SOLID insieme
I principi si rafforzano a vicenda. L'ISP mantiene piccole le interfacce, così le iniezioni DIP restano focalizzate; l'OCP si basa sul polimorfismo, che l'LSP mantiene sicuro; l'SRP fornisce le piccole classi che rendono possibile tutto questo. Puntate alla coesione interna e allo scarso accoppiamento tra componenti.
- Non create un'astrazione eccessiva per una classe utilizzata una sola volta.
- Introducete un'interfaccia quando compare una seconda implementazione o un test double.
Pragmatismo
SOLID è un mezzo, non un fine. Un'interfaccia prematura con una sola implementazione aggiunge un livello di indirezione senza alcun vantaggio ("generalizzazione speculativa"). Applicate i principi quando il cambiamento si presenta realmente o è chiaramente imminente. Rifattorizzare verso SOLID è economico quando disponete già di test; rifattorizzare ciecamente verso SOLID fin dal primo giorno è uno spreco.
Verifica rapida
Quale principio viola il problema dell'ereditarietà Square/Rectangle?
Riepilogo
Avete applicato tutti e cinque i principi SOLID al PHP reale:
- SRP: un solo motivo per cambiare per ogni classe.
- OCP: estendere tramite nuove classi polimorfiche, non modificando uno switch.
- LSP: i sottotipi rispettano il contratto del tipo base.
- ISP: interfacce di ruolo piccole invece di interfacce troppo ampie.
- DIP: dipendere dalle astrazioni e iniettare i dettagli nel composition root.
Utilizzateli per guidare il refactoring, non come semplice formalità.
Impara PHP con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 49
- Lezioni
- 195
Domande Frequenti
La lezione «I principi SOLID nella pratica» è gratuita?
Sì — il testo completo di «I principi SOLID nella pratica» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso PHP Academy, passa a CoddyKit PRO. Il corso PHP Academy include 4 lezioni in totale.
Cosa imparerò in «I principi SOLID nella pratica»?
Applicate i cinque principi SOLID a classi PHP reali. Eserciti PHP Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare PHP Academy?
Non è richiesta alcuna esperienza precedente. PHP Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «I principi SOLID nella pratica»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione PHP Academy?
Sì. Ogni lezione PHP Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- I principi SOLID nella pratica
- Pattern creazionali: Factory, Builder, Singleton
- Pattern strutturali: Adapter, Decorator, Facade
- Pattern comportamentali: Strategy, Observer, Command