---
title: 'PHP 7.3 from 7.2: Flexible Heredoc, JSON Exceptions, PCRE2 & Migration | DevSense'
description: "Guida all'aggiornamento di PHP 7.3: sintassi heredoc/nowdoc flessibile, virgola finale nelle chiamate, destrutturazione di referenze, is_countable, array_key_first/last, JsonException, Argon2id, PCRE2 e modifiche non retrocompatibili."
faq:
    - { question: "Cos'è la sintassi flessibile heredoc/nowdoc in PHP 7.3?", answer: "PHP 7.3 consente di indentare l'etichetta di chiusura di un heredoc o nowdoc. L'indentazione dell'etichetta di chiusura definisce la quantità di spazi di indentazione rimossi da tutte le righe all'interno del corpo del testo." }
    - { question: 'Come funziona JsonException in PHP 7.3?', answer: "Passando l'opzione 'JSON_THROW_ON_ERROR' alle funzioni 'json_encode()' o 'json_decode()', PHP genererà un'eccezione 'JsonException' in caso di errore, eliminando la necessità di controlli manuali con 'json_last_error()'." }
    - { question: "Cosa cambia per l'istruzione 'continue' in un blocco 'switch'?", answer: "L'uso di 'continue' all'interno di un'istruzione 'switch' ora genera un avviso (warning) perché si comporta esattamente come 'break'. Per continuare un ciclo esterno, occorre utilizzare 'continue 2'." }
    - { question: 'Quali funzioni di supporto sono state introdotte in PHP 7.3?', answer: "PHP 7.3 ha aggiunto 'is_countable()' per verificare se una variabile sia conteggiabile, oltre a 'array_key_first()' e 'array_key_last()' per recuperare la prima e l'ultima chiave di un array." }
published: '2026-05-31'
---
# PHP 7.3: Funzionalità principali

Hai mai perso ore a eseguire il debug di un errore silenzioso di parsing JSON in produzione perché avevi dimenticato di controllare `json_last_error()`? PHP 7.3 risolve questo problema di Developer Experience (DX) introducendo `JsonException` tramite l'opzione `JSON_THROW_ON_ERROR`. Questa versione rappresenta una pietra miliare in termini di sicurezza e praticità, migliorando l'ergonomia della sintassi con gli heredoc indentati, le virgole finali nelle chiamate di funzione e aggiungendo utili helper alla libreria standard.

