Building an Error Logger with the Chain of Responsibility Pattern in PHP 5

If you’re one of those PHP developers that wants to expand your background in pattern-based programming, then this article may suit your needs. Welcome to the second part of the series “Understanding the Chain of Responsibility Between PHP Objects.” Comprised of three installments, this series goes through the basics of building a chain of responsibility across several PHP objects, and teaches you how to apply this pattern by using copious code samples.

Introduction

As you’ll remember, over the course of the first article I provided you with a friendly introduction to creating a well-defined chain of responsibility between certain PHP classes. It demonstrated how a given object can delegate the execution of a specific task to its parent when it can’t handle the problem via its own methods.

Although this important concept was illustrated by using some basic classes that certainly can’t be used in real conditions, hopefully the experience was good enough to teach you how the chain of responsibility model can be successfully implemented with PHP. Once the logic that stands behind this pattern is mastered, translating it to a more useful context is much simpler.

Keeping in mind the practical side of the subject, in this second tutorial of the series, I’ll be covering the development of a custom error logging system, which also implements a chain of responsibility across its different classes to log errors to distinct modules.

In response to this experience, at the end of this article you should be equipped with more robust knowledge of how to create a responsibility chain between PHP objects that perform truly useful tasks, like logging errors to specific components of a Web application.

Having established the goal of this article, let’s move forward and learn together how this pattern can be applied in a real world situation. Let’s go!

{mospagebreak title=Setting up the foundations of an error logger}

In order to start building the error logging system that I mentioned in the beginning, first I’ll create a pair of classes that will sit on top of the responsibility chain. They’ll be responsible for defining the blueprints for all the eventual sub classes that will be derived from them.

Obviously, any potential errors that can’t be logged by the corresponding child modules will be delegated to the respective parent, in this way implementing the so-called chain of responsibility. That being said, here is the signature for the first couple of base classes that I mentioned before:

// define abstract ‘AbstractErrorLogger’ class on top of the
responsibility chain
abstract class AbstractErrorLogger{
    abstract public function setErrorLogger($errorLogger);
    abstract public function getErrorLogger();
    abstract public function logError();
}
// define concrete ‘ErrorLogger’ class
class ErrorLogger extends AbstractErrorLogger{
    private $errorLogger;
    public function __construct(){
        $this->errorLogger=NULL;
    }
    // get error logger
    public function getErrorLogger(){
        if($this->errorLogger==NULL){
            throw new Exception(‘No error logger has been set!’);
        }
        return $this->errorLogger;
    }
    // set error logger
    public function setErrorLogger($errorLogger){
        $this->errorLogger=$errorLogger;
    }
    public function logError(){}
}   

If you examine the respective definitions of the classes listed above, then you’ll understand quickly what they do. Basically, the first base class has been declared abstract, and in accordance with this concept, defines the generic structure of any error logger sub class that may be potentially derived from it.

With reference to the second class, it implements in a concrete way many of the methods declared in its abstract parent, except for the one called “logError().” Nevertheless, I want you to turn your attention to the logic followed by the “getErrorLogger()” method. As you can see, it defines the top of the responsibility chain; if an appropriate error logger isn’t found (represented by the condition $this->errorLogger==NULL), it simply throws an exception and the program’s execution is eventually halted.

Clearly, the behavior exposed by the previous class is a notorious sign that there must be other error loggers that need to be created to define the lower levels of the corresponding responsibility chain.

Based upon this premise, and after defining the structure of the generic error logger that you saw before, the next step consists of precisely deriving a new sub class from the base class in question. Therefore, the chain of responsibility can be provided with an extra module which will be tasked with logging specific errors.

To see how this brand new error logger will be defined, click on the link below and keep reading.

{mospagebreak title=Logging specific errors at a lower level}

As was explained in the previous section, to construct a new error logger that will be focused only on registering specific events, it’s necessary to derive another class from the highly generic “ErrorLogger.”

As you may guess, this new class will be responsible for handling all the errors occurring only inside its scope. In addition, in accordance with the logic implemented by the corresponding chain of responsibility, the class will delegate program control to its nearest parent, in this case represented by the “ErrorLogger” class, if a particular error can’t be handled properly.

More specifically, since I want this new class to be focused on registering all the errors that happen when validating an email address, I called it “MailErrorLogger.” Its definition is as follows:

// define ‘MailErrorLogger’ class
class MailErrorLogger extends ErrorLogger{ 
    private $errorLogger; 
    private $parentErrorLogger; 
    public function __construct(ErrorLogger $parentErrorLogger){ 
        $this->errorLogger=NULL; 
        $this->parentErrorLogger=$parentErrorLogger; 
    } 
    // get error logger 
    public function getErrorLogger(){ 
        if($this->errorLogger==NULL){ 
            // call parent object in chain of responsibility 
            return $this->parentErrorLogger->getErrorLogger(); 
        } 
        else{ 
            return $this->errorLogger; 
        } 
    } 
    // set error logger 
    public function setErrorLogger($errorLogger){ 
        if($errorLogger!=’Email Error Logger’){ 
            throw new Exception(‘Invalid error logger’); 
        } 
        $this->errorLogger=$errorLogger; 
    } 
    // log error by email to system administrator 
    public function logError(){ 
        mail(‘sysadmin@domain.com’,’Message from: ‘.$this-
>getErrorLogger(),’An error occurred when validating email
address!’);
    }
}

As shown above, the “MailErrorLogger” class has been provided with a basic ability, handy for logging all the eventual errors raised when checking an email address. In particular, the “logError()” method performs the error logging process by notifying the system administrator when this type of failure occurs, something clearly demonstrated by its corresponding definition.

