Throwing Exceptions in PHP

Throwing a generic exception is almost as simple as it sounds. All it takes is to instantiate an exception object—with the first parameter of the Exception constructor being the error message—and then, "throw" it.

throw new \Exception('Exception message')

The most important thing to take note of is the message. Defined in the constructor, and accessed via the getMessage() method, the message is the human-readable error that can often be related to the end user.

The Exception class

To more effectively utilize exceptions within your application, it is important to understand how to create and throw your own. But before we get into throwing custom exceptions, let's first take a look at what an exception is under the hood, and how to define your own, starting with the global Exception class that all PHP exceptions stem from:

class Exception {
    protected $message = 'Unknown exception';   // exception message
    private   $string;                          // __toString cache
    protected $code = 0;                        // user defined exception code
    protected $file;                            // source filename of exception
    protected $line;                            // source line of exception
    private   $trace;                           // backtrace
    private   $previous;                        // previous exception if nested exception

    public function __construct($message = null, $code = 0, Exception $previous = null);

    final private function __clone();           // Inhibits cloning of exceptions.

    final public  function getMessage();        // message of exception
    final public  function getCode();           // code of exception
    final public  function getFile();           // source filename
    final public  function getLine();           // source line
    final public  function getTrace();          // an array of the backtrace()
    final public  function getPrevious();       // previous exception
    final public  function getTraceAsString();  // formatted string of trace

    // Overrideable
    public function __toString();               // formatted string for display
}

As we can see from the definition above, every built-in exception includes a few configurable properties: an exception message, an exception code, the source filename of the exception, and the line number of the exception in the source file. This information is what is used to create a human-readable—and diagnosable—exception object.

Throwing custom exceptions

At their core, every exception is an extension of the global Exception class. What this means is that creating a custom exception, in its most basic form, requires only a class that extends the built-in Exception class.

namespace Custom;

class Exception extends \Exception { }

With this custom exception created, we can then throw it as we would any other exception:

throw new \Custom\Exception('Exception message');

The advantage to inheriting from the built-in Exception class is that we can extend the core functionality of default exceptions. By overriding class properties like code, file, line, and message or the __toString() method, we can coerce the exception data into a format we can work with.

namespace Custom;

class Exception extends \Exception {
  protected $details;
  
  public function __construct($details) {
      $this->details = $details;
      parent::__construct();
  }
  
  public function __toString() {
    return 'I am an exception. Here are the deets: ' . $this->details;
  }
}

Writing to the error log

Outside of exception throwing, PHP also supports writing directly to the error log (more about that in Where are PHP Errors Logged?). The aptly named error_log function can be used to write raw messages to the error log without interrupting program execution. This is useful when you need to track debug data or keep track of caught and handled exceptions.

bool error_log ( string $message [, int $message_type = 0 [, string $destination [, string $extra_headers ]]] )

Depending on the $messagetype, errorlog generally only requires one parameter: a message. While the other parameters can be used to direct where the error message should go, the most common use case is to use the default options to write directly to PHP's system logger.