---
title: 'PHP 8.4: Property Hooks, Lazy Objects, New DOM & Migration Guide | DevSense'
description: 'Note di aggiornamento per PHP 8.4 (da PHP 8.3): Property Hooks, visibilità asimmetrica, Lazy Objects, #[Deprecated], request_parse_body(), nuova API Dom\* e modifiche non retrocompatibili.'
faq:
    - { question: 'Cosa sono i Property Hooks in PHP 8.4?', answer: "I property hook consentono di intercettare e definire una logica personalizzata per l'accesso (get) e la modifica (set) di una proprietà direttamente nella sua dichiarazione, eliminando la necessità di scrivere codice ripetitivo per getter e setter." }
    - { question: 'Una proprietà con hook può essere passata per riferimento?', answer: 'No, le proprietà con hook non possono essere passate per riferimento poiché i loro valori vengono letti o scritti attraverso gli hook e potrebbero non avere un riferimento diretto in memoria.' }
    - { question: "Cos'è la visibilità asimmetrica in PHP 8.4?", answer: 'La visibilità asimmetrica consente di impostare livelli di visibilità differenti per la lettura e la scrittura di una proprietà. Ad esempio, una proprietà può essere letta pubblicamente (public) ma modificata solo privatamente (private set).' }
    - { question: 'A cosa serve request_parse_body()?', answer: "Consente l'analisi dei corpi delle richieste RFC1867 (multipart/form-data) in metodi HTTP diversi da POST, come PUT o PATCH." }
published: '2026-05-31'
---
# PHP 8.4: Funzionalità principali e guida interattiva

PHP 8.4 è una release di grande importanza orientata alla produttività. Cambia completamente il modo in cui esprimiamo i vincoli sulle proprietà (Property Hooks, visibilità asimmetrica), introduce funzionalità interne di livello framework (Lazy Objects) e risolve i problemi storici dell'estensione DOM introducendo nuove classi conformi agli standard WHATWG.

In questa guida, esploreremo queste funzionalità utilizzando esempi pratici, esamineremo i problemi comuni e metteremo alla prova le tue conoscenze alla fine!

---

