PHP Exception | Create your own Custom Exception Class

PHP Exception | Create our own Custom Exception Class
PHP Exception | Create our own Custom Exception Class

In our previous post, we saw how to handle Exception in PHP where we found that there are so many inbuilt Exceptions available, and based on the importance we used them in the different parts of the code. In this tutorial, we will see how we can create our own custom Exception class OR User defined Exception class.

But before moving ahead, we must have noticed that all these exceptions extend to the Exception class which is considered as the parent class, and based on that other child Exception classes are created and are used based on their importance.

Let’s see the built-in class Exception class (Reference php.net site) first and various properties and methods defined in it and then we’ll create our custom class.

<?php
class Exception extends Throwable
{
    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, Throwable $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, all the properties defined in the Exception class are either having protected or private access modifiers. This means that $message, $code, $file & $line properties are available to exception & it’s child classes.

On the other hand, private members $string, $trace & $previous variables can be accessed & modified by Exception class only and not by any other classes.

All the methods defined are final. This indicates that no method is allowed to override in the child class. But we can create our own custom method in the child class.

Now, let’s see how we can create our own custom exception class-

There is only one basic syntax to create it-

class CustomException extends Exception {}

Let’s start creating our custom Exception class. First, we’ll create a custom exception class and then will see different components inside it.

create our first own custom Exception class

<?php

class CustomException extends Exception
{

    public function __construct($message, $code = 0, Exception $previous = null) {
        parent::__construct($message, $code, $previous);
    }

    public function customMessage() {
        echo "Custom Message will go here\n";
    }
}

Here, we extended our CustomException class to Exception class and defined constructor which eventually calls parent constructor. As mentioned above we can also define our method inside this class like customMessage() here.

Let’s create a complete working example and then we’ll see it line by line.

<?php

class FileNotReadableException extends Exception
{
    private $fileWithError = '';

    public function __construct(string $fileName)
    {
        $this->fileWithError = $fileName;
        parent::__construct("The provided file could not be read.");
    }

    public function customMessage()
    {
        echo "File with Error While Reading is- {$this->fileWithError} \n";
    }
}

class HandleFileOperation
{

    public function checkFileIsReadable($file)
    {
        if (!is_readable($file)) {
            throw new FileNotReadableException($file);
        } else {
            // process file
        }
    }
}

$objCustomException = new HandleFileOperation();

try {

    $objCustomException->checkFileIsReadable("processFile.php");
} catch (FileNotReadableException $e) {

    echo $e->customMessage();
}

As we can see, checkFileIsReadable() function of HandleFileOperation class throws an exception when the file provided to it is not readable. Inside FileNotReadableException class we have defined our custom function named customMessage(). We can call this function to show a custom message on the screen rather than the predefined one in the parent class Exception.

Now, it is not absolutely necessary to create instance method inside the newly created custom exception class. We can also create static method in it and call it whenever necessary.

<?php

class FileNotReadableException extends Exception
{
    private static $fileWithError = 'Default';

    public function __construct(string $fileName)
    {
        self::$fileWithError = $fileName;
        parent::__construct("The provided file could not be read.");
    }

    public static function customMessage()
    {
        echo "File with Error While Reading is- " . self::$fileWithError . " \n";
    }
}

class HandleFileOperation
{

    public function checkFileIsReadable($file)
    {
        if (!is_readable($file)) {
            throw new FileNotReadableException($file);
        } else {
            // process file
        }
    }
}

$objCustomException = new HandleFileOperation();

try {

    $objCustomException->checkFileIsReadable("processFile.php");
} catch (FileNotReadableException $e) {

    echo FileNotReadableException::customMessage();
}

Above code will execute and will give same output like the previous example. Only difference is that we used here static methodolgy to write our code and tried to get the advantages of static.

Now, if you worked on modern framewporks like Laravel, Symfony then you must have seen tons of custom build exceptions. Like in symfony few examples are- AuthenticationException, AuthorizationException, BadResponse, BadMethodCallException, SecurityException etc.

Let’s understand the reason behind creating authentication exception and different methods defined inside it.

This exception is used inside authenticate middlware and if current user is unauthenticated then user will be presented with this exception. This exception is thrown inside unauthenticated() method which is defined as protected because based on the requirements we can modify the method inside child class by defining this method. This gives us more flexibility to write our authentication class by extending to this Authenticate class.

Conclusion:-

Exceptions are the powerful mechanism to handle all the errors in the runtime. As mentioned with above information, it can be occurred with many reasons. So handling at the time of writing code is the proficient way to halt unexcepted error to occur.