Non tutti i messaggi di errore possono essere gestiti all'interno dello script. Pur facendo uso di set_error_handler il manuale ci dice che
The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called. If errors occur before the script is executed (e.g. on file uploads) the custom error handler cannot be called since it is not registered at that time.
Se il problema è quello, all'interno di uno script, di modificare l'error_reporting senza modificare il php.ini, è comunque possibile fare uso della funzione error_reporting
Codice PHP:
$old_err_rep=error_reporting(E_ALL | E_STRICT);
che setta per lo script attualmente in esecuzione un livello di report utile in fase di sviluppo.
D'altra parte qualcosa di carino si può ancora realizzare. Ho apportato delle modifiche ai file logica.php e MyException.php ed error.php ma per completezza riposto tutte le pagine di modo che chi copia e incolla trova tutti i file dell'esempio funzionante.
In logica.php viene effettuata la cattura degli errori prodotti da PHP. All'esterno del blocco try-catch occorre però esplicitamente attivate la cattura e al termine disattivarla per consentire la comparsa di altri errori magari nel file di visualizzazione.
Il problema maggiore sta nel fatto che quando si verifica una eccezione il codice restante del try non viene eseguito e ciò può provocare dei dati mancanti alla pagina addetta alla visualizzazione. Applicare il controllo all'interno della pagina di visualizzazione può provocare la produzione di pagine incomplete. In tal caso sarebbe opportuno utilizzare le funzioni ob_ come nei primi esempi di modo da pulire il buffer e produrre solo l'errore al posto della pagina incompleta o un avvertimento che segnala la mancata produzione della pagina a causa di errori.
Nell'esempio di codice viene introdotta la chiamata ad un funzione deprecata all'interno di logica.php che fa scattare l'apertura del popup con i dettagli. La mancata completa esecuzione del corpo try ha comunque delle ripercussioni sulla visualizzazione.
index.php
Codice PHP:
<?php require_once 'logica.php';?>
<html>
<head>
<title>Stupida Calcolatrice</title>
</head>
<body>
<h1>Stupida Calcolatrice</h1>
<form action="index.php" method="post">
<input type="text" name="<?php echo operando;?>[]" value="<?php echo (isset($_POST[operando])) ? $_POST[operando][0] : "Inserire un numero" ?>">
<select name="<?php echo operatore;?>">
<?php
//Visualizzazione delle option precaricate nell'array $operatori in logica.php
// con permanenza dell'ultimo operatore selezionato
foreach ($operatori as $value)
echo "<option ".((isset($_POST[operatore]) and $_POST[operatore]==$value) ? "selected=\"selected\"" : "").">$value</option>";
?>
</select>
<input type="text" name="<?php echo operando;?>[]" value="<?php echo (isset($_POST[operando])) ? $_POST[operando][1] : "Inserire un numero" ?>">
[b]<?php echo $responso;?>[/b]
<input type="submit" value="Calcola">
</form>
</body>
</html>
logica.php
Codice PHP:
<?php
//Sezione di definizione
require_once 'MyException.php';
session_start();
define('operando', 'operando');
define('operatore', 'operatore');
$responso = "";
//Inizia la cattura degli errori generati da PHP
MyPHPException::Activate(E_ALL | E_STRICT);
try {
//Invoco una funzione deprecata
ereg ("([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})", "1999-1-1", $regs);
//Per aggiungere un nuovo operatore mi basta metterlo nell'array seguente e
//definire più sotto il case implementativo
$operatori = array('/', '*', '+', '-', '%');
//Sezione di elaborazione
if (isset($_POST[operatore])) {
if (!is_numeric($_POST[operando][0]))
throw new MyException("Il primo operatore non è un numero", 1);
if (!is_numeric($_POST[operando][1]))
throw new MyException("Il secondo operatore non è un numero", 2);
switch ($_POST[operatore]) {
case '/':
if ($_POST[operando][1] == 0)
throw new MyException("Non è possibile dividere per 0", 3);
$responso = $_POST[operando][0] / $_POST[operando][1];
break;
case '*':
$responso = $_POST[operando][0] * $_POST[operando][1];
break;
case '+':
$responso = $_POST[operando][0] + $_POST[operando][1];
break;
case '-':
$responso = $_POST[operando][0] - $_POST[operando][1];
break;
default:
throw new MyException("Operatore non implementato", 100);
break;
}
$responso = "= $responso";
}
} catch (MyPHPException $e) {
//Cattura dell'errore PHP
echo $e;
} catch (MyException $e) {
//Cattura di un errore dell'applicazione gestito
$responso = $e . "Operazione non effettuabile";
}
MyPHPException::\DeActivate();
//Ripristino il gestore normale per gli errori prodotti da PHP
?>
MyException.php
Codice PHP:
<?php
class MyException extends Exception{
public function __construct($message, $code) {
parent::__construct($message, $code);
$_SESSION[__CLASS__][]=array('message'=>$message,'code'=>$code);
}
public function __toString() {
return "<script type=\"text/javascript\">window.open('errore.php?id=".__CLASS__."','FinestraErrore','');</script>";
}
}
class MyPHPException extends MyException{
private static $olderrtype;
public static function Activate($error_type=E_ALL){
MyPHPException::$olderrtype=error_reporting($error_type);
set_error_handler('MyPHPException::ErrorHandler', $error_type);
}
public static function DeActivate(){
error_reporting(MyPHPException::$olderrtype);
restore_error_handler();
}
public static function ErrorHandler($errno, $errstr, $errfile, $errline, $errcontext){
$message="$errstr
File: ".basename($errfile)."
Line: $errline
";
if($errno & (E_PARSE | E_USER_ERROR))
return false;
throw new MyPHPException($message, $errno);
return true;
}
}
?>
errore.php
Codice PHP:
<?php
//Questa è una pagina di supporto alla classe MyException.php con il compito
//di visualizzare le eccezzioni sollevate
//Logica della pagina
session_start();
foreach ($_SESSION[$_GET['id']] as $subvalue) {
$code[] = $subvalue['code'];
$message[] = $subvalue['message'];
}
unset($_SESSION[$_GET['id']]);
//Visualizzazione
?>
<html>
<head>
<title>Messaggio di Errore</title>
</head>
<body>
<?php
$n=count($code);
for($i=0;$i<$n;$i++){
?>
<fieldset style="width: 20em;">
<legend>Errore: <?php echo $code[$i];?></legend>
<?php echo $message[$i];?>
</fieldset>
<?php }?>
</body>
</html>