PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Les références> <Règles de résolution de noms
Last updated: Fri, 20 Jun 2008

view this page in

Les exceptions

PHP 5 a une gestion des exceptions similaire à ce qu'offrent les autres langages de programmation. Une exception peut être lancée ("throw") et attrapée ("catch") dans PHP. Le code devra être entouré d'un bloc try pour faciliter la saisie d'une exception potentielle. Chaque try doit avoir au moins un bloc catch correspondant. Plusieurs blocs catch peuvent être utilisés pour attraper différentes classes d'exceptions. L'exécution normal (lorsque aucune exception n'est lancée dans le bloc try ou lorsqu'un catch correspondant à l'exception lancée n'est pas présent) continue après le dernier bloc catch défini dans la séquence. Les exceptions peuvent être lancées (ou relancées) dans un bloc catch.

Lorsqu'une exception est jetée, le code suivant le traitement ne sera pas exécuté et PHP tentera de trouver le premier bloc catch correspondant. Si une exception n'est pas attrapé, une erreur fatale issue de PHP sera envoyée avec un message spécifiant que l'exception n'a pu être attrapée à moins qu'un gestionnaire ne soit défini avec la fonction set_exception_handler().

Exemple #1 Lancer une exception

<?php
function inverse($x) {
    if (!
$x) {
        throw new 
Exception('Division par zéro.');
    }
    else return 
1/$x;
}

try {
    echo 
inverse(5) . "\n";
    echo 
inverse(0) . "\n";
} catch (
Exception $e) {
    echo 
'Exception reçue : ',  $e->getMessage(), "\n";
}

// Continue execution
echo 'Bonjour le monde !';
?>

L'exemple ci-dessus va afficher :

0.2
Exception reçue : Division par zéro.
Hello World

Exemple #2 Héritage d'une exception

<?php

class MyException extends Exception { }

class 
Test {
    public function 
testing() {
        try {
            try {
                throw new 
MyException('foo!');
            } catch (
MyException $e) {
                
/* on la relance */
                
throw $e;
            }
        } catch (
Exception $e) {
            
var_dump($e->getMessage());
        }
    }
}

$foo = new Test;
$foo->testing();

?>

L'exemple ci-dessus va afficher :

string(4) "foo!"

Exceptions étendues

Une classe Exception définie par l'utilisateur peut être définie en étendant la classe Exception interne. Les membres et les propriétés suivantes montrent ce qui est accessible dans la classe enfant qui est dérivée de la classe exception interne.

Exemple #3 La classe Exception interne

<?php
class Exception
{
  protected 
$message 'exception inconnu'// message de l'exception
  
protected $code 0;                      // code de l'exception défini par l'utilisateur
  
protected $file;                          // nom du fichier source de l'exception
  
protected $line;                          // ligne de la source de l'exception

  
function __construct(string $message=NULLint code=0);

  final function 
getMessage();              // message de l'exception
  
final function getCode();                 // code de l'exception
  
final function getFile();                 // nom du fichier source
  
final function getLine();                 // ligne du fichier source
  
final function getTrace();                // un tableau de backtrace()
  
final function getTraceAsString();        // chaîne formattée de trace

  /* Remplacable */
  
function __toString();                    // chaîne formatée pour l'affichage
}
?>

Si une classe étend la classe Exception interne et redéfinit le constructeur, il est vivement recommandé qu'elle appelle aussi parent::__construct() pour s'assurer que toutes les données disponibles ont été proprement assignées. La méthode __toString() peut être réécrite pour fournir un affichage personnalisé lorsque l'objet est présenté comme une chaîne.

Exemple #4 Étendre la classe Exception

<?php
/**
* Définition d'une classe d'exception personnalisée
*/
class MyException extends Exception
{
  
// Redéfinissez l'exception ainsi le message n'est pas facultatif
  
public function __construct($message$code 0) {

    
// traitement personnalisé que vous voulez réaliser ...

    // assurez-vous que tout a été assigné proprement
    
parent::__construct($message$code);
  }

  
// chaîne personnalisé représentant l'objet
  
public function __toString() {
    return 
__CLASS__ ": [{$this->code}]: {$this->message}\n";
  }

