---
title: 'PHP 7.4 from 7.3: Typed Properties, Arrow Functions, FFI & Migration | DevSense'
description: "Guida all'aggiornamento di PHP 7.4: proprietà tipizzate, funzioni freccia (arrow functions), varianza dei tipi, ??=, spread nei costrutti array, WeakReference, __serialize/__unserialize, precaricamento OPcache, FFI e modifiche BC."
faq:
    - { question: 'Cosa sono le proprietà tipizzate in PHP 7.4?', answer: "PHP 7.4 consente di dichiarare il tipo per le proprietà di una classe. L'accesso a una proprietà tipizzata non inizializzata prima dell'assegnazione di un valore genera un TypeError." }
    - { question: 'Come funzionano le funzioni freccia (arrow functions) in PHP 7.4?', answer: "Le funzioni freccia utilizzano la parola chiave 'fn' e catturano automaticamente le variabili dall'ambito genitore per valore. Sono limitate a una singola espressione che viene restituita implicitamente." }
    - { question: "Cos'è il precaricamento di OPcache?", answer: "Il precaricamento consente di caricare i file PHP in memoria all'avvio del server, rendendoli permanentemente disponibili per tutte le richieste senza sovraccarico di analisi (parsing), ma richiede il riavvio del server per l'aggiornamento dei file." }
    - { question: 'Qual è il nuovo meccanismo di serializzazione personalizzato in PHP 7.4?', answer: "PHP 7.4 introduce i metodi magici '__serialize' e '__unserialize', che sostituiscono la vecchia interfaccia 'Serializable' e offrono un modo più robusto per personalizzare la serializzazione." }
published: '2026-05-31'
---
# PHP 7.4: Funzionalità principali

Immagina di aggiornare la tua versione di PHP solo per vedere la tua applicazione in produzione andare in crash perché una proprietà di classe non è stata inizializzata. PHP 7.4 introduce la tanto attesa sicurezza dei tipi per le proprietà di classe, ma questo potere comporta il requisito rigoroso di inizializzarle prima dell'accesso. Rappresenta il ponte definitivo verso il moderno PHP 8, introducendo proprietà tipizzate e funzioni freccia che richiedono disciplina da parte dello sviluppatore.