## Indice
* [Heredoc e Nowdoc flessibili](#flexible-heredoc)
* [Virgola finale nelle chiamate a funzioni e metodi](#trailing-commas-calls)
* [Assegnazioni di referenze in `list()` e `[]`](#list-references)
* [`instanceof` con i letterali](#instanceof-literals)
* [`CompileError`](#compile-error)
* [Helper di sistema nuovi e aggiornati](#core-helpers)
* [JSON: `JSON_THROW_ON_ERROR` e `JsonException`](#json-exceptions)
* [Hashing delle password: Argon2id](#argon2id)
* [Estensioni importanti e stdlib](#extensions-stdlib)
* [Ricette pratiche](#practical-recipes)
* [Errori comuni](#common-mistakes)
* [Limitazioni](#limitations)
* [Modifiche non retrocompatibili (note di migrazione)](#backward-incompatible)
* [Funzionalità deprecate (da correggere presto)](#deprecations)
* [Altre modifiche e operazioni (build, INI, prestazioni)](#other-changes)
* [Quiz interattivo](#interactive-quiz)
* [Considerazioni finali](#closing-thoughts)

---

<a id="flexible-heredoc"></a>
## Heredoc e Nowdoc flessibili

L'etichetta di chiusura **non deve più** necessariamente trovarsi nella colonna 0: può essere **indentata**, e la stessa quantità di spazi viene **rimossa da ogni riga** all'interno del corpo del testo. Ciò rende SQL, HTML e testi di aiuto CLI incorporati molto più leggibili e conformi allo standard PSR-12.

**Attenzione in fase di migrazione:** se il corpo del testo **contiene lo stesso token** dell'etichetta di chiusura (che ora può essere indentata), PHP potrebbe interpretarlo come una **chiusura anticipata della stringa**. Utilizza **etichette lunghe e univoche** (es. `SQL_GET_USER` invece di `SQL`).

```php
// src/QueryBuilder.php
$query = <<<SQL
    SELECT id, name
    FROM users
    WHERE active = 1
    SQL;
```

> [!NOTE]
> Lo sapevi? L'indentazione dell'etichetta di chiusura determina la quantità di spazi rimossi dal testo. Se indenti il corpo *meno* dell'etichetta di chiusura, PHP genererà un ParseError.

---

<a id="trailing-commas-calls"></a>
## Virgola finale nelle chiamate a funzioni e metodi

Le chiamate possono terminare con una virgola finale: comodo per i diff multiriga e per gli elenchi di argomenti generati:

```php
// src/LoggerService.php
$this->logger->info(
    'User saved',
    [
        'id' => $user->id,
        'ip' => $request->ip(),
    ],
);
```

Questo si applica alle **chiamate** (invocazioni), non alla dichiarazione dei parametri `function foo($a,)` in PHP 7.3 (le virgole finali negli elenchi dei parametri delle funzioni sono state introdotte in PHP 8.0).

> [!NOTE]
> Lo sapevi? Le virgole finali nelle *dichiarazioni* di funzione (definizione dei parametri) sono ancora un errore di sintassi in PHP 7.3. Sono supportate solo nelle *chiamate*.

---

<a id="list-references"></a>
## Assegnazioni di referenze in `list()` e `[]`

La destrutturazione può associare variabili **per riferimento**:

```php
// src/Destructure.php
[&$head, $middle, &$tail] = $parts;
// stesso concetto con list():
list(&$a, $b) = $pair;
```

Utilizza questa sintassi solo se desideri modificare intenzionalmente parti di una struttura condivisa; in caso contrario, preferisci il passaggio per valore per mantenere chiaro il flusso dei dati.

---

<a id="instanceof-literals"></a>
## `instanceof` con i letterali

La parte sinistra può essere un **valore letterale**; il risultato è sempre **`false`**. Questa possibilità esiste principalmente per motivi di **coerenza** e per facilitare l'analisi statica del codice, non per logiche a runtime.

```php
// src/Validation.php
$result = (123 instanceof User); // false
```

---

<a id="compile-error"></a>
## `CompileError`

La classe `CompileError` viene introdotta come base per determinati **errori a tempo di compilazione**; `ParseError` **estende** questa classe. Inizialmente questo si manifesta in modo evidente quando **`token_get_all($code, TOKEN_PARSE)`** riscontra problemi di analisi: alcune situazioni che in precedenza erano errori fatali ora possono essere catturate come eccezioni dagli strumenti di analisi.

```php
// src/ErrorHandling.php
try {
    eval('invalid code');
} catch (CompileError $e) {
    echo "Compilazione fallita: " . $e->getMessage();
}
```

---

<a id="core-helpers"></a>
## Helper di sistema nuovi e aggiornati

* **`array_key_first($array)`** / **`array_key_last($array)`** — evita trucchi con `reset()`/`end()` per ottenere le chiavi; il comportamento è predefinito per il tipo di array (vedi il manuale per gli array vuoti).
* **`is_countable($value)`** — `true` per array e oggetti che implementano `Countable` — sostituisce il comune controllo `is_array($x) || $x instanceof \Countable` eseguito prima di `count()`.
* **`hrtime($as_number = false)`** — tempo monotono ad alta risoluzione (in nanosecondi); preferibile a `microtime(true)` per misurare **intervalli** (non l'ora solare di sistema).
* **`net_get_interfaces()`** — elenca le interfacce di rete dove supportato (dipendente dalla piattaforma).

```php
// src/Helpers.php
$firstKey = array_key_first($myArray);
if (is_countable($data)) {
    $count = count($data);
}
```

> [!NOTE]
> Lo sapevi? `hrtime()` utilizza l'orologio monotono del sistema, che è immune ai cambiamenti dell'ora di sistema (come le sincronizzazioni NTP). Questo lo rende l'unico metodo affidabile per misurare gli intervalli di tempo di esecuzione.

---

<a id="json-exceptions"></a>
## JSON: `JSON_THROW_ON_ERROR` e `JsonException`

Passa l'opzione **`JSON_THROW_ON_ERROR`** alle funzioni **`json_encode()`** / **`json_decode()`** per generare un'eccezione **`JsonException`** anziché gestire **`json_last_error()`**. L'opzione **`JSON_PARTIAL_OUTPUT_ON_ERROR`** ha comunque la precedenza se applicate entrambe.

```php
// src/JsonParser.php
try {
    $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    // Gestisci l'errore
}
```

---

<a id="argon2id"></a>
## Hashing delle password: Argon2id

Quando PHP viene compilato con una versione sufficientemente recente di **libargon2**, la funzione **`password_hash()`** accetta l'algoritmo **`PASSWORD_ARGON2ID`**, offrendo la variante **ibrida i+d** di Argon2 oltre al supporto ad Argon2i.

```php
// src/Security.php
$hash = password_hash('secret', PASSWORD_ARGON2ID);
```

---

<a id="extensions-stdlib"></a>
## Estensioni importanti e stdlib

* **PCRE**: motore aggiornato a **PCRE2** — lievi modifiche nel comportamento (controlli più severi sugli intervalli delle classi di caratteri, ecc.); la funzione **`preg_quote()`** ora inserisce l'escape anche per il carattere **`#`**.
* **Multibyte (mbstring)**: supporto a **Unicode 11**, stringhe **>2GB**, operazioni sui caratteri maiuscoli/minuscoli più veloci; **case-folding completo** per i confronti case-insensitive; le catture con nome di **`mb_ereg_*`** sono allineate al comportamento di PCRE.
* **LDAP**: i **controlli** LDAP sono integrati nelle API di ricerca/modifica e in **`ldap_parse_result()`**; migliorata la gestione delle opzioni per i controlli server/client.
* **MySQLi / PDO MySQL**: le query preparate possono restituire **frazioni di secondo** per le colonne di tipo `DATETIME(6)` / `TIMESTAMP(6)`.
* **FPM**: impostazioni di logging (`log_limit`, `log_buffering`, `decorate_workers_output`); la funzione **`getallheaders()`** è disponibile in FPM.
* **Sessioni / cookie**: funzioni **`session_set_cookie_params(array $options)`** e **`session.cookie_samesite`**; le funzioni **`setcookie()` / `setrawcookie()`** accettano un array `$options` che include **`samesite`**.
* **Stream**: i nomi IPv6 restituiti da **`stream_socket_get_name()`** utilizzano il formato host **tra parentesi quadre** (es. `[::1]:1337`).
* **Autoload SPL**: se un autoloader **genera un'eccezione**, gli **autoloader successivi vengono saltati**.
* **IMAP**: gli accessi via **rsh/ssh** sono **disabilitati per impostazione predefinita** — abilitali con cautela (`imap.enable_insecure_rsh`).

---

<a id="practical-recipes"></a>
## Ricette pratiche

### Controllo preliminare per `count()`

```php
// src/recipes.php
if (is_countable($rows)) {
    $n = count($rows);
}
```

### Recupero stabile della prima/ultima chiave

```php
// src/recipes.php
$firstKey = array_key_first($map);
$lastKey = array_key_last($map);
```

### Parsing JSON rigoroso

```php
// src/recipes.php
try {
    $payload = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    // gestisci o incapsula
}
```

### Misurazione del tempo ad alta risoluzione

```php
// src/recipes.php
$t0 = hrtime(true);
// ...
$elapsedNs = hrtime(true) - $t0;
```

---

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

Ecco alcuni errori tipici commessi dagli sviluppatori in PHP 7.3:

### 1. Indentazione non corretta dell'etichetta di chiusura Heredoc
Se il corpo del testo presenta righe con un'indentazione *inferiore* rispetto a quella dell'etichetta di chiusura, o se quest'ultima contiene spazi finali, viene generato un ParseError.
```php
// src/BadHeredoc.php
// Errato: il corpo è indentato meno dell'etichetta di chiusura, genera ParseError
$text = <<<TEXT
Line 1
    Line 2
      TEXT;
```
```php
// src/GoodHeredoc.php
// Corretto: l'indentazione dell'etichetta di chiusura corrisponde all'indentazione minima del corpo
$text = <<<TEXT
    Line 1
    Line 2
    TEXT;
```

### 2. Utilizzo di `continue` in un blocco `switch`
L'uso di `continue` all'interno di istruzioni switch si comporta come `break` in PHP, il che spesso genera cicli infiniti quando gli sviluppatori si aspettano che passi all'iterazione successiva del ciclo esterno. PHP 7.3 genera un avviso in questo caso.
```php
// src/BadContinueSwitch.php
// Errato: genera l'avviso: "continue" targeting "switch" is equivalent to "break"
foreach ($items as $item) {
    switch ($item) {
        case 'skip':
            continue;
    }
}
```
```php
// src/GoodContinueSwitch.php
// Corretto: usa "continue 2" per fare riferimento al ciclo foreach esterno
foreach ($items as $item) {
    switch ($item) {
        case 'skip':
            continue 2;
    }
}
```

---

<a id="limitations"></a>
## Limitazioni

* **Virgole finali**: supportate solo nelle chiamate a funzioni e metodi. Il tentativo di scrivere `function foo($a, $b,) {}` (con la virgola finale nella dichiarazione) genererà un ParseError di sintassi.
* **Heredoc flessibile**: l'etichetta di chiusura deve trovarsi su una riga a sé stante e non può contenere alcun testo dopo di essa (eccetto un punto e virgola o un a capo). Qualsiasi spazio vuoto finale dopo l'identificatore di chiusura causerà un errore del compilatore.

---

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

### Core

* **Heredoc/nowdoc flessibile**: le stringhe che **contengono l'etichetta di chiusura** possono cambiare significato o causare **errori di parsing** — rinomina le etichette o inserisci l'escape nei contenuti.
* **`continue` all'interno di `switch`**: ora genera un **avviso** (in precedenza in PHP si comportava come `break`). **Esamina l'uso di `switch` + `continue`.**
* **`ArrayAccess` con chiavi stringa numeriche**: per le chiavi letterali **`"123"`**, PHP **non effettua più la conversione automatica** in intero per `ArrayAccess` — viene chiamato **`offsetGet("123")`** invece di **`offsetGet(123)`**.
* **Proprietà statiche tramite assegnazione di referenza**: non è più consentito **separare** le proprietà statiche ereditate tramite l'assegnazione di referenze.
* **Referenze da accessi a proprietà/array**: le referenze restituite da letture concatenate di **proprietà/array** vengono **risolte immediatamente**.
* **Disimballaggio di `...$traversable`**: le **chiavi non intere** su oggetti `Traversable` **non vengono più disimballate** per le chiamate di funzione.
* **Avvisi elevati a eccezioni (`EH_THROW`)**: tali eccezioni **non popolano più** la funzione **`error_get_last()`**.
* **Messaggi `TypeError`**: i tipi errati vengono mostrati come **`int` / `bool`** invece di **`integer` / `boolean`**.
* **`compact()`**: il passaggio di nomi di **variabili non definite** genera ora un **Notice**.
* **`getimagesize()`** (e funzioni simili): il tipo MIME per i file BMP viene segnalato come **`image/bmp`** (IANA), anziché **`image/x-ms-bmp`**.
* **Cookie (da PHP 7.3.23)**: i **nomi** dei cookie in ingresso **non vengono decodificati dall'URL** (allineamento di sicurezza).

### BCMath

* Gli avvisi vengono instradati tramite il **gestore degli errori standard** di PHP.
* Le funzioni **`bcmul()` / `bcpow()`** rispettano la **scala richiesta** in modo più rigoroso.

### IMAP

* Il tunneling **rsh/ssh** è **disattivato** per impostazione predefinita, a meno che non venga abilitata esplicitamente l'opzione **`imap.enable_insecure_rsh`**.

### Regex Multibyte (`mb_ereg_*`)

* Le **catture con nome** modificano la **struttura del match array** e la sintassi di sostituzione in **`mb_ereg_replace()`**.

### MySQLi e PDO MySQL

* Le **frazioni di secondo** sono ora visibili nei valori dei risultati associati.

### Reflection

* Le esportazioni in stringa utilizzano le diciture di tipo **`int` / `bool`** nell'output.

### SimpleXML

* Le operazioni numeriche sui nodi di testo SimpleXML scelgono tra **int e float** anziché effettuare sempre la conversione forzata tramite **int**.

---

<a id="deprecations"></a>
## Funzionalità deprecate (da correggere presto)

Elementi critici del core:

* **`define()` case-insensitive** (passando `true` come terzo argomento) e l'utilizzo di una **differente combinazione di maiuscole/minuscole** rispetto alla definizione.
* **Funzioni all'interno di namespace denominate `assert()`** — da evitare; il motore riserva a **`assert()`** un trattamento speciale.
* **Needle non stringa** nella **famiglia di funzioni `strpos`** — esegui il cast esplicito.
* Le funzioni **`fgetss()`**, **`gzgetss()`**, **`SplFileObject::fgetss()`** e il filtro **`string.strip_tags`**.
* Opzioni **`FILTER_FLAG_SCHEME_REQUIRED` / `FILTER_FLAG_HOST_REQUIRED`** con **`FILTER_VALIDATE_URL`** (ridondanti).
* La funzione **`image2wbmp()`** (GD).
* L'opzione **`Normalizer::NONE`** con ICU ≥ 56.
* **Alias `mbereg_*()`** non documentati — passa a **`mb_ereg_*()`**.
* Deprecazione della direttiva INI **`pdo_odbc.db2_instance_name`**.

---

<a id="interactive-quiz"></a>
## Quiz interattivo

Metti alla prova la tua conoscenza di PHP 7.3:

1. **Quale affermazione è vera riguardo alle virgole finali in PHP 7.3?**
   * A) Sono consentite nelle chiamate a funzioni ma non nelle dichiarazioni di funzioni.
   * B) Sono consentite nelle dichiarazioni di funzioni ma non nelle chiamate a funzioni.
   * C) Sono consentite sia nelle dichiarazioni sia nelle chiamate.
   * D) Sono ancora errori di sintassi in ogni contesto.

   <details>
   <summary>Clicca per vedere la risposta</summary>
   
   **Risposta corretta: A**  
   PHP 7.3 consente la virgola finale nelle chiamate di funzione/metodo (invocazioni), ma dichiarare una funzione con una virgola finale nella lista dei parametri rimane un ParseError di sintassi.
   </details>

2. **Cosa fa PHP 7.3 quando incontra un `continue` all'interno di un blocco `switch`?**
   * A) Si comporta silenziosamente come un `continue 2` sul ciclo genitore.
   * B) Genera un ParseError fatale.
   * C) Emette un avviso (warning) che segnala che 'continue' all'interno di 'switch' equivale a 'break'.
   * D) Continua l'esecuzione normalmente senza alcun avviso.

   <details>
   <summary>Clicca per vedere la risposta</summary>
   
   **Risposta corretta: C**  
   PHP 7.3 genera un avviso (warning) in questo caso perché `continue` all'interno di `switch` non salta le iterazioni di un ciclo esterno, ma si comporta come `break`.
   </details>

3. **Quale funzione è stata introdotta in PHP 7.3 per verificare se una variabile può essere passata a `count()`?**
   * A) `is_iterable()`
   * B) `is_countable()`
   * C) `can_count()`
   * D) `is_array_or_countable()`

   <details>
   <summary>Clicca per vedere la risposta</summary>
   
   **Risposta corretta: B**  
   La funzione `is_countable()` restituisce `true` se la variabile è un array o un'istanza di una classe che implementa `Countable`.
   </details>

---

<a id="closing-thoughts"></a>
## Considerazioni finali

PHP 7.3 premia una **revisione mirata del codice**: controlla la presenza di **`continue` + `switch`**, l'uso di **`compact(`**, le implementazioni di **`ArrayAccess`**, le etichette **heredoc** e il **disimballaggio degli argomenti `...$generator`**. Esegui nuovamente i test di integrazione per **regex** e **date/ore**, quindi procedi: **7.4** aggiungerà funzionalità del linguaggio molto più importanti, quindi correggere le deprecazioni di PHP 7.3 ridurrà i warning al prossimo aggiornamento.