views:

60

answers:

4

Hi everyone, i am trying to understand the use of exceptions in PHP.. How they work and when to use them... The basic structure below, is the the correct method.. It seems somewhat bloated to me?

Thanks in advance for any advise or help..

<?php

class APIException extends Exception 
{
    public function __construct($message)
    {
        parent::__construct($message, 0);
    }

    public function __toString()
   {
        echo('Error: ' . parent::getMessage());
    }

   public function __toDeath()  
   {
      die("Oops: ". parent::getMessage());
   }
}

?>

<?php

require_once('exception.class.php');

class auth extends base
{
   /* 
    * User functions 
    */ 

   public function user_create($args='')
   {
      try
      {
         if ( !isset($arg['username']) || !isset($arg['password']) || 
              !isset($arg['question']) || !isset($arg['answer']) )
         {
            throw new APIException('missing variables, try again');
         }
      }
      catch (APIException $e)
      {
         $e->__toString();
      }

      try
      {
         if ( $this->user_exists() ) 
         {
            throw new APIException('user already exists');
         }
      }
      catch (APIException $e)
      {
         $e->__toString();
      }
   }

   protected function user_exists($name)
   {
      // Do SQL Query 
      try
      {
         $sql = "select * from user where username='$user'";
         if (!mysql_query($sql))
         {
            throw new APIException('SQL ERROR');
         }
      }
      catch (APIException $e)
      {
         $e->__toDeath();
      }
   }
}

?>
+1  A: 

Syntax wise, that is correct.

Although your implementation does not really use them to their full potential, as your basically using them as if conditionals.

The great thing about Exceptions is that they can happen anywhere and the Exception will get thrown 'up' your code until it is caught.

So you could have a User class, with a login() method. You wrap any call to login() in a try block and then throw exceptions within the login() method. The login() method does not handle the exceptions, it only knows something has gone wrong and throws them.

Your catch block can then catch the different types of Exception and deal with them appropriately.

jakenoble
+1  A: 

No, you're not using them correctly. Take a look at this

public function user_create($args='')
{
  try
  {
     if ( !isset($arg['username']) || !isset($arg['password']) || 
          !isset($arg['question']) || !isset($arg['answer']) )
     {
        throw new APIException('missing variables, try again');
     }
  }
  catch (APIException $e)
  {
     $e->__toString();
  }
  //snip...

When you throw new APIException('missing variables, try again');, it will just be caught by catch (APIException $e).

One of the points of exceptions is so that you can tell code calling the function that something went wrong. A more proper usage might look something like this.

public function user_create($args='')
{
   if ( !isset($arg['username']) || !isset($arg['password']) || 
        !isset($arg['question']) || !isset($arg['answer']) )
   {
      throw new APIException('missing variables, try again');
   }
  //snip...
// elsewhere
try {
  $foo->user_create('bar');
} catch(APIException $e) {
  // handle error here
  // log_error($e->getCode(), $e->getMessage());
}

Notice that the you use the try/catch block when you call user_create. Not within user_create.

haydenmuhl
+1  A: 

Never use Exceptions where you expect something could go wrong.

For instance:

$sql = "select * from user where username='$user'";
if (!mysql_query($sql))
{
    throw new APIException('SQL ERROR');
}

You know very well that the user could not be found (and shame on you for creating such horrible unescaped sql!!), so exceptions are NOT to be used there.

Now:

if (!(mysql_connect($hostname, $user, $pass)))
{
    throw new Exception("Can't connect to db!");
}

is valid because you honestly wouldn't expect to not be able to connect to the DB.

Exceptions are meant to give you more than just die prompts, and are meant to be used with "pretty error messages", at the very least:

try
{
    // Run my Entire App 
}
catch (Exception $e)
{
    // Catch every exception, give them my pretty 404 page with a kinder explanation than a white screen or weird programming error message.
    $error = $e->getMessage();
    include '404.tpl.php';
}

They excel at giving you backup options:

try
{
    // Let's try to log in the user:
    login($user, $pass);
}
catch (Exception $e)
{
    // Let's log them in as a guest, then...
    login('guest', 'nobody');
}

Even that contradicts the point above; an if should be used in this place.

hopeseekr
A: 

I've asked around a bit, and there seems to be no agreed-upon rules as to why and when to use exceptions. People will say things about 'use them in exceptional circumstances', or 'use them for something you don't expect' - I don't think these answers provide any particular guidance as far as when or where to use them. It seems to be only personal opinion. I would love to see a reasonable, objective standard, but I suspect it doesn't exist.

So personally, I use them in all my classes to make sure that I deal with the situation ( if I don't, I get big ugly 'uncaught exception' messages on my screen), and code execution does not continue in that method. I also use them to enforce types in argument variables. The execution of a method stops upon an exception, and since most PHP objects don't live through a page load, there isn't much sense in advanced error-checking. Just let them blow up with an exception, catch it, and give the user an error message so they can provide you with some feedback to correct the situation.