Vai al contenuto

Com’è cambiato PHP negli anni?

Checché se ne dica, Php è e rimane indubbiamente uno dei linguaggi di programmazione più diffusi e utilizzati per lo sviluppo di pagine web. Sono passati quasi 30 anni quando apparve per la prima volta e da allora ha subito diverse modifiche. Il suo comportamento dinamico, senza dover compilare il sorgente per renderlo eseguibile, legato alla sua interoperabilità tra sistemi operativi Linux e Windows, lo ha reso il linguaggio preferibile su cui lavorare. Php utilizza tipi di dati e diverse funzioni di C e C++. La programmazione orientata agli oggetti è stata aggiunta per la prima volta nell’estensione php3 e ulteriori miglioramenti sono stati apportati nelle versioni successive. L’evoluzione di PHP ha rivoluzionato la capacità dei programmatori web di creare pagine web dinamiche e applicazioni per i propri consumatori.

Cenni storici

Php è stato sviluppato da Rasmus Lerdorf nel 1994 per il proprio sito Web per preservare la sua home page personale. Più tardi, nel 1998, altri due programmatori Andi Gutmans e Zeev Suraski si unirono a lui. Nel testo originale della mail che Lerdorf scrisse, l’8 giugno 1995, presentò la prima versione di PHP come Personal Home Page Tools (PHP Tools) poiché fu creato per uso personale. Nel 1997 fu fondata la Zend Technologies Ltd. da Andi Gutmans e Zeev Suraski che contribuì in maniera significativa alla popolarità globale e il riconoscimento dalla comunità dei programmatori. E’ in questi anni che il suo nome cambiò nell’acronimo ricorsivo che tutti conosciamo: PHP Hypertext Preprocessor.

L’obiettivo dietro lo sviluppo di questo linguaggio non era di farne un linguaggio globale. In effetti, ha guadagnato popolarità per inciso, cosa incontrollabile per Rasmus Lerdorf per proteggere e limitare la sua individualità. Tuttavia, questa impresa si è rivelata vantaggiosa per le generazioni future per avere un facile accesso a Internet e scoprire nuove tecniche di sviluppo web.

Tutti abbiamo assistito alla crescita dello sviluppo web che è stato regolarmente integrato dallo sviluppo di nuove estensioni PHP che consentono ai programmatori web di pensare oltre la loro immaginazione e di produrre pagine web sempre più attraenti e dinamiche. Ecco alcune modifiche che le versioni php hanno subito nel corso del tempo:

  • PHP 1 e 2: le prime due versioni iniziali di php non hanno abbastanza funzionalità ma piantano le basi per lo sviluppo delle prossime versioni
  • PHP 3 e 4:  queste due versioni hanno subito modifiche sostanziali poiché Zeev Suraski e Andi Gutmans hanno ricreato l’intero linguaggio che ha portato al nuovo nome del linguaggio Hypertext Preprocessor. Durante questa fase è stato aggiunto un sistema di analisi più avanzato chiamato Zend Engine. L’introduzione di variabili superglobali, interfaccia a riga di comando e programmazione orientata agli oggetti ha reso le sue funzionalità più potenti.
  • PHP 5:  Nel 2004 è stata presentata la quinta versione di php, alimentata dal nuovo Zend Engine II. Questa versione includeva la funzionalità per manipolare il database con facilità e avere continuità. La variabile vincolante è stata aggiunta in questa versione.
  • PHP 6:  In questa versione, la libreria ICU (International Components for Unicode) era incorporata nel programma. Ma per diversi altri motivi questa versione è stata abbandonata e non è stata lanciata sul mercato.
  • PHP 7:  Questa è la penultima versione con offre diverse funzionalità non presenti nelle versioni precedenti come il supporto per interi a 64 bit, ritorno e dichiarazioni di tipo scalare ecc. È alimentato da Zend Engine 3.

La versione 8

PHP 8 è stato rilasciato il 26 novembre 2020. A causa delle modifiche sostanziali, c’è una buona probabilità che gli script scritti in una versione precedente di PHP debbano essere aggiornati per farli girare su PHP 8. Tuttavia, l’aggiornamento non dovrebbe essere troppo complicato, specie se gli script sono stati tenuti aggiornati alle ultime versioni, poichè la maggior parte delle modifiche sostanziali erano già deprecate in precedenza nelle versioni 7.*. Passiamo in rassegna una lista di nuove caratteristiche presenti nell’ultima versione di PHP.

