Guida Completa alla Funzione mysqli_thread_safe in PHP
Scopri cosa significa thread-safe in PHP, perché mysqli_thread_safe() non esiste e come verificare la sicurezza dei thread nel tuo ambiente.
Quando si lavora con database MySQL in PHP tramite l'estensione mysqli, una domanda che emerge spesso è: "È mysqli thread-safe, ed esiste una funzione mysqli_thread_safe() che posso chiamare per verificarlo?"
La risposta breve è che mysqli_thread_safe() non è una funzione in PHP, e la thread safety non è qualcosa che si interroga a runtime. È una proprietà di come il tuo binario PHP è stato compilato. Questa guida spiega cosa significa realmente "thread-safe" per PHP, perché la thread safety di mysqli è una decisione presa al momento della compilazione, quando è rilevante in pratica e come verificarla nel tuo ambiente.
Cosa Significa "Thread-Safe" in PHP
Un programma è thread-safe quando più thread possono eseguire lo stesso codice contemporaneamente senza corrompere dati condivisi. In una build thread-safe, il motore PHP protegge lo stato globale interno (la symbol table, il memory manager, i globali delle estensioni, ecc.) in modo che due thread in esecuzione all'interno dello stesso processo non possano interferire con i dati dell'altro.
PHP viene distribuito in due varianti, decise al momento della compilazione del binario:
- ZTS (Zend Thread Safety) — chiamata anche build Thread Safe (TS). Il motore aggiunge blocchi e copie per thread dello stato globale in modo che PHP possa girare all'interno di un processo host multi-threaded.
- NTS (Non-Thread-Safe) — il motore assume una richiesta per processo e salta questo overhead, risultando più veloce.
Non è possibile passare dall'una all'altra a runtime, e non esiste alcun mysqli_thread_safe() per abilitarla o riportarne lo stato. Il tipo di build è fissato quando si sceglie ./configure --enable-maintainer-zts (o l'equivalente per la piattaforma) durante la compilazione.
Perché È un'Impostazione al Momento della Compilazione, Non una Funzione
Le persone si aspettano una funzione mysqli_thread_safe() perché alcune librerie C espongono una chiamata mysql_thread_safe(). PHP non ne offre una, perché la risposta non cambia mai per un dato binario — interrogarla a runtime restituirebbe sempre lo stesso valore. Che mysqli sia sicuro nei thread dipende direttamente dalla scelta ZTS/NTS incorporata nella build PHP, più la libreria client sottostante (i moderni PHP usano mysqlnd, il driver nativo, che non ha un proprio interruttore di thread safety separato).
Quindi, invece di chiamare una funzione, si ispeziona la build.
Quando la Thread Safety È Davvero Importante
Per la grande maggioranza delle applicazioni PHP, dovresti usare la build NTS e la thread safety non è un problema:
| Configurazione | Build da usare | Perché |
|---|---|---|
| Nginx + PHP-FPM | NTS | Ogni worker è un processo single-threaded; nessun thread condiviso. |
Apache con mpr_prefork | NTS | Ogni richiesta ha il proprio processo. |
| Script CLI, cron job | NTS | Un processo, un thread. |
Apache con worker / event MPM + mod_php | ZTS | mod_php gira all'interno dei worker threaded di Apache. |
Estensioni come parallel / pthreads (legacy) | ZTS | Creano thread PHP in un unico processo. |
La classica trappola nel mondo reale è Apache + mod_php su un MPM threaded: se si carica un PHP non thread-safe in un Apache threaded, il server può crashare o corrompere dati sotto carico. Usare PHP-FPM invece di mod_php aggira completamente questo problema, ed è per questo che FPM + NTS è il deployment moderno standard. Vedi la guida all'installazione di PHP per come vengono scelte le build.
Gestire mysqli in un Contesto Multi-Threaded
Anche su un PHP ZTS correttamente compilato, il connection object di mysqli non è destinato ad essere condiviso tra thread. Un link mysqli mantiene risultati bufferizzati, lo stato delle prepared statement e un socket aperto — l'uso concorrente da due thread produce errori commands-out-of-sync o risultati corrotti.
La regola è semplice: una connessione per thread. Apri la connessione all'interno del thread che la usa invece di passare un handle condiviso.
<?php
// Each worker/thread creates and owns its own connection.
function runWorkerTask(int $workerId): void
{
// New, independent connection for THIS thread.
$db = new mysqli('localhost', 'user', 'password', 'shop');
if ($db->connect_errno) {
// Handle per-thread connection failure locally.
error_log("Worker {$workerId} failed: {$db->connect_error}");
return;
}
$result = $db->query('SELECT COUNT(*) AS total FROM orders');
$row = $result->fetch_assoc();
echo "Worker {$workerId} sees {$row['total']} orders\n";
$db->close(); // Release the connection when the thread is done.
}Per le basi su come aprire e verificare una connessione, vedi Connettersi a MySQL con mysqli e mysqli_connect_errno().
Come Verificare la Thread Safety nel Tuo Ambiente
Poiché non esiste una funzione runtime, usa uno di questi metodi per leggere l'impostazione della build.
Usando phpinfo()
Crea uno script di una riga e aprilo nel browser, oppure eseguilo dalla CLI:
<?php
phpinfo();Nell'output, trova la tabella in alto e cerca la riga Thread Safety (si trova vicino alle informazioni su Zend Engine / build). Mostra enabled (ZTS) o disabled (NTS).
Verifica dalla Riga di Comando
Da un terminale, filtra il dump completo della configurazione:
php -i | grep "Thread Safety"Questo stampa uno dei seguenti:
Thread Safety => enabled
Thread Safety => disabledAll'Interno del Codice PHP in Esecuzione
Se vuoi il valore in modo programmatico — per una pagina di diagnostica, ad esempio — leggi la costante PHP_ZTS invece di cercare una funzione inesistente:
<?php
// PHP_ZTS is 1 on a Thread Safe (ZTS) build, 0 on a Non-Thread-Safe (NTS) build.
echo PHP_ZTS === 1 ? "Thread-safe (ZTS) build\n" : "Non-thread-safe (NTS) build\n";Questo è il sostituto corretto e supportato per l'immaginaria chiamata mysqli_thread_safe().
Errori Comuni
- Chiamare
mysqli_thread_safe()— non esiste e genera unError: Call to undefined function. UsaPHP_ZTSophpinfo()invece. - Condividere una connessione
mysqlitra thread — apri sempre una connessione separata per ogni thread. - Caricare un PHP NTS in un Apache MPM threaded — adatta la build al server, o passa a PHP-FPM.
- Presumere che ZTS sia "migliore" — è più lento ed è necessario solo per host genuinamente threaded; preferisci NTS negli altri casi.
Conclusione
mysqli_thread_safe() è una funzione che non esiste. La thread safety in PHP è fissata al momento della compilazione dalla scelta Zend Thread Safety (ZTS), non attivata o riportata da una chiamata runtime. La maggior parte degli stack moderni (Nginx/Apache-prefork + PHP-FPM) usa la build NTS più veloce e non ha mai bisogno di ZTS. Quando hai bisogno di verificarla, leggila con phpinfo(), php -i | grep "Thread Safety", o la costante PHP_ZTS — e dai sempre a ogni thread la propria connessione mysqli per mantenere i dati consistenti.