Promessa di retrocompatibilità

Assicurare facili aggiornamenti dei progetti è una prorità. Per questo motivo, Symfony promette retrocompatibilità per tutti i suoi rilasci minori. Questa strategia è anche nota come versionamento semantico. In breve, versionamento semantico vuol dire che solo i rilasci maggiori (come 2.0, 3.0, ecc.) possono infrangere la retrocompatibilità. I rilasci minori (come 2.5, 2.6, ecc.) possono introdurre nuove caratteristiche, ma devono farlo senza infrangere l’API esistente del ramo (2.x nell’esempio).

Attenzione

Questa promessa è stata introdotta con Symfony 2.3 e quindi non si applica alle versioni precedenti.

Tuttavia, la retrocompatibilità ha diversi aspetti. Di fatto, quasi ogni modifica fatta sul framework può potenzialmente rompere un’applicazione. Per esempio, se si aggiunge un nuovo metodo a una classe, questo potrebbe rompere un’applicazione che estende tale classe e ha quello stesso metodo, ma con una firma diversa.

Inoltre, non tutte le infrazioni alla retrocompatibilità hanno lo stesso impatto sul codice. Mentre alcune infrazioni richiedono modifiche significative a classi o architettura, altre possono essere risolte semplicemente cambiando un nome di metodo.

Per questo è stata creata questa pagina. la sezione “Usare il codice di Symfony” dirà come assicurarsi che un’applicazione non si rompa completamente durante un aggiornamento a una nuova versione dello stesso ramo.

La seconda sezione, “Lavorare sul codice di Symfony”, ha come obiettivo i contributori di Symfony. Questa sezione elenca regole dettagliate che ogni contributori deve seguire per assicurare aggiornamenti tranquilli agli utenti.

Usare il codice di Symfony

Se si usa Symfony in un progetto, le linee guida seguenti aiuteranno ad assicurare aggiornamenti tranquilli di tutti i rilasci minori futuri della stessa versione di Symfony.

Uso delle interfacce

Tutte le interfacce di Symfony possono essere usate per forzare i tipi. Si possono anche richiamare tutti i metodi dichiarati. È garantito che non sarà infranto il codice legato a tali regole.

Attenzione

Fanno eccezione a questa regola le interfacce con tag @internal. Tali interfacce non andrebbero usate o implementate.

Se si vuole implementare un’interfaccia, ci si deve prima assicurare che sia un’interfaccia API. Si possono riconoscere le interfacce API dal tag @api nel codice sorgente:

/**
 * HttpKernelInterface handles a Request to convert it to a Response.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
interface HttpKernelInterface
{
    // ...
}

Se si implementa un’interfaccia API, la promessa è che il codice non sarà mai rotto. Le interfacce normali, invece potrebbero essere estese nei rilasci minori, per esempio con aggiunte di nuovi metodi. Occorre essere pronti ad aggiornare a mano del codice, se si implementa un’interfaccia normale.

Nota

Anche in modifiche che richiedano aggiornamenti manuali, sarà assicurato che tali modifiche siano semplici. Ci saranno sempre precise istruzioni nel file UPGRADE della cartella radice di Symfony.

La tabella seguente spiega in dettaglio i casi d’uso coperti dalla promessa di retrocompatibilità:

Caso d’uso Normale API
Se... Retrocompatibilità garantita
Si forza il tipo tramite interfaccia
Si richiama un metodo
Se si implementa l’interfaccia e... Retrocompatibilità garantita
Si implementa un metodo No [1]
Si aggiunge un parametro a un metodo implementato No [1]
Si aggiunge un valore predefinito a un parametro Yes

Nota

Se si ritiene che una classe normale debba avere un tag @api, inserire la propria richiesta in una issue su GitHub. Sarà fatta una valutazione sull’opportunità di inserire il tag o meno.

Uso delle classi

Tutte le classi fornite da Symfony possono essere instanziate e accedute tramite i loro metodi e proprietà pubblici.

Attenzione

Classi, proprietà e metodi con tag @internal, come anche le classi che si trovano negli spazi dei nomi *\\Tests\\, fanno eccezione a questa regola. Sono pensati solo per uso interno e non vanno acceduti.

Proprio come per le interfacce, c’è una distinzione tra classi API e classi normali. Come le interfacce API, le classi API sono contraddistinte da un tag @api:

/**
 * Request represents an HTTP request.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class Request
{
    // ...
}

La differenza tra classi normali e classi API è la garanzia di piena retrocompatibilità se si estende una classe API e se ne sovrascrivono i metodi. Non c’è la stessa garanzia per le classi normali, in cui potrebbero, per esempio, essere aggiunti parametri a metodi. Di conseguenza, la firma di un metodo sovrascritto non corrisponderebbe più e genererebbe un errore fatale.

Nota

Come per le interfacce, eventuali modifiche garantiscono comunque facili aggiornamenti. Istruzioni dettagliate saranno fornite nel file UPGRADE della cartella radice di Symfony.

In alcuni casi, solo proprietà e metodi specifici hanno il tag @api, pur trovandosi in classi normali. In questi casi, la piena retrocompatibilità è garantita per proprietà e metodi (come indicato nella colonna API qui sotto), ma non per il resto della classe.

Per sicurezza, verificare nella tabella seguente quali casi d’uso siano coperti dalla promessa di retrocompatibilità:

Caso d’uso Normale API
Se...* Retrocompatibilità garantita
Si forza il tipo tramite classe
Si crea una nuova istanza
Si estende la classe
Si accede a una proprietà pubblica
Si richiama un metodo pubblico
Se si estende la classe e... Retrocompatibilità garantita
Si accede a una proprietà protetta No [1]
Si richiama un metodo protetto No [1]
Si sovrascrive una proprietà pubblica
Si sovrascrive una proprietà protetta No [1]
Si sovrascrive un metodo pubblico No [1]
Si sovrascrive un metodo protetto No [1]
Si aggiunge una nuova proprietà No No
Si aggiunge un nuovo metodo No No
Si aggiunge un parametro a un metodo sovrascritto No [1]
Si aggiunge un valore predefinito a un parametro
Si richiama un metodo privato (tramite Reflection) No No
Si accede a una proprietà privata (tramite Reflection) No No

Nota

Se si ritiene che una classe normale debba avere un tag @api, inserire la propria richiesta in una issue su GitHub. Sarà fatta una valutazione sull’opportunità di inserire il tag o meno.

Lavorare sul codice di Symfony

Per chi volesse contribuire a migliorare Symfony, nella prossima sezione saranno mostrare le regole che assicurano aggiornamenti tranquilli per gli utenti.

Modifica di interfacce

Questa tabella indica quali modifiche sono consentite quando si lavora sulle interfacce di Symfony:

Tipo di modifica Normale API
Rimuovere del tutto No No
Cambiare nome o spazio dei nomi No No
Aggiungere interfaccia genitrice [2] [3]
Rimuovere interfaccia genitrice No No
Metodi    
Aggiungere metodo [2] No
Rimuovere metodo No No
Cambiare nome No No
Spostare nell’interfaccia genitrice
Aggiungere parametro senza valore predefinito No No
Aggiungere parametro con valore predefinito [2] No
Rimuovere parametro [4] [4]
Aggiungere valore predefinito a un parametro [2] No
Rimuovere valore predefinito a un parametro No No
Aggiungere tipo forzato a un parametro No No
Rimuovere tipo forzato da un parametro [2] No
Cambiare tipo di parametro [2] [5] No
Cambiare tipo restituito [2] [6] No

Modifica di classi

Questa tabella indica quali modifiche sono consentite quando si lavora sulle classi di Symfony:

Tipo di modifica Normale API
Rimuovere del tutto No No
Rendere finale No No
Rendere astratta No No
Cambiare nome o spazio dei nomi No No
Cambiare classe genitrice [7] [7]
Aggiungere interfaccia
Rimuovere interfaccia No No
Proprietà pubbliche    
Add public property
Rimuovere proprietà pubblica No No
Ridurre visibilità No No
Spostare in classe genitrice
Proprietà protette    
Aggiungere proprietà protetta
Rimuovere proprietà protetta [2] No
Ridurre visibilità [2] No
Spostare in classe genitrice
Proprietà private    
Aggiungere proprietà privata
Rimuovere proprietà privata
Construttori    
Aggiungere costruttore senza parametri obbligatori [2] [2]
Rimuovere costruttore [2] No
Ridurre visibilità di un costruttore pubblico No No
Ridurre visibilità di un costruttore protetto [2] No
Spostare in classe genitrice
Metodi pubblici    
Aggiungere metodo pubblico
Rimuovere metodo pubblico No No
Cambiare nome No No
Ridurre visibilità No No
Spostare in classe genitrice
Aggiungere parametro senza valore predefinito No No
Aggiungere parametro con valore predefinito [2] No
Rimuovere parametro [4] [4]
Aggiungere valore predefinito a un parametro [2] No
Rimuovere valore predefinito a un parametro No No
Aggiungere tipo forzato a un parametro [8] No
Rimuovere tipo forzato da un parametro [2] No
Cambiare tipo di parametro [2] [5] No
Cambiare tipo restituito [2] [6] No
Metodi protetti    
Aggiungere metodo protetto
Rimuovere metodo protetto [2] No
Cambiare nome No No
Ridurre visibilità [2] No
Spostare in classe genitrice
Aggiungere parametro senza valore predefinito [2] No
Aggiungere parametro con valore predefinito [2] No
Rimuovere parametro [4] [4]
Aggiungere valore predefinito a un parametro [2] No
Rimuovere valore predefinito a un parametro [2] No
Aggiungere tipo forzato a un parametro [2] No
Rimuovere tipo forzato da un parametro [2] No
Cambiare tipo di parametro [2] [5] No
Cambiare tipo restituito [2] [6] No
Metodi privati    
Aggiungere metodo privato
Rimuovere metodo privato
Cambiare nome
Ridurre visibilità
Aggiungere parametro senza valore predefinito
Aggiungere parametro con valore predefinito
Rimuovere parametro
Aggiungere valore predefinito a un parametro
Rimuovere valore predefinito a un parametro
Aggiungere tipo forzato a un parametro
Rimuovere tipo forzato da un parametro
Cambiare tipo di parametro
Cambiare tipo restituito
Metodi statici    
Cmabiare non statico in statico No No
Cmabiare statico in non statico No No
[1](1, 2, 3, 4, 5, 6, 7, 8) Il codice dell’applicazione potrebbe rompersi in conseguenza di modifiche al codice di Symfony. Tali modifiche saranno tuttavia documentate nel file UPGRADE.
[2](1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28) Va evitato. Se fatto, la modifica deve essere documentata nel file UPGRADE.
[3]L’interfaccia genitrice aggiunta non deve introdurre metodi che non esistono già nell’interfaccia.
[4](1, 2, 3, 4, 5, 6) Si possono rimuovere solo gli ultimi parametri, poiché PHP tralascia eventuali parametri in sovrannumero passati a un metodo.
[5](1, 2, 3)

Il tipo di parametro può essere cambiato solo con uno compatibile o meno specifico. Sono ammesse le seguenti modifiche:

Tipo originale Nuovo tipo
booleano qualsiasi tipo scalare con equivalenti valori booleani
stringa qualsiasi tipo scalare od oggetto con equivalenti valori stringhe
intero qualsiasi tipo scalare con equivalenti valori interi
virgola mobile qualsiasi tipo scalare con equivalenti valori a virgola mobile
classe <C> qualsiasi superclasse o interfaccia di <C>
interfaccia <I> qualsiasi superinterfaccia di <I>
[6](1, 2, 3)

Il tipo restituito può essere cambiato solo con uno compatibile o più specifico. Sono ammesse le seguenti modifiche:

Tipo originale Nuovo tipo
boolean qualsiasi tipo scalare con equivalenti valori booleani
string qualsiasi tipo scalare or object with equivalent valori stringhe
integer qualsiasi tipo scalare con equivalenti valori interi
float qualsiasi tipo scalare con equivalenti valori a virgola mobile
array istanza di ArrayAccess, Traversable e Countable
ArrayAccess array
Traversable array
Countable array
classe <C> qualsiasi sottoclasse di <C>
interfaccia <I> qualsiasi sottointerfaccia o classe che implementi <I>
[7](1, 2) Quando si cambia la classe genitrice, la classe genitrice originale deve restare un antenato della classe.
[8]Un tipo forzato si può aggiungere solo se il passaggio di un valore con tipo diverso generava in precedenza un errore fatale.

Tabella dei contenuti

Argomento precedente

Eseguire i test di Symfony

Argomento successivo

Standard del codice

Questa pagina