---
title: 'PHP 8.0 from PHP 7.4: JIT, Union Types, Match & Nullsafe — Upgrade Guide | DevSense'
description: 'Esplora PHP 8.0 dopo PHP 7.4: argomenti con nome (named arguments), espressione match, operatore nullsafe, attributi, compilatore JIT, tipi unione (union types)—cosa cambia, cosa riscrivere ed esempi pratici.'
faq:
    - { question: 'Qual è il vantaggio principale del compilatore JIT in PHP 8.0?', answer: "Il compilatore JIT (Just-In-Time) traduce il bytecode in codice macchina in tempo reale (runtime), offrendo fino al 500% di incremento delle prestazioni per le operazioni pesanti limitate dalla CPU (CPU-bound), sebbene le tipiche applicazioni web registrino un guadagno di circa l'1-5%." }
    - { question: "Come differisce l'espressione match dalla classica istruzione switch?", answer: "Match utilizza il confronto di identità stretto (===), restituisce direttamente un valore, non presenta comportamenti di fall-through (quindi non richiede il comando 'break') e lancia un UnhandledMatchError se nessun valore corrisponde e non viene fornito un ramo 'default'." }
    - { question: "Cos'è la Constructor Property Promotion in PHP 8.0?", answer: "La Constructor Property Promotion consente agli sviluppatori di dichiarare e inizializzare le proprietà delle classi direttamente all'interno dell'elenco dei parametri del costruttore, eliminando la necessità di dichiarazioni ed assegnazioni separate." }
    - { question: 'Come sono cambiati i confronti non rigidi (loose comparisons) in PHP 8.0?', answer: 'In PHP 8.0, i confronti non rigidi tra numeri e stringhe non numeriche confrontano questi elementi come stringhe anziché convertire la stringa nel valore 0, prevenendo bug come ''0 == "foobar"'' che restituiva true.' }
published: '2026-05-31'
---
# PHP 8.0: Funzionalità principali

Da PHP 7.4: note basate su benchmark su JIT, tipi e modifiche non retrocompatibili che emergono nelle applicazioni reali.