  public function 
customFunction() {
    echo 
"Une fonction personnalisée pour ce type d'exception\n";
  }
}

/**
* Création d'une classe pour tester l'exception
*/
class TestException
{
  public 
$var;

  const 
THROW_NONE    0;
  const 
THROW_CUSTOM  1;
  const 
THROW_DEFAULT 2;

  function 
__construct($avalue self::THROW_NONE) {

    switch (
$avalue) {
      case 
self::THROW_CUSTOM:
        
// jète une exception personnalisé
        
throw new MyException('1 est un paramètre invalide'5);
        break;

      case 
self::THROW_DEFAULT:
        
// jète l'exception par défaut.
        
throw new Exception('2 n\'est pas autorisé en tant que paramètre'6);

        break;

      default:
        
// Aucune exception, l'objet sera créé.
        
$this->var $avalue;
        break;
    }
  }
}

// Exemple 1
try {
  
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
MyException $e) {            // Devrait être attrapée
  
echo "Capture mon exception\n"$e;
  
$e->customFunction();
} catch (
Exception $e) {              // Sauté
  
echo "Capture l'exception par défaut\n"$e;
}

// Continue l'exécution
var_dump($o);
echo 
"\n\n";


//Exemple 2
try {
  
$o = new TestException(TestException::THROW_DEFAULT);
} catch (
MyException $e) {            // Ne correspond pas à ce type
  
echo "Capture mon exception\n"$e;
  
$e->customFunction();
} catch (
Exception $e) {              // Devrait être attrapée
  
echo "Capture l'exception par défaut\n"$e;
}

// Continue l'exécution
var_dump($o);
echo 
"\n\n";


// Exemple 3
try {
  
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
Exception $e) {              // Devrait être attrapée
  
echo "Capture l'exception par défaut\n"$e;
}

// Continue l'exécution
var_dump($o);
echo 
"\n\n";


// Exemple 4
try {
  
$o = new TestException();
} catch (
Exception $e) {              // sauté, aucune exception
  
echo "Capture l'exception par défaut\n"$e;
}

// Continue l'exécution
var_dump($o);
echo 
"\n\n";
?>


Les références> <Règles de résolution de noms
Last updated: Fri, 20 Jun 2008
 
add a note add a note User Contributed Notes
Les exceptions
Tim Gallagher
08-Apr-2008 12:41
Eli had a great idea with his code, however it started spewing tons of exceptions because of notices.

Here is a slightly different one.

<?php
set_error_handler
(create_function('$x, $y', 'throw new Exception($y, $x);'), E_ALL & ~E_NOTICE);
?>
i dot crash17 at gmail dot com
05-Apr-2008 12:50
As a response to Anonymous on 28-Dec-2007 07:25, please, remember that creating lots of MyXExtension classes is wrong if and only if your object oriented model is not well designed.