Also, it should be noticed how the “getErrorLogger()” method implements, in an efficient way, the corresponding chain of responsibility: if there’s a situation when an appropriate error logger can’t be retrieved, this task is simply transferred to its parent, that is the pertinent “ErrorLogger” class. Now do you understand how the chain of responsibility really works here? I’m sure you do!

The remaining class methods speak for themselves, therefore I’ll spend no time explaining how they work. Instead, once the previous “MailErrorLogger” class has been correctly defined, I’d like to show you a concrete example where this error logging class can be used with fairly good results.

That being said, over the next few lines I’ll be demonstrating how the “MailErrorLogger” class can be utilized in conjunction with an email checking system to log errors when a specified email address fails to pass the verification process.

Want to find out how this will be done? Go ahead and read the following section.

{mospagebreak title=Logging email-related errors}

If you’re anything like me, then I’m sure that you want to see how the prior “MailErrorLoger” class works in a real situation. Therefore I coded a new sample class (shown below) which essentially performs a decent validation on a given email address that has been previously inputted via its constructor.

That said, the definition for the email checking class looks like this:

// define ‘EmailValidator’ class
class EmailValidator{ 
    private $email; 
    private $mailErrorLogger; 
    public function __construct($email,ErrorLogger
$mailErrorLogger){
        $this->mailErrorLogger=$mailErrorLogger; 
        if(!preg_match("/^.+@.+$/",$email)){ 
            $this->mailErrorLogger->logError(); 
        } 
        $this->email=$email; 
    } 
    // validate email 
    public function validate(){ 
        if(!$this->windnsrr(array_pop(explode("@",$this-
>email)))){
            $this->mailErrorLogger->logError(); 
        } 
    } 
    // check for MX records in the DNS (Windows-based systems) 
    private function windnsrr($hostName,$recType=”){ 
        if(!$hostName){ 
            if($recType==”)$recType="MX"; 
            exec("nslookup -type=$recType $hostName",$result); 
            foreach($result as $line){ 
                if(preg_match("/^$hostName/",$line)){ 
                    return true; 
                } 
            } 
            return false; 
        } 
        return false; 
    }
}

As shown above, the “EmailValidator” class has been provided with a single method, not surprisingly called “validate(),” which comes in very handy for checking whether a given email address is valid or not. This method runs only on Windows-based systems, but it can be easily modified to extend its range of utilization to other operating systems.

Additionally, it should be noticed that this email checking class accepts an error logger object as one of its input parameters (the other is the email address for validation), which is very convenient for registering errors when a particular email address is considered invalid. As you’ll realize, this process is performed inside the respective “validate()” method, and certainly is very easy to follow.

All right, at this point I think that you grasped the logic that drives the “EmailValidator” class. Let me show you a group of code samples which will demonstrate how this validation mechanism can be used in conjunction with the “MailErrorLogger” class that you learned in the previous section.

In these examples, if a given email address is considered not valid, and an error logger isn’t passed to the email error logging class, then this class will transfer this condition to its parent so that the failure can be appropriately handled. After all, this is how the chain of responsibility works, right?

Now, take a look at the scripts below:

try{
    // instantiate ‘ErrorLogger’ object 
    $errorLogger=new ErrorLogger(); 
    // validate email without providing an error logger 
    $errorLogger->getErrorLogger(); 
    /* displays the following:
 
    No error logger has been set!
 
    */
}
catch(Exception $e){ 
    echo $e->getMessage(); 
    exit();

try{ 
    // instantiate ‘ErrorLogger’ object 
    $errorLogger=new ErrorLogger(); 
    // instantiate ‘EmailErrorLogger’ 
    $mailErrorLogger=new MailErrorLogger($errorLogger); 
    // instantiate ‘EmailValidator’ object 
    $emailValidator=new EmailValidator
(‘username@domain.com’,$mailErrorLogger);
    $emailValidator->validate();
    /* displays the following:

    No error logger has been set!

    */
}
catch(Exception $e){ 
    echo $e->getMessage(); 
    exit();
}

try{
    // instantiate ‘ErrorLogger’ object 
    $errorLogger=new ErrorLogger(); 
    // provide an error logger 
    $mailErrorLogger=new MailErrorLogger($errorLogger); 
    $mailErrorLogger->setErrorLogger(‘Email Error Logger’); 
    $emailValidator=new EmailValidator
(‘username@domain.com’,$mailErrorLogger);
    $emailValidator->validate();
}
catch(Exception $e){ 
    echo $e->getMessage(); 
    exit();
}

As you can see, the first two code snippets show what happens when a particular error logger hasn’t been defined. In the first case, since none of the pertinent child classes have been instantiated, the parent class handles this situation by throwing an exception and halting the script’s execution.

The second example is slightly more interesting, due to the fact that a “MailErrorLogger” object is created, but no error logger is defined via its “setErrorLogger()” method. This condition is also transferred to the parent, which triggers a new exception.

The last example shows a case where the correct error logger has been set, therefore the inputted email address can be appropriately verified by the corresponding “validate()” method, and the responsibility for logging errors rests only on the proper “MailErrorLogger” object.

As you’ll realize, when all the previous classes work together, the chain of responsibility schema really works. I suggest you try modifying the above examples and examine the results that you obtain in each situation.

Wrapping up

In this second article of the series, I provided you with a more useful example of how to implement a chain of responsibility across a pair of PHP classes, in order to build an error logger system.

However, this journey isn’t finished yet. In the last article, I’ll show you how to expand the error logger mechanism that you learned here, by adding more elements to the existing responsibility chain. You won’t want to miss it!

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort