Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

PHP: generare eccezioni invece di restituire false

Il comportamento di default delle funzioni PHP prevede che in caso di errori restituiscono il valore booleano false invece di generare un’eccezione, analizziamo alcune soluzioni che consentono di ovviare a questo problema.
Il comportamento di default delle funzioni PHP prevede che in caso di errori restituiscono il valore booleano false invece di generare un’eccezione, analizziamo alcune soluzioni che consentono di ovviare a questo problema.
Link copiato negli appunti

In un precedente articolo abbiamo parlato del comportamento di default delle funzioni core in caso di fallimento durante la fase di esecuzione, esse infatti restituiscono il valore booleano false invece di generare un’eccezione. In questo nuovo approfondimento proporremo invece alcune soluzioni che consentono di ovviare al problema precedentemente descritto.

Soluzione 1: funzioni wrapper che estendenono quelle Core

Il team di sviluppo di Guzzle, un popolare framework PHP che permette di evitare i problemi relativi alla creazione di richieste HTTP ed alla costruzione di client per Web Services, ha avuto la brillante idea di operare nel modo seguente per quanto riguarda le funzioni PHP che lavorano con i dati JSON:

namespace GuzzleHttp;
// ...
function json_decode($json, $assoc = false, $depth = 512, $options = 0)
{
    $data = \json_decode($json, $assoc, $depth, $options);
    if (JSON_ERROR_NONE !== json_last_error()) {
        throw new \InvalidArgumentException(
            'json_decode error: ' . json_last_error_msg()
        );
    }
    return $data;
}
function json_encode($value, $options = 0, $depth = 512)
{
    $json = \json_encode($value, $options, $depth);
    if (JSON_ERROR_NONE !== json_last_error()) {
        throw new \InvalidArgumentException(
            'json_encode error: ' . json_last_error_msg()
        );
    }
    return $json;
}

In questo caso vengono create due funzioni "wrapper", chiamate allo stesso modo di quelle del Core, che svolgono il medesimo compito, ad eccezione del fatto che vengono definite all'interno di un namespace. Le funzioni json_decode e json_encode chiamano le loro controparti Core e generano un'eccezione nel caso in cui si verifichi un errore in fase di chiamata.

Dunque, avendo dichiarato la funzione json_decode con le nostre feature, nel codice successivo possiamo passare a chiamarla attraverso l'operatore use:

use function json_decode;
// Genera un'eccezione al posto di restituire false, dato che il JSON non è corretto
json_decode('{ "foo": bar" ');

In questo caso la funzione genera correttamente un'eccezione, al posto di restituire false, perché la stringa JSON fornita non è corretta.

Prendendo spunto dall'ottimo lavoro da parte del team di Guzzle, gli sviluppatori di The Code Machine hanno iniziato il progetto chiamato "Safe PHP" che permette di utilizzare le funzioni Core nella maniera "corretta", avvalendosi delle eccezioni, senza limitarsi a quelle che gestiscono la codifica e la decodifica JSON.

L'idea alla base di Safe PHP è semplice: sostituire tutte le funzioni Core con versioni wrapper che invece di restituire false/NULL in caso di errore, lanciano un'eccezione. In questo modo il codice diventa davvero più robusto: abbiamo ad esempio l'opportunità di lavorare con l'operatore try/catch. Con Safe PHP è possibile scrivere qualcosa del genere:

use function Safe\file_get_contents;
use function Safe\json_decode;
$content = file_get_contents('myfile.json');
$myvar = json_decode($content);

In questo caso non c'è alcun rischio di passare involontariamente valori false/NULL nelle future operazioni con le variabili utilizzate, rendendo di fatto il debugging molto più semplice. Inoltre, c'è un altro vantaggio: dato che le funzioni dichiarate da Safe PHP hanno nomenclatura identica a quelle del Core, il codice non cambia di una virgola, ad eccezione delle linee necessarie all'introduzione delle funzioni (operatore use) all'inizio dello script.

Questo sistema è talmente efficace che Safe PHP non è ovviamente l'unico script che fa uso di wrapper che estendono le funzioni Core. Esistono svariate alternative per svolgere compiti anche complessi, come ad esempio:

  • symfony/filesystem: wrapper che estende le funzioni PHP Core per lavorare con il filesystem.
  • Flysystem (PHP League): libreria di astrazione per lavorare con le funzioni filesystem.
  • nette/utils: libreria che fornisce weapper per molte delle funzioni Core di PHP (la nomenclatura cambia).

Soluzione 2: personalizzare il sistema di gestione degli errori di PHP

Esiste inoltre un'altra modalità per gestire questa "pecca" di PHP, oltre a quella di wrappare le funzioni Core. Dato che PHP è provvisto di un sistema di gestione degli errori personalizzabile, e che molte delle funzioni Core che restituiscono false/NULL in caso di fallimento delle operazioni generano anche un avvertimento, possiamo sfruttare questa caratteristica catturando l'errore e producendo manualmente un'eccezione invece di utilizzare il gestore dell'errore standard. Facciamolo, tramite la funzione set_error_handler:

set_error_handler(function($severity, $message, $file, $line) {
	throw new ErrorException($message, 0, $severity, $file, $line);
});

Questa soluzione è oggettivamente molto valida, ma presenta due punti deboli da non trascurare:

  1. il comportamento dello script dipende da un sistema di gestione degli errori che non è direttamente dichiarato nel codice, ovvero non è una componente creativa di quest'ultimo. Se ad esempio il codice deve essere ri-utilizzato in progetti differenti, non c'è garanzia che il sistema utilizzi un gestore degli errori rigido.
  2. Alcuni strumenti di analisi del codice PHP, come PHPStan, non hanno consapevolezza del sistema di gestione degli errori globale, cosi che questi vanno configurati in modo più "morbido" (aka meno restrittivo). Rendere un sistema di analisi più morbido, significa perdere molte delle problematiche che verrebbero invece segnalate con un sistema più rigido.

Ti consigliamo anche