One should (I even think MUST) create as many custom Exception extentions as the design needs, because every different type of exception requires (or will require, even if we haven't think about it) a different response, from showing different messages to the user, to log error messages or even kill the script.

Forwarding can become confusing if you are using a big number of classes and packages, and is useless if you are using few (unless you are too lasy to write 3, 5 or 10 includes and their respective Exception classes).

Remember that object orientation was created to give more semantics to the programming code so the programmer understands better what is written without having to excecute the code, so don't do things that go against that, which is the cool thing about object orientation.
Eli Sand
01-Apr-2008 01:55
There's been a few pieces of code already to show how to convert normal PHP errors in to exceptions, but if you want a simple single line you can put somewhere, try this:

<?php
set_error_handler
(create_function('$x, $y', 'throw new Exception($y, $x);'));
?>

It doesn't get any easier than that.  The only catch is this must be executed in the global scope.  That means you can't embed this in a class for example.  Just add it near the beginning of your entire script (where you include() files for example) and that should be it!  Just make sure to catch the exceptions thrown, or set a default exception handler.
michael dot ochs at gmx dot net
21-Mar-2008 07:44
Actually it isn't possible to do:
<?php
someFunction
() OR throw new Exception();
?>

This leads to a T_THROW Syntax Error. If you want to use this kind of exceptions, you can do the following:

<?php
function throwException($message = null,$code = null) {
    throw new
Exception($message,$code);
}

someFunction() OR throwException();
?>
chugadie dot geo at yahoo dot com
06-Mar-2008 02:40
@webmaster at asylum-et dot com

What Mo is describing is bug 44053 (http://bugs.php.net/bug.php?id=44053) in which exceptions cannot be caught if you are using a custom error handler to catch warnings, notices, etc.
webmaster at asylum-et dot com
16-Feb-2008 12:26
According to Mo PDO exeptions do not currently extend the base Exception class and will not be caught by try {...} catc...
I am unsure what version that pertains to but I am running Windows XP SP 2, Apache 2.2.4.0, PHP 5.2.5.5 and it seems to work just fine.
See the code below.
<?php
$user
='username here';
$pass='user pass here';
$dbase='database name here';
try {
 
$dbh = new PDO('mysql:host=localhost;dbname='.$dbase, $user, $pass);
  echo
'Connection opened';
} catch (
Exception $e) {
  die(
"Error!: " . $e->getMessage() . '<br/>'."\n");
}
?>
Outputs:
Error!: SQLSTATE[28000] [1045] Access denied for user 'username here'@'localhost' (using password: YES)
Error!: SQLSTATE[28000] [1045] Access denied for user 'username here'@'localhost' (using password: NO)
Error!: SQLSTATE[42000] [1049] Unknown database 'database name here'

These are exactly the errors I would expect to see so my guess is that in one of the versions between what Mo had been using and current this issue has been fixed.
Mo
30-Dec-2007 10:44
Note that PDO exceptions do not currently extend the base Exception class, and so will not be caught by:

try
{
...
} catch(Exception $e)
{
...
}

There are only two ways to handle PDO exceptions: by specifically catching PDOException, or by using an uncaught exception handler.
Anonymous
28-Dec-2007 11:25
You can catch/throw the same exception multiple times if in need of nesting (without need of creating tons of MyXExtension classes, just use as many try/catch pairs as needed:

<?php

try
{

try
{
 
// oops...
 
throw( new Exception() );
}
catch(
Exception $e )
{
  echo
"we deal with his fault here...";
 
// and forward it
 
throw( new Exception() );
}

}
catch(
Exception $e )
{
  echo
"Gotcha again";
}

?>

so if you just need to broadcast the exception till it reach your structure, you may try the above.
omnibus at omnibus dot edu dot pl
04-Dec-2007 07:11
Just to be more precise in what Frank found:
Catch the exceptions always in order from the bottom to the top of the Exception and subclasses class hierarchy. If you have class MyException extending Exception and class My2Exception extending MyException always catch My2Exception before MyException.

Hope this helps
Jason
14-Nov-2007 02:36
If you are wondering how to catch an include error and throw an exception, you can do so by doing:

<?php
try {
    if(!@include(
'/path/to/file.php')) {
        throw new
Exception('Failed to load blabla');
    }
}
catch(
Exception $e) {
    print
$e->getMessage();
}
?>

This is helpful for people with custom Exception handlers that need to escape the default warning.

Too bad you can't, without using this method, catch the exception..

If you insist on using require() instead, you must understand that include() and require() are identical in all ways, except that the way they handle errors - require throws E_FATAL when the file isn't found, include issues E_WARNING, that's the only difference!
frank at netventures dot com dot au
08-Nov-2007 07:43
If you are going to use multiple catches within a try-catch then do not forget the stacking order of those catches!

This is important as any classes that extend the Exception class, like MyException in example 20.3, will be caught in the Exception case. This is because your newly extended class also has a class type of Exception. This baffled me for awhile as the examples here worked but mine didn't because my first catch was trying to catch Exception.

Example:

<?php

/**
 * My1Exception extends Exception
 * My2Exception extends Exception
 */

/**
 * This will always fall in the first exception
 */
try {
    throw new
My1Exception("My fail english? That's unpossible", 69);
} catch (
Exception $e) {
    print
"Incorrect Exception";
} catch (
My1Exception $e) {
    print
"Correct Exception but I won't be here";
} catch (
My2Exception $e) {
    print
"Again, incorrect";
}

/**
 * Whereas here, the catch stacking order was changed so our throw will cascade into the correct catch
 */
try {
    throw new
My1Exception("My cat's breath smells like cat food", 69);
} catch (
My2Exception $e) {
    print
"Incorrect Exception";
} catch (
My1Exception $e) {
    print
"Correct Exception and I WILL be printed";
} catch (
Exception $e) {
    print
"Again, incorrect";
}

?>

So, ALWAYS keep the Exception catch block at the bottom, then any of the other extended exceptions that extend from Exception, then any of your other extended exceptions that extend from those extended exceptions, etc
hartym dot dont dot like dot spam at gmail dot com
18-Oct-2007 07:41
@serenity: of course you need to throw exception within the try block, catch will not watch fatal errors, nor less important errors but only exceptions that are instanceof the exception type you're giving. Of course by within the try block, i mean within every functions call happening in try block.

For example, to nicely handle old mysql errors, you can do something like this:

<?php
try
{
 
$connection = mysql_connect(...);
  if (
$connection === false)
  {
    throw new
Exception('Cannot connect do mysql');
  }

  
/* ... do whatever you need with database, that may mail and throw exceptions too ... */

  
mysql_close($connection);
}
catch (
Exception $e)
{
  
/* ... add logging stuff there if you need ... */

 
echo "This page cannot be displayed";
}

?>

By doing so, you're aiming at the don't repeat yourself (D.R.Y) concept, by managing error handling at only one place for the whole.
serenity at exscape dot org
23-Aug-2007 07:20
WOWA: You certainly do *not* need to throw an exception within the try block, that was just an example.
The only difference from JavaScript is that you need to add a class to catch (i.e. catch (Exception $e) instead of catch (e)).

Example:
<?php
try
{
       
// Code that might fail
}      
catch (
Exception $e)
{
        echo
"Caught exception: " . $e->getMessage();
       
// Or ErrorFunc(...) or whatever you'd like to do

}
?>
Jouni
20-Jun-2007 04:59
If you are having troubles with exceptions and you are using eAccelerator, it is because of an eAccelerator v. 0.9.5 bug. See http://www.eaccelerator.net/ticket/242 for more information. I posted this here so that other eAccelerator users can save their time.
peter dot goodman at gmail dot com
15-Jun-2007 10:52
I've found that exception destructors are not called unless the exception is caught.

I've created a simple solution to this problem (calling __destruct() from __toString() ) and have written up a lengthy article detailing one good use case for this method at http://ioreader.com/2007/06/14/taking-advantage-of-exceptions-in-php5/

Also, one of the useful things about using a destructor as a clean up method is that it is called at the end of a catch statement.
jon at hackcraft dot net
08-Jun-2007 08:00
Hi corrupted_wise.

Your method works, but has a disadvantage in mixing two different error-handling methods.

There is clarity to be had in just using set_error_handler or just using try...catch (I recommend the latter).

If the code you want to avoid using is further inside the same try block than the code that could throw the exception (or called by code in the same block) then it won't be called in the case of the try block being exited due to an error. Therefore there is no need to use set_error_handler.
corrupted_wise at yahoo dot com
01-May-2007 07:37
There was a certain section of my code that I needed to completely ignore if it failed.  So I trapped it all in a try/catch and utilized the set_error_message, which in essence is like a pseudo-goto clutch.  The reason for it all was if it failed during the code, I didn't want it to execute the rest of the respective section but continue outside of it.  In the hopes it might help someone else out, here's what I did.

I'm using PHP 5.2.1

<?php
....
try {
 
set_error_handler(create_function('', "throw new Exception(); return true;"));

  ...
code...

} catch(
Exception $e) {

}

restore_error_handler();
?>
jon at hackcraft dot net
25-Jan-2007 01:52
Further to dexen at google dot me dot up with "use destructors to perform a cleanup in case of exception". The fact that PHP5 has destructors, exception handling, and predictable garbage collection (if there's a single reference in scope and the scope is left then the destructor is called immediately) allows for the use of the RAII idiom.

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization and my own http://www.hackcraft.net/RAII/ describe this.
romain dot boisnard at gmail dot com
17-Jan-2007 01:43
If you need a Java-like exception with a sort of "Throwable" cause to report the whole stackTrace, you can use this class I wrote and I release under the LGPL GNU Lesser General Public Liscence.

It looks more or less like the original PHP "Exception" but you might want to change the formatting of the returned string in the two last functions. Enjoy :)

<?php
/* Author : Romain Boisnard */
/* Liscenced under the LGPL GNU Lesser General Public Liscence, report the actual liscence for details.

/* LinkedException */
// Java-like exception with a cause

class LinkedException extends Exception {
    private
$cause;
   
    function
__construct($_message = null, $_code = 0, Exception $_cause = null) {
       
parent::__construct($_message, $_code);
       
$this->cause = $_cause;
    }
   
    public function
getCause() {
        return
$this->cause;
    }
   
    public function
getStackTrace() {
        if (
$this->cause !== null) {
           
$arr = array();
           
$trace = $this->getTrace();
           
array_push($arr, $trace[0]);
            unset(
$trace);
            if (
get_class($this->cause) == "LinkedException") {
                foreach (
$this->cause->getStackTrace() as $key => $trace) {
                   
array_push($arr, $trace);
                }
            }
            else {
                foreach (
$this->cause->getTrace() as $key => $trace) {
                   
array_push($arr, $trace);
                }
            }
            return
$arr;
        }
        else {
            return
$this->getTrace();
        }
    }
   
    public function
showStackTrace() {
       
$htmldoc = "<p style=\"font-family: monospace; border: solid 1px #000000\"><span style=\"font-weight: bold; color: #000000;\">An exception was thrown :<br/></span>";
       
$htmldoc.= "Exception code : $this->code<br/>";
       
$htmldoc.= "Exception message : $this->message<br/>";
       
$htmldoc.= "<span style=\"color: #0000FF;\">";
       
$i = 0;
        foreach (
$this->getStackTrace() as $key => $trace) {
           
$htmldoc.= $this->showTrace($trace, $i);
           
$i++;
        }
       
$htmldoc.= "#$i {main}<br/>";
        unset(
$i);
       
$htmldoc.= "</span></p>";
        return
$htmldoc;
    }
   
    private function
showTrace($_trace, $_i) {
       
$htmldoc = "#$_i ";
        if (
array_key_exists("file",$_trace)) {
           
$htmldoc.= $_trace["file"];
        }
        if (
array_key_exists("line",$_trace)) {
           
$htmldoc.= "(".$_trace["line"]."): ";
        }
        if (
array_key_exists("class",$_trace) && array_key_exists("type",$_trace)) {
           
$htmldoc.= $_trace["class"].$_trace["type"];
        }
        if (
array_key_exists("function",$_trace)) {
           
$htmldoc.= $_trace["function"]."(";
            if (
array_key_exists("args",$_trace)) {
                if (
count($_trace["args"]) > 0) {
                   
$args = $_trace["args"];
                   
$type = gettype($args[0]);
                   
$value = $args[0];
                    unset(
$args);
                    if (
$type == "boolean") {
                        if (
$value) {
                           
$htmldoc.= "true";
                        }
                        else {
                           
$htmldoc.= "false";
                        }
                    }
                    elseif (
$type == "integer" || $type == "double") {
                        if (
settype($value, "string")) {
                            if (
strlen($value) <= 20) {
                               
$htmldoc.= $value;
                            }
                            else {
                               
$htmldoc.= substr($value,0,17)."...";
                            }
                        }
                        else {
                            if (
$type == "integer" ) {
                               
$htmldoc.= "? integer ?";
                            }
                            else {
                               
$htmldoc.= "? double or float ?";
                            }
                        }
                    }
                    elseif (
$type == "string") {
                        if (
strlen($value) <= 18) {
                           
$htmldoc.= "'$value'";
                        }
                        else {
                           
$htmldoc.= "'".substr($value,0,15)."...'";
                        }
                    }
                    elseif (
$type == "array") {
                       
$htmldoc.= "Array";
                    }
                    elseif (
$type == "object") {
                       
$htmldoc.= "Object";
                    }
                    elseif (
$type == "resource") {
                       
$htmldoc.= "Resource";
                    }
                    elseif (
$type == "NULL") {
                       
$htmldoc.= "null";
                    }
                    elseif (
$type == "unknown type") {
                       
$htmldoc.= "? unknown type ?";
                    }
                    unset(
$type);
                    unset(
$value);
                }
                if (
count($_trace["args"]) > 1) {
                   
$htmldoc.= ",...";
                }
            }           
           
$htmldoc.= ")<br/>";
        }
        return
$htmldoc;
    }
}
?>
dexen at google dot me dot up
18-Sep-2006 09:45
Summary:
 * use destructors to perform a cleanup in case of exception.

PHP calls method __destruct()  on instance of class when variable storing the instance goes out-of-scope (or gets unset). This works for function leave by Exception, aside of plain return. (same as for C++, AFAIK)

aFunction() {
$i = new LockerClass();
throw new MinorErrorEx('Warn user & perform some other activity');
// $i->__destruct() gets called before stack unwind begins, unlocking whatever get locked by new LockerClass();
 return $bar;
}

(A lengthy) example:

Let's say you need to perform a series of operaions on SQL database that should not get disrupted. You lock the tables:
<?php
function updateStuff() {
   
DB::query('LOCK TABLES `a`, `b`, `c` WRITE');
   
/* some SQL Operations */
   
someFunction();
   
/* more SQL Operations */
   
DB::query('UNLOCK TABLES');
}
?>

Now, let's supouse that someFunction() may throw an exception. This would leave us with the tables locked, as the second DB::query() will not get called. This pretty much will cause the next query to fail. You can do it like:
<?php
function updateStuff() {
   
DB::query('LOCK TABLES `a`, `b` WRITE');
   
/* some SQL Operations */
   
try {
       
someFunction(); }
    catch (
Exception $e ) {
       
DB::query('UNLOCK TABLES');
        throw
$e;
    }
   
/* more SQL Operations */
   
DB::query('UNLOCK TABLES')
}
?>

However, this is rather ugly as we get code duplication. And what if somebody later modifies updateStuff() function in a way it needs another step of cleanup, but forget to add it to catch () {}? Or when we have multiple things to be cleaned up, of which not all will be valid all the time?
 
My solution using destructor: i create an instance of class DB holding a query unlocking tables which will be executed on destruction.

<?php
function updateStuff() {
   
$SQLLocker = DB::locker( /*read lock list*/array('a', 'b'), /*write lock list*/array('b') );
   
/* some SQL Operations */
   
someFunction();
   
/* $SQLLocker gets destructed there if someFunction() throws an exception */
   
DB::query('UNLOCK TABLES');
   
/* other SQL Operations */
    /* $SQLLocker gets destructed there if someFunction() does not throw an exception */
}

class
DB {
    function
locker ( $read, $write ) {
       
DB::query( /*locks*/);
       
$ret = new DB;
       
$ret->onDestruct = 'UNLOCK TABLES';
        return
$ret;
    }

    function
_destructor() {
        if (
$this->onDestruct )
           
DB::query($this->onDestruct);
    }
}
?>
jazfresh at hotmail.com
08-Aug-2006 01:18
Sometimes you want a single catch() to catch multiple types of Exception. In a language like Python, you can specify multiple types in a catch(), but in PHP you can only specify one. This can be annoying when you want handle many different Exceptions with the same catch() block.

However, you can replicate the functionality somewhat, because catch(<classname> $var) will match the given <classname> *or any of it's sub-classes*.

For example:

<?php
class DisplayException extends Exception {};
class
FileException extends Exception {};
class
AccessControl extends FileException {}; // Sub-class of FileException
class IOError extends FileException {}; // Sub-class of FileException

try {
  if(!
is_readable($somefile))
     throw new
IOError("File is not readable!");
  if(!
user_has_access_to_file($someuser, $somefile))
     throw new
AccessControl("Permission denied!");
  if(!
display_file($somefile))
     throw new
DisplayException("Couldn't display file!");

} catch (
FileException $e) {
 
// This block will catch FileException, AccessControl or IOError exceptions, but not Exceptions or DisplayExceptions.
 
echo "File error: ".$e->getMessage();
  exit(
1);
}
?>

Corollary: If you want to catch *any* exception, no matter what the type, just use "catch(Exception $var)", because all exceptions are sub-classes of the built-in Exception.
linus at flowingcreativity dot net
20-Jul-2006 05:06
Here is a basic example of a way to mimick the convenience of exception handling in PHP4:

<?php

do {
    if (!
$test_condition) {
       
$error = 'test condition failed';
        break;
    }
   
    if (!
test_function()) {
       
$error = 'test function failed';
        break;
    }
   
    echo
'success!';
   
} while (
false);

if (isset(
$error)) {
    echo
$error;
}

?>

Obviously this falls far short of PHP5 real exception handling in terms of normalisation.  Also, $error won't propogate up the call stack like a real exception (i.e. test_function() can't itself throw an exception, nor call 'break').  But for me, the most important thing about exception handling is to be able to run through code and deal with errors separately, and not have to have a million nested IFs.  Compare that code to this:

<?php

if (!$test_condition) {
   
$error = 'test condition failed';
} elseif (!
test_function()) {
   
$error = 'test function failed';
} else {
    echo
'success!';
}

if (isset(
$error)) {
    echo
$error;
}

?>

At first this seems no more cumbersome, but what if test_function took arguments that required complicated preparation?  You would need a mess like this:

<?php

if (!$test_condition) {
   
$error = 'test condition failed';
} else {
   
$fooRes = mysql_query('SELECT foo FROM bar LIMIT 1');
   
$fooRow = mysql_fetch_assoc($fooRes);
   
    if (!
test_function($fooRow)) {
       
$error = 'test function failed';
    } else {
        echo
'success!';
    }
}

?>

Obviously this could get out of hand quickly.  In the first example, you can just prepare the argument before the 'if (!test_function($fooRow))', and on the same nesting level.

This method is also somewhat more flexible in that you can generate 'exceptions', and then deal with them much later (which may be desirable if they aren't really threatening).  In PHP5, a catch block must always follow a try block directly.
tatarynowicz at gmail dot com
10-Jul-2006 09:26
Carlos Konstanski: You can't directly extract previous lexical environment in non-functional languages.

What you probably _can_ do is to create a function that dumps the current lexical environment (to an external file or to stdout) and then use it to recreate past states.

function log_lex ($vars, $functions) {
  $f = fopen('lex_env.log', 'a');
  fwrite($f, serialize(array($vars, $functions, get_defined_constants(), debug_backtrace()));
  fclose($f);
}

log_lex (get_defined_vars(), get_defined_functions());

Writing the parser/browser for dumps is the difficult part. Then just sprinkle the code with log_lex() and see how the program runs.

Sure, it works better in Lisp, but Lisp isn't supported on the webservers I work with, and making PHP more like Lisp would probably make it as popular as Lisp is.
14-May-2006 07:49
@armenio at inmidiaweb dot com dot br:
When echoing into JavaScript code must use htmlspecialchars(addslashes($this->msg)) - think what would happen if msg was "')</script>";
armenio at inmidiaweb dot com dot br
11-May-2006 04:23
<?php
class alert{
   
    public
$return;
    public
$msg;
   
    public function
__construct($value){
       
$this->msg = $value;
    }
    public function
OutPut(){
       
$this->return  = '<script language="JavaScript">';
       
$this->return .= '    alert("'.$this->msg.'")';
       
$this->return .= '</script>';
        return
$this->return;
    }
}
$msg = new alert('classe criada com sucesso');
$msg->OutPut();
?>
fjoggen at gmail dot com
27-Apr-2006 04:58
This code will turn php errors into exceptions:

<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
    throw new
ErrorException($message, 0, $severity, $filename, $lineno);
}

set_error_handler('exceptions_error_handler');
?>

However since <?php set_error_handler()?> doesn't work with fatal errors, you will not be able to throw them as Exceptions.
gerry03 at 4warding dot com
14-Nov-2005 01:39
Good PHP5 article about exceptions. I have read quite a few now and this is the only one I've liked:

http://www.andreashalter.ch/phpug/20040115/
Carlos Konstanski
30-Sep-2005 01:17
Being able to catch the exception up the call stack from where it is thrown is a good idea, in that it lets you handle the exception closer to where it ought to be handled - in the calling code.  Not as good as common lisp though, where you can call a condition handler that resides up the stack without actually unwinding the stack.  With this additional feature, you have the lexical environment at the point where the exception occured, combined with the relocation of the handler to a place where the lower-level function's failure can be addressed from the standpoint of the calling code.

Even so, this fluke of PHP that lets you place the try...catch block up the stack from the actual point of error could be used to implement a neat shift in error-handling architecture, where the caller gets to decide how to proceed after an error.
jd at wuputah dot com
07-May-2005 10:15
PHP5 supports exception throwing inside a function, and catching it outside that function call. There is no mention of this in documentation but it works just fine, as tested by this sample code:

<?php

function exceptionFunction() {
        throw new
Exception("Throwing an exception!");
}

try {
       
exceptionFunction();
} catch (
Exception $e) {
        echo
"Exception caught!\n";
}

?>

The result in PHP 5.0.3 is "Exception caught!"

Further tests show that nested functions with exceptions, methods throwing exceptions, etc all work the same way. This is like declaring all classes (or methods) in Java as "class ClassName throws Exception". While I consider this a good thing, you should be aware that any thrown exception will propagate up your stack until it is either caught or runs out of stack.
ravindra at gatewaytechnolabs dot com
29-Oct-2004 04:34
<?php
/*I add here example for nested Exception Handling.*/
 
try
 {
   try
   {
     throw new
exception();
   }
   catch(
exception $m)
   {
    print
$m;
    print
"<br>";
    print
"inner exception"."<br>";
   }
   throw new
exception();
 }
 catch(
exception $e)
 {
  print
$e;
  print
"outer exception";
 }
 
?>
gomikochar at yahoo dot com
10-Oct-2004 10:00
To re-throw an exception, you must specify the name of the variable after throw in the catch block, i.e.,

<?php

try {
  try {
    throw new
Exception("Unknown error");
  }
  catch (
Exception $ie) {  // Inner Catch Block
   
throw;  // this will NOT work; parse error
   
throw $ie// this will re-throw the exception to the outer catch block
 
}
}
catch (
Exception $oe) {  // Outer Catch Block
 
echo $oe;
}

?>
php5 at grapio dot nl
07-Oct-2004 09:16
The base exception class, which is build in PHP5 has also a function getLine(). This is as expected if you look at the class define. But it is not noticed there.
I had just this code:
<?php
try
{
     throw new
Exception("test")
}
catch (
Exception $e)
{
  echo
$e->getLine()
}
?>
And this worked.
ravindra at gatewaytechnolabs dot com
01-Oct-2004 07:23
Like Java php5 also supports nesting of try catch.
moirae at centrum dot cz
21-Aug-2004 09:16
Really good article about exceptions in php5: http://www.zend.com/php5/articles/php5-exceptions.php

Les références> <Règles de résolution de noms
Last updated: Fri, 20 Jun 2008
 
 
show source | credits | sitemap | contact | advertising | mirror sites