## Indice
* [Property Hooks (Hook delle proprietà)](#property-hooks)
* [Visibilità asimmetrica delle proprietà](#asymmetric-visibility)
* [Lazy Objects (Ghosts e Proxies)](#lazy-objects)
* [Deprecazioni a livello utente con `#[Deprecated]`](#deprecated-attribute)
* [Namespace DOM moderno conforme a WHATWG (`Dom\*`)](#dom-modern)
* [Analisi di richieste multipart non-POST: `request_parse_body()`](#request-parse-body)
* [Nuovi helper per array e operazioni matematiche](#new-functions)
* [Modifiche non retrocompatibili e deprecazioni](#backward-incompatible)
* [🧠 Domande di autovalutazione](#self-check)

---

<a id="property-hooks"></a>
## Property Hooks (logica get/set sulle proprietà)

Per anni, gli sviluppatori PHP hanno dovuto scrivere codice ripetitivo per definire getter e setter allo scopo di validare o formattare i valori prima di memorizzarli. PHP 8.4 introduce i **Property Hooks** direttamente nella dichiarazione della proprietà.

Esistono due tipi di hook:
* `set`: attivato quando si scrive in una proprietà.
* `get`: attivato quando si legge una proprietà.

Vediamo questo meccanismo in azione:

```php
// app/DTO/Person.php
final class Person
{
    // Un hook può scrivere in una proprietà di supporto utilizzando $this->propName
    public string $firstName {
        set => ucfirst(strtolower($value));
    }

    public string $lastName {
        set {
            if (strlen($value) < 2) {
                throw new InvalidArgumentException('Last name is too short!');
            }
            $this->lastName = $value;
        }
    }

    // Proprietà calcolata (virtuale) priva di spazio di memoria dedicato!
    public string $fullName {
        get => $this->firstName . ' ' . $this->lastName;
    }
}
```

> [!NOTE]
> **Lo sapevi?**
> Le proprietà che definiscono esclusivamente un hook `get` sono considerate virtuali per impostazione predefinita e non occupano spazio in memoria né persistenza all'interno degli oggetti.

### ⚠️ Errori comuni

**1. Tentativo di passare una proprietà con hook per riferimento**
Poiché l'accesso a una proprietà dotata di hook richiama una funzione a livello sottostante, non è possibile passarla per riferimento:

```php
// app/Services/ContactService.php
function cleanString(string &$str) {
    $str = trim($str);
}

$person = new Person();
cleanString($person->firstName); // ❌ Fatal Error: Cannot pass property Person::$firstName by reference
```

**2. Creazione accidentale di una ricorsione infinita negli hook `set`**
Se assegni un valore a `$this->propertyName` all'interno del suo stesso hook usando la sintassi `$this->propertyName = $value`, il codice viene compilato ma, se non si gestisce correttamente la variabile di supporto, si rischia di innescare una ricorsione infinita. Fortunatamente, le espressioni abbreviate (`=>`) assegnano automaticamente il valore alla variabile di supporto sottostante.

---

<a id="asymmetric-visibility"></a>
## Visibilità asimmetrica delle proprietà (`public private(set)`)

In PHP 8.4, è ora possibile definire livelli di visibilità differenti per la lettura e la scrittura delle proprietà. Questo rappresenta un enorme passo in avanti per la progettazione di DTO in sola lettura e per gli aggregate root nel Domain-Driven Design (DDD).

```php
// app/Models/User.php
final class User
{
    // Leggibile da ovunque, ma modificabile solo dall'interno di questa classe
    public private(set) string $email;

    public protected(set) int $loginAttempts = 0;

    public function __construct(string $email)
    {
        $this->email = $email;
    }

    public function incrementAttempts(): void
    {
        $this->loginAttempts++;
    }
}
```

> [!NOTE]
> **Lo sapevi?**
> La visibilità asimmetrica richiede che l'operazione di scrittura (`set`) sia **più restrittiva** rispetto all'operazione di lettura. Ad esempio, la combinazione `private public(set)` non è valida e produrrà un errore di sintassi.

---

<a id="lazy-objects"></a>
## Lazy Objects (Ghosts e Proxies tramite la Reflection)

PHP 8.4 introduce il supporto nativo per i **Lazy Objects** (oggetti paresi). Questa funzionalità è destinata principalmente agli sviluppatori di framework e ORM (come Doctrine o le relazioni Eloquent di Laravel) che hanno la necessità di posticipare l'idratazione da database o le chiamate API fino a quando non viene effettivamente effettuato l'accesso a una proprietà.

In precedenza, le librerie dovevano generare classi proxy complesse al volo. Ora, l'estensione Reflection gestisce questo comportamento in modo nativo:

```php
// app/Services/Container.php
$initializer = static function (LargeService $service) {
    $service->loadHeavyConfiguration();
};

$r = new ReflectionClass(LargeService::class);
// Crea un'istanza lazy ghost di LargeService
$lazyService = $r->newLazyGhost($initializer);
```

La funzione di inizializzazione dell'oggetto viene eseguita esclusivamente al tentativo di accedere a una proprietà di `$lazyService`.

---

<a id="deprecated-attribute"></a>
## Deprecazioni a livello utente con `#[Deprecated]`

In precedenza, per contrassegnare come deprecata una funzione o un metodo personalizzato, gli sviluppatori dovevano attivare manualmente un errore di tipo `E_USER_DEPRECATED`. Ora è possibile utilizzare l'attributo nativo `#[\Deprecated]`:

```php
// app/Helpers/LegacyMath.php
class LegacyMath
{
    #[\Deprecated(message: "Use BCMath or native division instead", since: "1.4.0")]
    public static function divide(int $a, int $b): float
    {
        return $a / $b;
    }
}
```

Quando un client richiama questo metodo, PHP genererà automaticamente un avviso di deprecazione includendo il messaggio e la versione specificati.

---

<a id="dom-modern"></a>
## Namespace DOM moderno conforme a WHATWG (`Dom\*`)

Per lungo tempo, la classe `DOMDocument` di PHP ha sofferto di una scarsa conformità con gli standard HTML5. PHP 8.4 introduce un'API DOM moderna e conforme alle specifiche WHATWG all'interno del namespace `Dom`.

```php
// app/Services/HtmlParser.php
// Analizza le moderne strutture HTML5 senza ricorrere a workaround complessi
$dom = Dom\HTMLDocument::createFromString('<main><article>Modern HTML5!</article></main>');
$node = $dom->querySelector('article');

echo $node->textContent; // Output: Modern HTML5!
```

Le classi esistenti come `DOMDocument` rimangono disponibili per motivi di retrocompatibilità, ma si incoraggiano gli sviluppatori a migrare verso `Dom\HTMLDocument` e `Dom\XMLDocument`.

---

<a id="request-parse-body"></a>
## Analisi di richieste multipart non-POST: `request_parse_body()`

Se hai mai sviluppato un'API REST in PHP in cui gli utenti caricano file tramite richieste `PUT` o `PATCH`, conoscerai bene la problematica: le variabili globali `$_FILES` e `$_POST` vengono popolate solo in caso di richieste `POST`. Gli sviluppatori erano costretti ad analizzare manualmente il flusso dei dati in ingresso.

PHP 8.4 introduce la funzione `request_parse_body()`, che analizza le richieste multipart/form-data conformi a RFC1867 per qualsiasi metodo HTTP:

```php
// public/index.php
if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
    [$postData, $files] = request_parse_body();
    
    // $postData contiene i campi inviati tramite modulo
    // $files contiene i file caricati mappati in modo identico a $_FILES
}
```

---

<a id="new-functions"></a>
## Nuovi helper per array e operazioni matematiche

PHP 8.4 include diverse funzioni di utilità per semplificare le attività di sviluppo quotidiane:

### 1. `array_find()`, `array_find_key()`, `array_any()`, `array_all()`

```php
// app/Services/Validator.php
$users = [
    ['name' => 'Alice', 'role' => 'user'],
    ['name' => 'Bob', 'role' => 'admin'],
];

// Trova il primo utente amministratore
$admin = array_find($users, fn($u) => $u['role'] === 'admin');

// Verifica se esistono utenti con ruolo 'user'
$hasUsers = array_any($users, fn($u) => $u['role'] === 'user');
```

### 2. Rimozione di spazi bianchi multibyte (`mb_trim`)
La funzione nativa `trim()` non supporta i caratteri multibyte, lasciando spazi vuoti UTF-8 non rimossi al termine delle stringhe. PHP 8.4 risolve questo problema con le funzioni `mb_trim()`, `mb_ltrim()` e `mb_rtrim()`.

---

<a id="backward-incompatible"></a>
## Modifiche non retrocompatibili e deprecazioni

Prima di aggiornare i server di produzione a PHP 8.4, analizza la tua codebase verificando i seguenti punti:

1. **I parametri implicitamente nullable sono deprecati**
   ```php
   // ❌ Deprecato in PHP 8.4
   function save(string $name = null) {}

   // ✅ Approccio corretto
   function save(?string $name = null) {}
   ```
2. **Comportamento di `exit()` e `die()`**
   Ora sono funzioni a tutti gli effetti anziché costrutti del linguaggio. Ciò significa che sono soggetti alla coercizione dei tipi standard ed alla direttiva `strict_types`. Il passaggio di un oggetto o di un array non valido genererà un `TypeError`.
3. **Migrazione delle risorse a oggetti**
   Le estensioni come DBA, ODBC e SOAP restituiscono ora oggetti anziché risorse. Se esegui controlli con `is_resource()` su queste connessioni, l'output sarà ora `false`.

---

<a id="self-check"></a>
## 🧠 Domande di autovalutazione

Ripassiamo ciò che abbiamo imparato! Prova a rispondere a queste domande:
1. **Vero o Falso?** È possibile definire sia un hook `get` sia un hook `set` per una proprietà virtuale?
2. Perché `cleanString($person->firstName)` genera un Fatal Error se la proprietà `$firstName` definisce degli hook?
3. Cosa succede se definisci una proprietà con visibilidad `private public(set)`?
4. Quale funzione helper introdotta in PHP 8.4 dovresti usare per verificare se *almeno un* elemento in un array soddisfa una determinata callback di convalida?

<details>
<summary><b>Mostra risposte</b></summary>

1. **Falso.** Una proprietà virtuale non dispone di memoria sottostante, pertanto non è possibile definire un hook `set` che scriva direttamente in essa (a meno che l'hook `set` non vada ad aggiornare una proprietà differente della stessa classe).
2. Poiché le proprietà con hook sono valori calcolati richiamati tramite apposite routine; non possiedono un riferimento stabile in memoria e quindi non sono idonee per il passaggio per riferimento.
3. Viene generato un errore di sintassi. La visibilità di scrittura (`set`) deve essere identica o più restrittiva rispetto alla visibilità di lettura (`get`).
4. Si consiglia di utilizzare `array_any()`.
</details>