## Indice
* [Argomenti con nome (Named Arguments)](#named-arguments)
* [Espressione Match](#match-expression)
* [Operatore Nullsafe (?->)](#nullsafe-operator)
* [Constructor Property Promotion](#constructor-promotion)
* [Evoluzione del sistema dei tipi (Union, mixed, static)](#type-system)
* [Attributi / Annotazioni](#attributes)
* [Nuove funzioni di stringa](#string-functions)
* [Weak Map](#weak-maps)
* [Espressione Throw e gestione degli errori](#throw-and-errors)
* [Compilatore JIT e prestazioni](#jit-performance)
* [Modifiche ai moduli e al core](#modules-changes)
* [Aggiustamenti sintattici (::class, virgole finali)](#syntax-tweaks)
* [Confronti più coerenti tra stringhe e numeri](#saner-comparisons)
* [Modifiche non retrocompatibili (note di migrazione)](#backward-incompatible)
* [Errori comuni](#common-mistakes)
* [Quiz di autovalutazione](#self-test-quiz)

---

L'aggiornamento a una nuova versione principale del linguaggio rappresenta sempre una scommessa ad alta posta: desideri i nuovi incrementi di prestazioni, ma temi i crash di produzione notturni causati da vecchi presupposti del codice legacy. PHP 8.0 non è una tipica versione minore—è un ripristino fondamentale della piattaforma. Introducendo il compilatore JIT, convertendo le coercizioni dei tipi deboli in confronti rigorosi e trasformando i warning silenziosi in eccezioni Error che interrompono gli script, PHP 8.0 richiede un cambio totale nel modo in cui scriviamo ed eseguiamo la migrazione del nostro codice. Ecco una panoramica pragmatica e testata sul campo di ciò che cambia sotto il cofano e di cosa si romperà effettivamente nella tua applicazione.

<a id="named-arguments"></a>
## Argomenti con nome (Named Arguments)

Il passaggio di argomenti a una funzione tramite il loro nome elimina la necessità di ricordarne l'ordine e consente di saltare i parametri opzionali. Questo rende il codice autodocumentante.

> [!NOTE]
> **Lo sapevi?**
> A partire da PHP 8.0, se utilizzi gli argomenti con nome, rinominare un parametro in un metodo di una classe padre o di un'interfaccia rappresenta una modifica non retrocompatibile! Se una classe figlia o un chiamante utilizza il vecchio nome del parametro, verrà generata un'eccezione `ArgumentCountError` o `Error`.

```php
// Prima: era necessario specificare tutti i parametri nell'ordine corretto
// app/Services/CookieService.php
setcookie('test', '', time() + 60 * 60 * 2, '/', '', false, true);

// PHP 8.0: specifica solo ciò che è richiesto
// app/Services/CookieService.php
setcookie(
    name: 'test',
    expires: time() + 60 * 60 * 2,
    httponly: true
);
```

---

<a id="match-expression"></a>
## Espressione Match

Un'alternativa più rigorosa e concisa all'istruzione switch. Restituisce un valore e utilizza il confronto di tipo stretto (===), eliminando bug imprevisti dovuti alla coercizione implicita dei tipi.

```php
// app/Services/ResponseService.php
$statusCode = 200;

$statusMessage = match ($statusCode) {
    200, 300 => 'Successo o Reindirizzamento',
    400, 404 => 'Errore Client',
    500 => 'Errore Server',
    default => 'Stato sconosciuto',
};
```

---

<a id="nullsafe-operator"></a>
## Operatore Nullsafe (?->)

Consente di leggere le proprietà e richiamare i metodi in catena. Se uno degli elementi restituisce null, l'intera catena restituisce null senza lanciare un errore fatale.

```php
// PHP 7.4
// app/Services/SessionService.php
$country = null;
if ($session !== null) {
    $user = $session->user;
    if ($user !== null) {
        $country = $user->getAddress()->country;
    }
}

// PHP 8.0
// app/Services/SessionService.php
$country = $session?->user?->getAddress()?->country;
```

---

<a id="constructor-promotion"></a>
## Constructor Property Promotion

In precedenza, la creazione di semplici DTO (Data Transfer Objects) o Value Objects richiedeva la scrittura di molto codice boilerplate: dichiarazione delle proprietà, passaggio delle stesse al costruttore e loro assegnazione. PHP 8.0 unisce questi tre passaggi in uno solo.

```php
// PHP 7.4: Approccio classico (e logorroico)
// app/DTO/UserDTO.php
class UserDTO 
{
    public string $name;
    public string $email;
    protected int $age;

    public function __construct(string $name, string $email, int $age) 
    {
        $this->name = $name;
        $this->email = $email;
        $this->age = $age;
    }
}

// PHP 8.0: Elegante e conciso
// app/DTO/UserDTO.php
class UserDTO 
{
    public function __construct(
        public string $name,
        public string $email,
        protected int $age,
    ) {}
}
```

---

<a id="type-system"></a>
## Evoluzione del sistema dei tipi

In PHP 8.0 il sistema dei tipi è diventato notevolmente più rigoroso ed espressivo.

### Tipi Unione (Union Types)
Prima di PHP 8.0, se una variabile poteva accettare diversi tipi di dati (ad esempio, `int` o `float`), ci si affidava alle annotazioni PHPDoc. Ora PHP supporta questa funzionalità in modo nativo.

```php
// app/Services/CalculatorService.php
class Calculator 
{
    private int|float $number;

    public function setNumber(int|float $number): void 
    {
        $this->number = $number;
    }
}
```

### Il pseudo-tipo `mixed`

Il nuovo tipo `mixed` risolve problemi legati al codice legacy. Equivale a `array|bool|callable|int|float|null|object|resource|string`. Nota: `mixed` include già null, quindi scrivere `?mixed` o `mixed|null` non è consentito e genererà un errore fatale a livello di compilazione.

### Il tipo di ritorno `static`

Per implementare pattern come \"Late Static Binding\" e \"Fluent Interfaces\", è stato aggiunto il tipo di ritorno `static` (in precedenza era disponibile solo `self`).

```php
// app/Factories/BaseFactory.php
class BaseFactory {
    public function create(): static {
        return new static();
    }
}
```

### L'interfaccia `Stringable`

Se una classe implementa il metodo magico `__toString()`, PHP 8.0 le assegna automaticamente (in modo implicito) l'interfaccia `Stringable`. Questo consente di utilizzare `string|Stringable` nelle definizioni dei tipi.

---

<a id="attributes"></a>
## Attributi / Annotazioni (Analisi approfondita)

Gli **attributi** (introdotti in PHP 8.0) sono **metadati strutturati** da associare a classi, metodi, proprietà, parametri e costanti. Il motore di PHP li memorizza nel bytecode; possono essere letti tramite la **Reflection**. Non sono **elementi magici**: non accadrà nulla a meno che il *tuo* framework, router o strumento non li ispezioni—lo stesso concetto delle annotazioni in Java/C#, ma nativo in PHP.

### Attributi vs PHPDoc

| | PHPDoc (`@route`, `@deprecated`) | Attributi (`#[Route]`) |
|---|----------------------------------|-------------------------|
| Parsing | Stringhe nei commenti; richiede parser personalizzati | Sintassi di prima classe; nessuna espressione regolare sui commenti |
| Tipizzazione | Informale; rischia di divergere dal codice reale | Gli argomenti del costruttore sono valori PHP reali |
| Strumenti | Supporto IDE variabile | L'API Reflection è stabile e veloce |

Utilizza PHPDoc per la **documentazione umana**; utilizza gli attributi per il **comportamento che il tuo codice dovrà effettivamente interpretare** (routing, regole di validazione, serializzazione, generazione di codice).

### Dichiarazione di una classe attributo

Qualsiasi classe può essere utilizzata come attributo se contrassegnata con l'attributo nativo `#[\Attribute]`. Una maschera di bit opzionale limita **dove** può essere applicato (`Attribute::TARGET_*`). Se si omettono le destinazioni, l'attributo sarà applicabile a **tutti** gli elementi.

```php
// app/Attributes/Route.php
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
final class Route
{
    public function __construct(
        public string $path,
        public array $methods = ['GET'],
    ) {}
}
```

* **`final`** è ampiamente utilizzato affinché la classe dell'attributo non venga inavvertitamente ereditata.
* I parametri del costruttore diventano gli **argomenti** passati al momento dell'utilizzo (`#[Route('/x', methods: [...])]`).

È possibile contrassegnare un attributo come **ripetibile** sullo stesso elemento (es. per definire più validatori) includendo `Attribute::IS_REPEATABLE` nella maschera di bit.

### Applicazione degli attributi (sintassi)

Gli attributi si posizionano **prima** della dichiarazione, singolarmente, su più righe o raggruppati:

```php
// app/Http/Controllers/UserController.php
#[Route('/api/users', methods: ['GET', 'POST'])]
final class UserController {}

// app/Http/Controllers/ItemController.php
#[Route('/items')]
final class ItemController
{
    #[Route('/items/{id}', methods: ['GET'])]
    public function show(int $id): array
    {
        return ['id' => $id];
    }
}
```

Gli argomenti con nome (PHP 8.0) si leggono in modo naturale: `methods: ['GET']` viene mappato direttamente al parametro del costruttore.

### Come funziona a runtime

1. PHP **analizza** gli attributi a tempo di compilazione e li associa alla struttura di reflection.
2. A runtime, ottieni un'istanza di `ReflectionClass`, `ReflectionMethod`, `ReflectionProperty`, ecc.
3. Chiama **`getAttributes()`** per ottenere le istanze di `ReflectionAttribute`, e successivamente **`newInstance()`** per istanziare la classe dell'attributo con gli argomenti specificati nel codice sorgente.

Nulla viene eseguito \"da solo\": il codice di bootstrap, il container DI o il router devono interrogare l'API Reflection.

### Lettura degli attributi con la Reflection

```php
// app/Services/RouterService.php
$reflection = new ReflectionClass(UserController::class);

// Solo attributi di una specifica classe (scelta raccomandata)
foreach ($reflection->getAttributes(Route::class) as $attr) {
    /** @var Route $route */
    $route = $attr->newInstance();
    // $route->path, $route->methods
}

// Tutti gli attributi della classe (richiede filtraggio manuale)
foreach ($reflection->getAttributes() as $attr) {
    $name = $attr->getName();       // es: Route::class
    $args = $attr->getArguments(); // argomenti grezzi del costruttore
}
```

Utilizza **`ReflectionMethod::getAttributes()`** per rotte o middleware a livello di metodo, **`ReflectionParameter::getAttributes()`** per attributi di validazione dei parametri, ecc.

---

<a id="saner-comparisons"></a>
## Confronti più coerenti tra stringhe e numeri

Si tratta di una delle modifiche non retrocompatibili più insidiose. In precedenza, eseguendo un confronto non rigido tra un numero e una stringa, PHP convertiva la stringa in un numero. In PHP 8.0, se la stringa non è numerica, i numeri vengono confrontati come stringhe.

```php
// app/Services/ComparisonService.php
// PHP 7.4
0 == 'foobar'; // true

// PHP 8.0
0 == 'foobar'; // false
```

---

<a id="syntax-tweaks"></a>
## Aggiustamenti sintattici

### Utilizzo di `::class` sugli oggetti

Ora puoi ottenere il nome della classe direttamente da una variabile oggetto tramite il costrutto `::class`. In precedenza per questo scopo era necessario utilizzare la funzione `get_class()`.

```php
// app/Services/ReflectionService.php
$object = new \App\Models\User();
// PHP 7: get_class($object);
echo $object::class; // Stampa \"App\\Models\\User\"
```

### Virgole finali

È consentito inserire una virgola finale negli elenchi dei parametri di funzioni, metodi e closure. Questo rende le differenze dei commit Git più pulite.

```php
// app/Services/RequestService.php
public function makeRequest(
    string $url,
    array $data,
    array $headers, // <-- la virgola finale è ora valida
) { ... }
```

---

<a id="string-functions"></a>
## Nuove funzioni di stringa

Invece di utilizzare `strpos()` ed eseguire il controllo `!== false`, sono state aggiunte tre nuove funzioni che restituiscono un valore `bool` stretto:

```php
// app/Services/StringService.php
$str = "DevSense è fantastico";

str_starts_with($str, "DevSense"); // true
str_contains($str, "fantastico");  // true
str_ends_with($str, "fantastico"); // true
```

### La funzione `get_debug_type()`

La nuova funzione `get_debug_type()` restituisce il tipo di una variabile in modo descrittivo (es. `App\Models\User` invece di semplicemente `object`, oppure `int` invece di `integer`). È ideale per formulare messaggi di errore chiari.

---

<a id="weak-maps"></a>
## Weak Map

Una svolta architetturale importante per gli `ORM` e i sistemi di `caching`. Le `WeakMap` consentono di creare associazioni agli oggetti in un modo che **non impedisce** al Garbage Collector di rimuovere tali oggetti dalla memoria.

```php
// app/Services/CacheService.php
class Cache {
    private WeakMap $cache;
    
    public function __construct() {
        $this->cache = new WeakMap();
    }
    
    public function getMetadata(object $obj): array {
        if (!isset($this->cache[$obj])) {
            $this->cache[$obj] = $this->computeExpensiveData($obj);
        }
        return $this->cache[$obj];
    }
}
```

Non appena l'oggetto `$obj` viene distrutto altrove nell'applicazione, esso scompare automaticamente anche dalla WeakMap, liberando immediatamente la memoria.

---

<a id="throw-and-errors"></a>
## Espressione Throw e gestione degli errori

L'operatore throw è passato dall'essere un'istruzione (statement) ad essere un'espressione (expression).

```php
// app/Services/UserService.php
// Ora puoi lanciare eccezioni direttamente all'interno degli operatori ternari o con l'assegnazione null coalescing
$user = $request->get('user') ?? throw new InvalidArgumentException('Utente richiesto');

$callable = fn() => throw new Exception('Questo codice non dovrebbe essere eseguito');
```

Modifica globale della severità: in PHP 8.0, l'operatore di soppressione degli errori `@` non maschera più gli errori fatali.
Inoltre, la maggior parte dei Warning del motore è stata convertita in eccezioni di tipo `Error` (ad esempio, il tentativo di accedere a una proprietà di una variabile non oggetto ora interrompe lo script anziché limitarsi a registrare un Warning).

### Blocchi catch non catturanti (Non-capturing catches)

Se devi intercettare un'eccezione ma non hai bisogno dell'oggetto eccezione stesso, la variabile può ora essere omessa.

```php
// app/Services/ErrorService.php
// Prima: eravamo obbligati a dichiarare la variabile $e
try {
    // codice
} catch (Exception $e) {
    Log::error('Si è verificato un errore');
}

// PHP 8.0:
try {
    // codice
} catch (Exception) {
    Log::error('Si è verificato un errore');
}
```

### Errori di tipo per le funzioni interne

La maggior parte delle funzioni interne di PHP ora lancia eccezioni rigorose di tipo `TypeError` o `ValueError` quando vengono passati parametri non validi, anziché emettere un Warning e restituire null.

```php
// app/Services/DebugService.php
// PHP 7.4
strlen([]); // Warning: strlen() expects parameter 1 to be string, array given

// PHP 8.0
strlen([]); // TypeError: strlen(): Argument #1 ($str) must be of type string, array given
array_chunk([], -1); // ValueError: array_chunk(): Argument #2 ($length) must be greater than 0
```

---

<a id="jit-performance"></a>
## Compilatore JIT e prestazioni

La modifica architetturale più profonda sotto il cofano di PHP 8.0 è l'introduzione del **compilatore JIT (Just-In-Time)**.

**OPcache** (Prima di PHP 8): il codice sorgente veniva analizzato in OpCode e la macchina virtuale Zend li eseguiva riga per riga.

**JIT (PHP 8.0+)**: analizza gli OpCode e compila i percorsi di esecuzione frequenti (\"hot paths\") direttamente in codice macchina per la CPU (x86/ARM).

Per le tipiche applicazioni web limitate da operazioni I/O (I/O-bound), il guadagno prestazionale si attesta sull'1-5%. Ma per le computazioni pure (CPU Bound) l'incremento varia dal **300% al 500%**.

> [!NOTE]
> **Lo sapevi?**
> Il compilatore JIT in PHP 8.0 viene eseguito all'interno di OPcache. Se abiliti `opcache.jit_buffer_size`, ma dimentichi di impostare `opcache.enable` o `opcache.enable_cli`, il compilatore JIT rimarrà completamente disabilitato senza mostrare alcun avviso!

---

<a id="modules-changes"></a>
## Modifiche ai moduli e al core

Continua la rimozione dei tipi di risorsa opachi a favore dell'uso degli oggetti:
* **cURL**: `curl_init()` restituisce un'istanza della classe `CurlHandle`.
* **GD**: `imagecreate()` restituisce un'istanza di `GdImage`.
* **Sockets**: `socket_create()` restituisce un'istanza di `Socket`.

Gestione della memoria: i nuovi oggetti vengono distrutti **automaticamente** dal Garbage Collector. Funzioni come `curl_close()` non hanno più alcuna utilità pratica.

Altre modifiche alle estensioni:
* **JSON** è ora stabilmente integrato nel core (non può essere disattivato con il flag `--disable-json`).
* **XML-RPC** è stato rimosso dal core e spostato in **PECL**.
* Aggiunta la funzione matematica **`fdiv()`**, che consente la divisione per zero (restituendo `INF`, `-INF` o `NAN` anziché lanciare un errore).

---

<a id="backward-incompatible"></a>
## Modifiche non retrocompatibili (note di migrazione)

Anche se non utilizzi la nuova sintassi, il passaggio a PHP 8.0 può causare malfunzionamenti a causa di comportamenti a runtime più rigidi e della rimozione di funzionalità legacy. Di seguito una sintesi delle casistiche più comuni da verificare in fase di testing.

### Linguaggio / parole chiave / rimozioni

* `match` è ora una **parola chiave riservata**.
* `mixed` è ora una **parola riservata** (non può essere utilizzata come nome per classi/interfacce/trait ed è vietata nei namespace).
* `__autoload()` è stata rimossa. Usa al suo posto `spl_autoload_register()`.
* `create_function()` è stata rimossa. Usa funzioni anonime / closure.
* `each()` è stata rimossa. Usa `foreach` o `ArrayIterator`.
* La definizione di costanti non sensibili al maiuscolo/minuscolo è stata rimossa (`define('FOO', 'bar', true)` non è più supportato).
* I metodi con lo stesso nome della classe non vengono più trattati come costruttori (usa `__construct()`).
* Non è più consentito richiamare metodi non statici in modo statico.
* I cast `(real)` e `(unset)` sono stati rimossi.

### Gestione degli errori e diagnostica (runtime più rigoroso)

* I fallimenti delle asserzioni (assert) ora lanciano eccezioni per impostazione predefinita.
* La direttiva INI `track_errors` è stata rimossa (pertanto `$php_errormsg` non è più disponibile; utilizza al suo posto `error_get_last()`).
* L'operatore `@` non sopprime più gli errori fatali.
* Il livello di notifica degli errori predefinito è impostato su `E_ALL`.
* Molti warning sono diventati eccezioni di tipo `Error` (ad esempio: scrittura su una proprietà di una variabile non oggetto, tipi di chiavi di array o offset di stringa non validi, disimballaggio di elementi non array/non Traversable).
* Molti notice sono diventati warning (variabili/proprietà/chiavi di array non definite, conversione da array a stringa, ecc.).

### Stringhe numeriche e coercizione di tipo

* I confronti non rigidi tra numeri e stringhe non numeriche hanno cambiato comportamento (i numeri vengono confrontati come stringhe).
* Le operazioni aritmetiche/bitwise su stringhe non numeriche ora lanciano `TypeError`.
* Il cast da float a stringa è ora indipendente dalla localizzazione del sistema (locale-independent).

---

<a id="common-mistakes"></a>
## ⚠️ Errori comuni

Ecco alcuni errori tipici durante l'utilizzo delle funzionalità di PHP 8.0:

### 1. Espressione Match senza Default
Un'espressione `match` deve essere esaustiva. Se nessuna delle condizioni corrisponde e non è definito un ramo `default`, PHP lancerà un'eccezione `UnhandledMatchError`.

```php
// app/Services/PaymentService.php
// ERRATO: si verificherà un crash se $status è uguale a 'failed'
$message = match ($status) {
    'pending' => 'In attesa di pagamento',
    'completed' => 'Pagamento completato',
};

// CORRETTO: gestisci sempre un'opzione di fallback
$message = match ($status) {
    'pending' => 'In attesa di pagamento',
    'completed' => 'Pagamento completato',
    default => 'Pagamento fallito o annullato',
};
```

### 2. Effetti collaterali con l'operatore Nullsafe
L'operatore nullsafe interrompe l'esecuzione dell'intera catena se uno qualsiasi degli elementi restituisce `null`. Tuttavia, se tenti di effettuare un'assegnazione all'interno di una catena nullsafe o richiami un metodo con effetti collaterali, questo potrebbe non essere eseguito. Inoltre, l'operatore nullsafe non può essere utilizzato sul lato sinistro di un'assegnazione.

```php
// app/Services/UserService.php
// ERRATO: Errore di sintassi - non è possibile scrivere su una catena nullsafe
$session?->user?->name = 'John'; 

// ERRATO: il metodo con effetti collaterali potrebbe non essere richiamato se $logger è null
$logger?->log('Action occurred')?->sendNotification();
```

### 3. Posizione degli argomenti con nome
Sebbene sia possibile combinare argomenti posizionali e con nome, gli argomenti con nome devono sempre essere posizionati **dopo** quelli posizionali. L'inserimento in ordine errato causa un errore a livello di compilazione.

```php
// app/Services/NotificationService.php
// ERRATO: Argomento con nome inserito prima di un argomento posizionale (Errore di compilazione)
sendEmail(subject: 'Hello', $userEmail);

// CORRETTO: Argomenti con nome posizionati alla fine
sendEmail($userEmail, subject: 'Hello');
```

---

<a id="self-test-quiz"></a>
## Quiz di autovalutazione

Metti alla prova la tua comprensione delle novità di PHP 8.0.

### Domanda 1: Qual è l'output del seguente codice?
```php
// app/Http/Controllers/TestController.php
$result = 0 == 'hello';
var_dump($result);
```
* A) `bool(true)`
* B) `bool(false)`
* C) `TypeError`

<details>
<summary>Clicca per vedere la risposta</summary>

**Risposta: B**  
In PHP 8.0, il confronto non rigido (`==`) tra un numero e una stringa non numerica esegue il confronto trattando entrambi gli elementi come stringhe. Pertanto, `0 == 'hello'` viene valutato come `'0' == 'hello'`, restituendo `false`. In PHP 7.4 avrebbe restituito `true`.
</details>

### Domanda 2: Quale eccezione viene lanciata se un'espressione `match` non ha corrispondenze e non presenta un ramo `default`?
* A) `RuntimeException`
* B) `ValueError`
* C) `UnhandledMatchError`

<details>
<summary>Clicca per vedere la risposta</summary>

**Risposta: C**  
PHP 8.0 genera un'eccezione di tipo `UnhandledMatchError` se nessun ramo dell'espressione match corrisponde alla variabile valutata e non è stato definito alcun ramo `default`.
</details>

---

## Riassunto (Considerazioni finali)

Considera PHP 8.0 come un **ripristino della piattaforma**: meno sorprese dai confronti non rigidi, errori più chiari dalle API interne e un sistema di tipi che finalmente rispecchia il modo in cui vengono scritte le moderne basi di codice PHP. Il vantaggio risiede in un numero ridotto di bug silenziosi in produzione e in una migrazione più agevole verso PHP 8.1+.