Named Parameters

PHP 8.0 consente il passaggio di named parameters nelle chiamate di funzioni/metodi oltre ai tradizionali parametri posizionali.

// positional parameters
function str_contains(string $haystack, string needle): bool {}
str_contains('FooBar', 'Foo');

// named parameter
str_contains(haystack: 'FooBar', needle: 'Foo');
str_contains(needle: 'Foo', haystack: 'FooBar');

I named parameters offrono una maggiore leggibilità quando si chiama una funzione con parametri che non richiedono un ordine particolare o non possono essere resi più intuitivi. In questo caso, l’ordine dei parametri passati non è importante, purché vengano passati tutti i parametri richiesti.

Attributes

Uno dei più grandi nuovi cambiamenti in PHP 8 è il supporto per gli attributi. Gli attributi aiutano ad aggiungere metadati a funzioni PHP, parametri, classi, metodi di classe, costanti, proprietà, chiusure e persino classi anonime. Questi metadati possono essere recuperati a livello di codice e forniscono un approccio pragmatico per risolvere gli attributi in altre parti del codice.

Gli attributi sono dichiarati con i simboli #[]

#[CustomAttribute] 
class Foo { 
    #[AnotherAttribute(42)] 
    public function bar(): void {} 
}

Poichè il cancelletto # viene considerato in tutte le versioni di PHP come una riga di commento, quando un attributo viene utilizzato, non causerà un errore di sintassi nelle versioni PHP precedenti alla 8.0. Ciò rende il codice che utilizza attributi PHP 8.0 in qualche modo retrocompatibile. In precedenza gli attributi/annotazioni richiedevano la loro memorizzazione nei commenti DocBlock e l’analisi della stringa per dedurli.

Proprietà del construttore (Constructor Property)

Constructor Property Promotion è una nuova sintassi in PHP 8 che consente la dichiarazione di proprietà della classe e l’ assegnazione del costruttore direttamente dal costruttore. In pratica è una sintassi abbreviata per dichiarare e assegnare le proprietà della classe dal costruttore . Ciò evita di dover digitare il nome della proprietà della classe da quattro volte a una sola volta e il tipo di proprietà da due volte a una sola .

Una classe tipica che dichiara una proprietà e quindi le assegna un valore nel costruttore di classe è piuttosto dettagliata.

class User {
    private string $name;
    public function __construct(string $name) {
        $this->name = $name;
    }
}

Utilizzando la notazione Constructor Property, ciò si traduce in una sintassi molto semplificata e minima che è funzionalmente identica alla dichiarazione dettagliata della classe:

class User {
    public function __construct(private string $name) {}
}

Compilazione JIT (Just-In-Time)

I linguaggi di programmazione interpretati non hanno fasi di compilazione ed eseguono direttamente il codice in una macchina virtuale. La maggior parte dei linguaggi interpretati (incluso PHP) ha un passaggio di compilazione “leggero” per migliorarne le prestazioni. I linguaggi di programmazione con la compilazione Ahead-Of-Time (AOT) , d’altra parte, richiedono che il codice sia compilato prima che venga eseguito. La compilazione Just-In-Time è un modello ibrido di interpretazione e di compilazione Ahead-of-Time, in cui parte o tutto il codice viene compilato, spesso in fase di esecuzione, senza richiedere allo sviluppatore di compilarlo manualmente.

PHP era storicamente un linguaggio interpretato, in cui tutto il codice veniva interpretato da una macchina virtuale (Zend VM). Questo è stato cambiato con l’introduzione di Opcache e Opcodes, che possono memorizzare nella cache il bytecode di PHP. La versione 7.0 di ha aggiunto il concetto di AST (Abstract Syntax Tree), che separava ulteriormente il parser dal compilatore. JIT di PHP utilizza internamente DynASM da LuaJIT e implementato come parte di Opcache. JIT è disabilitato di default e, se abilitato dal file php.ini, fornisce un aumento delle prestazioni per le applicazioni pesanti per la CPU.

# Enabling JIT in php.ini 
opcache.enable=1 
opcache.jit_buffer_size=100M 
opcache.jit=tracing

Union Types

Nelle versioni precedenti a PHP 8.0, era possibile dichiarare un solo tipo per proprietà, parametri e tipi restituiti. PHP 7.1 e versioni successive hanno introdotto il tipo nullable, il che significa che possiamo dichiarare il tipo null con una dichiarazione di tipo simile a ?string. Con PHP 8.0, possiamo dichiarare più di un tipo per argomenti, tipi restituiti e proprietà di classe.