## Indice
* [Proprietà tipizzate](#typed-properties)
* [Funzioni freccia (Arrow functions)](#arrow-functions)
* [Covarianza e contravarianza](#variance)
* [Assegnazione null coalescing (`??=`)](#null-coalesce-assign)
* [Operatore spread negli array](#array-spread)
* [Separatore nei letterali numerici](#numeric-separator)
* [Riferimenti deboli (Weak references)](#weak-references)
* [`__toString()` può lanciare eccezioni](#tostring-exceptions)
* [Serializzazione: `__serialize` / `__unserialize`](#custom-serialize)
* [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="typed-properties"></a>
## Proprietà tipizzate

Le proprietà delle classi possono dichiarare i tipi. Le proprietà tipizzate non inizializzate **non devono essere lette** prima dell'assegnazione: in caso contrario viene generato l'errore **`Typed property ... must not be accessed before initialization`**.

```php
// src/User.php
final class User
{
    public int $id;
    public string $name;
    public ?string $nickname = null;
}
```

Note tratte da codice reale:

* Utilizza **`?Tipo`** o un valore predefinito se l'assenza di valore è uno stato valido.
* Il tipo **`callable`** **non** è consentito come tipo di proprietà (dipendente dal contesto).
* Non è possibile inizializzare una proprietà con `new NomeClasse()` direttamente al momento della dichiarazione come si fa con i tipi scalari; le proprietà con tipo oggetto presentano dei vincoli.

> [!NOTE]
> Lo sapevi? In PHP 7.4, le proprietà tipizzate sono implementate a livello del motore con sicurezza di \"inizializzazione paresseuse\" (lazy initialization). Una proprietà esiste in uno stato \"non inizializzato\", che è distinto da `null`. Il controllo `isset($user->id)` restituirà `false` se non è stata assegnata, anche se la proprietà non è nullable.

---

<a id="arrow-functions"></a>
## Funzioni freccia (Arrow functions)

Le funzioni freccia (`fn`) catturano le variabili **per valore** dall'ambito circostante e restituiscono una singola espressione: ideali per callback brevi.

```php
// src/MathHelper.php
$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3]);
```

**`fn` è una parola chiave riservata**: non è possibile chiamare una funzione o una classe `fn` (i nomi di metodi/costanti rimangono consentiti).

> [!NOTE]
> Lo sapevi? A differenza delle arrow functions di JavaScript, le funzioni freccia di PHP catturano le variabili solo per valore. Non è possibile modificare una variabile dell'ambito esterno dall'interno di una funzione freccia.

---

<a id="variance"></a>
## Covarianza e contravarianza

Nell'ereditarietà, i tipi di ritorno possono essere **covarianti** e i tipi di parametro **contravarianti**, con alcuni limiti. La varianza completa funziona al meglio con l'**autoloading**; in un singolo file sono possibili solo riferimenti **non ciclici** perché le classi devono essere conosciute prima dell'uso.

```php
// src/Repository.php
interface Repository {
    public function get(int $id): object;
}

class UserRepository implements Repository {
    public function get(int $id): User { // Tipo di ritorno covariante
        return new User();
    }
}
```

---

<a id="null-coalesce-assign"></a>
## Assegnazione null coalescing (`??=`)

Assegna il valore solo se la variabile a sinistra non è impostata o è null:

```php
// src/Config.php
$config['debug'] ??= false;
```

---

<a id="array-spread"></a>
## Operatore spread negli array

Disimballa gli iterabili all'interno di letterali di array:

```php
// src/ArrayMerge.php
$base = [1, 2];
$all = [0, ...$base, 3]; // [0, 1, 2, 3]
```

Si integra perfettamente con `array_merge(...$arrays)` ora che `array_merge()` può essere chiamata **senza argomenti** (restituisce `[]`).

---

<a id="numeric-separator"></a>
## Separatore nei letterali numerici

I caratteri di sottolineatura (underscore) migliorano la leggibilità e non alterano il valore:

```php
// src/Constants.php
$million = 1_000_000;
$hex = 0xFF_FF_FF;
```

---

<a id="weak-references"></a>
## Riferimenti deboli (Weak references)

`WeakReference` consente di mantenere un riferimento che **non** impedisce la distruzione di un oggetto: utile per cache e grafi senza causare perdite di memoria (memory leak).

```php
// src/Cache.php
$obj = new stdClass();
$weakRef = WeakReference::create($obj);
```

---

<a id="tostring-exceptions"></a>
## `__toString()` può lanciare eccezioni

È consentito lanciare eccezioni dal metodo `__toString()` (in precedenza era un errore fatale). Alcuni errori fatali recuperabili precedenti sono stati convertiti in eccezioni di tipo **`Error`**: verifica i percorsi di cast in stringa nel tuo codice.

```php
// src/Stringy.php
class Stringy {
    public function __toString(): string {
        throw new Exception("Impossibile convertire in stringa");
    }
}
```

---

<a id="custom-serialize"></a>
## Serializzazione: `__serialize` / `__unserialize`

Nuovi hook sostituiscono i pattern ad hoc e rimpiazzano a lungo termine l'interfaccia `Serializable`:

```php
// src/Point.php
final class Point
{
    private int $x;
    private int $y;

    public function __serialize(): array
    {
        return ['x' => $this->x, 'y' => $this->y];
    }

    public function __unserialize(array $data): void
    {
        $this->x = $data['x'];
        $this->y = $data['y'];
    }
}
```

I tipi SPL come `ArrayObject` possono generare **nuovi** payload leggibili a partire da PHP 7.4+ ma non compatibili con versioni precedenti.

---

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

* **FFI**: consente di chiamare librerie C da PHP (molto potente; richiede sandboxing e controlli di sicurezza).
* **Precaricamento OPcache**: carica un set di file all'avvio per eliminare il costo di caricamento automatico (autoload)—richiede `opcache.preload` e solitamente `opcache.preload_user`.
* **`mb_str_split()`**: simile a `str_split()` ma opera sui **code point**.
* **`proc_open()`**: comando passato come **array** (evita l'uso della shell) e supporto a descrittori `redirect` / `null`.
* **`strip_tags()`**: tag consentiti specificabili come **array** di nomi.
* **PDO**: nome utente/password utilizzabili nel DSN per più driver; **`??`** in SQL esegue l'escape di un `?` letterale (es. per il tipo JSON di PostgreSQL `?`).
* **PCRE**: la funzione `preg_replace_callback*` accetta opzioni (flags) (`PREG_OFFSET_CAPTURE`, `PREG_UNMATCHED_AS_NULL`).
* **Password**: Argon2 via **sodium** se compilato senza libargon.

---

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

### Valori predefiniti sicuri con `??=`

```php
// src/recipes.php
$options['timeout'] ??= 30;
```

### Funzione freccia all'interno di un ordinamento

```php
// src/recipes.php
usort($rows, fn($a, $b) => $a['score'] <=> $b['score']);
```

### Unione tramite disimballaggio di liste dinamiche

```php
// src/recipes.php
$merged = array_merge(...$chunks);
```

---

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

Ecco alcuni problemi tipici che gli sviluppatori affrontano durante il passaggio a PHP 7.4:

### 1. Lettura di proprietà tipizzate non inizializzate
```php
// src/BadPropertyAccess.php
// Errato: la lettura della proprietà prima dell'assegnazione di un valore genera un errore fatale
class BadUser {
    public int $id;
}
$user = new BadUser();
echo $user->id; // Fatal Error: Typed property BadUser::$id must not be accessed before initialization
```
```php
// src/GoodPropertyAccess.php
// Corretto: fornisci un valore predefinito o esegui l'inizializzazione nel costruttore
class GoodUser {
    public int $id = 0; // valore predefinito
    // OPPURE:
    // public function __construct(int $id) { $this->id = $id; }
}
```

### 2. Modifica di variabili dell'ambito esterno nelle funzioni freccia
```php
// src/BadArrowScope.php
// Errato: pensare che le funzioni freccia catturino le variabili dell'ambito per riferimento
$count = 0;
$increment = fn() => $count++;
$increment();
echo $count; // Output: 0 (La variabile esterna rimane inalterata!)
```
```php
// src/GoodArrowScope.php
// Corretto: utilizza la funzione anonima tradizionale con il costrutto use e passaggio per riferimento
$count = 0;
$increment = function() use (&$count) {
    $count++;
};
$increment();
echo $count; // Output: 1
```

---

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

* **Funzioni freccia**: sono limitate a una singola espressione. Non è possibile inserire logica multiriga o istruzioni return esplicite all'interno di una funzione freccia.
* **Precaricamento OPcache**: i file precaricati rimangono permanentemente in memoria. Qualsiasi modifica al codice richiede il riavvio completo di PHP-FPM o del server web per essere applicata.
* **FFI**: offre prestazioni eccezionali ma bypassa i livelli di sicurezza di PHP. È altamente vulnerabile a corruzioni della memoria (segmentation fault) e non dovrebbe essere usata in ambienti di hosting condiviso non affidabili.

---

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

### Core

* **Accesso ad array su tipi non array**: l'uso di `null`, `bool`, `int`, `float` o `resource` come `$x['k']` genera un **Notice**.
* **`get_declared_classes()`**: non include più le classi **anonime** finché non vengono istanziate.
* **`fn`**: parola chiave riservata per i nomi di classi/funzioni.
* **`<?php` a fine file** senza a capo: ora viene analizzato come un **tag aperto** (in precedenza era ambiguo con `short_open_tag`).
* **Stream wrapper**: `include`/`require` sugli stream possono invocare `stream_set_option(STREAM_OPTION_READ_BUFFER)`—implementa questo metodo o restituisci `false` per evitare avvisi.
* **Serializzazione**: **rimosso il formato `o`** (rilevante solo per payload manipolati).
* **Costanti per le password**: gli identificatori `PASSWORD_*` sono **stringhe** (`'2y'`, `'argon2id'`, …), non interi—il codice che esegue confronti con `1`/`2`/`3` smetterà di funzionare.
* **`htmlentities()`**: genera un **Notice** quando la codifica ricade sul comportamento di `htmlspecialchars`.
* **`fread`/`fwrite`**: restituiscono **`false`** in caso di errore (anziché `''` o `0`); l'errore può emettere un **Notice**.
* **BCMath**: genera un warning in caso di stringhe numeriche non ben formate (vengono comunque trattate come zero).
* **CURL**: la serializzazione di **`CURLFile`** genera un'eccezione in anticipo; `curl_version($nonDefault)` genera un warning ed ignora i valori diversi da `CURLVERSION_NOW`.
* **Date**: il dump di `DateTime*` non lascia più proprietà orfane; il **confronto tra `DateInterval`** genera un warning e restituisce sempre `false`.
* **Intl**: la variante predefinita per `idn_to_ascii` / `idn_to_utf8` è **`INTL_IDNA_VARIANT_UTS46`**.
* **MySQLi**: rimosso il server integrato; rimossa la proprietà non documentata `$mysqli->stat`—utilizza **`mysqli::stat()`**.
* **OpenSSL**: `openssl_random_pseudo_bytes` lancia eccezioni analoghe a **`random_bytes`** in caso di errore; `$crypto_strong` è impostata su `true` in assenza di eccezioni.
* **PCRE**: con **`PREG_UNMATCHED_AS_NULL`**, i gruppi finali senza corrispondenza vengono impostati su **`null`** (mantenendo stabile la dimensione di `$matches`).
* **PDO**: la serializzazione di **`PDO`/`PDOStatement`** lancia un'eccezione **`Exception`** (non `PDOException`).
* **Reflection**: la serializzazione di oggetti reflection **genera un'eccezione**; modificati alcuni **valori numerici delle costanti dei modificatori**.
* **SPL / `ArrayObject`**: modificato il comportamento di **`get_object_vars`** a meno che non sia impostato `STD_PROP_LIST`; la chiamata `SplPriorityQueue::setExtractFlags(0)` genera immediatamente un'eccezione.
* **Tokenizer**: byte non previsti generano il token **`T_BAD_CHARACTER`** invece di creare lacune nel flusso.
* **Cookie (da PHP 7.4.11)**: i **nomi** dei cookie non vengono più decodificati dall'URL.

---

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

Elementi critici:

* **Operatori ternari annidati** senza parentesi esplicite (eccetto la forma non ambigua con operando centrale).
* **Offset con parentesi graffe** `$str{0}` / `$arr{0}` → utilizza `[]`.
* **`(real)`** / **`is_real()`** → **`(float)`** / **`is_float()`**.
* **`array_key_exists()` sugli oggetti** → **`isset()`** / **`property_exists()`**.
* **`implode($parts, $glue)`** con ordine inverso degli argomenti → **`implode($glue, $parts)`**.
* **`ReflectionType::__toString()`** e **`Reflection*::export()`** → utilizza le API come **`ReflectionNamedType::getName()`** e il cast a stringa degli oggetti reflection.
* **`allow_url_include`**, **`FILTER_SANITIZE_MAGIC_QUOTES`**, vecchi helper di paginazione LDAP e numerose funzioni di servizio (`money_format()`, `hebrevc()`, …)—vedi la pagina di riferimento [migration74 deprecated](https://www.php.net/manual/en/migration74.deprecated.php).

---

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

Metti alla prova la tua conoscenza delle funzionalità di PHP 7.4:

1. **Cosa succede leggendo una proprietà tipizzata non inizializzata in PHP 7.4?**
   * A) Restituisce `null`
   * B) Genera un Notice e restituisce `null`
   * C) Genera un'eccezione di tipo Error
   * D) Restituisce `false`

   <details>
   <summary>Clicca per vedere la risposta</summary>
   
   **Risposta corretta: C**  
   PHP 7.4 vieta tassativamente di leggere una proprietà tipizzata prima della sua inizializzazione. Il tentativo genera un `Error` (nello specifico: `Error: Typed property ... must not be accessed before initialization`).
   </details>

2. **È possibile modificare una variabile dell'ambito esterno dall'interno di una funzione freccia?**
   * A) Sì, le variabili sono catturate per riferimento
   * B) No, le variabili sono catturate per valore
   * C) Sì, ma solo se utilizzi la parola chiave `use`
   * D) Sì, ma solo per gli oggetti

   <details>
   <summary>Clicca per vedere la risposta</summary>
   
   **Risposta corretta: B**  
   Le funzioni freccia di PHP catturano automaticamente le variabili per valore. Qualsiasi modifica apportata alle variabili dell'ambito esterno dall'interno della funzione freccia è locale e non influisce sull'ambito esterno.
   </details>

3. **Quale tipo di proprietà NON è consentito in PHP 7.4?**
   * A) `object`
   * B) `callable`
   * C) `iterable`
   * D) `?string`

   <details>
   <summary>Clicca per vedere la risposta</summary>
   
   **Risposta corretta: B**  
   Il tipo `callable` è esplicitamente vietato come tipo di proprietà di una classe poiché il suo comportamento dipende strettamente dal contesto di chiamata.
   </details>

---

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

Considera PHP 7.4 come **la versione di transizione**: adotta le proprietà tipizzate e la serializzazione moderna **prima** dei controlli più rigorosi di PHP 8.0. In parallelo, verifica la presenza di **algoritmi password di tipo intero**, degli identificatori denominati **`fn`**, della sintassi **`$var{idx}`** e dei pattern basati su **ArrayObject**—ed esegui nuovamente i test di integrazione per **stream**, **OpenSSL random** e la serializzazione **PDO/Reflection**.