class Example {
    private int|float $foo;
    public function squareAndAdd(float|int $bar): int|float {
        return $bar ** 2 + $foo;
    }
}

PHP ora si assicurerà che i parametri della funzione, i tipi restituiti e le proprietà della classe appartengano a uno dei tipi dichiarati nella definizione. Ne riparleremo in un articolo dedicato.

Operatore Null Safe

L’operatore Null-safe è una nuova sintassi in PHP 8.0, che fornisce il concatenamento opzionale. Durante la valutazione degli elementi, se un elemento della catena ha esito negativo, l’esecuzione dell’intera catena verrà interrotta e restituirà un valore nullo, senza causare errori. Poiché gli arresti anomali del programma causati da valori null sono molto frequenti, l’operatore null safe rappresenta una garanzia in più per il buon funzionamento del programma.

La sintassi dell’operatore null safe è simile l’operatore di accesso al metodo/alla proprietà -> ma con l’aggiunta di un ?, quindi ?->

class Customer {
    public function getAddress(): ?Address {}
}
class Address {
    public function getCountry(): string {}
}

$country = $customer->getAddress()->getCountry();

Chiamando  Customer::getAddress(), poichè il valore restituito del metodo è definito nullable (cioè ?Address), la funzione potrebbe può restituire un valore null o un oggetto di tipo Address. La $customer->getAddress()->getCountry() è una catena non “null safe” e PHP potrebbe generare un errore se il valore restituito di getAddress() è null, poichè tenta di chiamare il getCountry() su null:

Fatal error: Uncaught Error: Call to a member function getCountry() on null in ...

Per ovviare a questo problema, bisognerebbe quindi controllare se il getAddress() ritorna un oggetto oppure null e poi comportarsi di conseguenza. Diciamo che dovremmo utilizzare un paio di condizioni if e isset() per evitare errori nel programma.

Su PHP 8, possiamo invece usare i null safe. Quindi, con una singola riga, risolveremmo tutti i problemi, poichè l’operatore null safe cortocircuita l’accesso alla proprietà/al metodo e ritornando null immediatamente se il lato sinistro dell’operatore è null, senza eseguire il resto dell’espressione.

$country = $customer->getAddress()?->getCountry();

Espressioni match

Le espressioni match sono simili ai blocchi switch, ma i blocchi match migliora notevolmente la sintassi del blocco switch fornendo confronti indipendenti dai tipi, possono restituire un valore, non richiedono l’uso di break per il breakout e supportano più valori di corrispondenza (come si vede nell’esempio). A differenza di switch, il match può contenere solo un’espressione (una singola riga) per ogni singolo caso. Inoltre,  deve esserci una condizione che corrisponda all’espressione o un caso di default per gestirla. Se non ci sono corrispondenze, match genera un’eccezione UnhandledMatchError.

$status = match($request_method) {
    'post' => $this->handlePost(),
    'get', 'head' =>  $this->handleGet(),
    default => throw new \Exception('Unsupported'),
};

Weakmap (Mappe deboli)

Normalmente, quando si crea un oggetto e lo si assegna a una variabile, ciò che accade è che l’oggetto viene creato in memoria e quindi viene creata la variabile come riferimento ad esso. Possiamo vederla come la variabile che ha solo l’indirizzo dell’oggetto, non l’oggetto stesso. Se assegniamo ad un’altra variabile lo stesso oggetto, c’è ancora un solo oggetto, ma ora ci sono due variabili con l’indirizzo dell’oggetto.

$a = new Foo();
$b = $a;

// $a e $b, nonostante siano variabili diverse, puntano allo stesso oggetto Foo

Ogni volta che una variabile viene rimossa, PHP controlla se ci sono altre variabili che fanno ancora riferimento a quell’oggetto. Se non ce ne sono, sa che è sicuro eliminare quell’oggetto. Questo processo è chiamato “garbage collector”.

Una Weakmap è un modo per creare una variabile che si comporta come qualsiasi altra, ma quando PHP verifica se qualche variabile punta ancora a un oggetto, quelle variabili “deboli” non contano. Quindi, se ci sono ancora tre riferimenti deboli che puntano a un oggetto, ma nessuna variabile normale, PHP eliminerà l’oggetto e imposterà simpaticamente le restanti variabili su null.

 

Tag: