Expanding an Error Logger with the Chain of Responsibility Pattern

Do you want to know how to build an error logging system using the chain of responsibility schema with PHP? If your answer is a loud yes, then in this group of articles you’ll find what you’ve been looking for! Welcome to the concluding part of the series “Understanding the chain of responsibility between PHP objects.” This set of three tutorials shows you how to define a specific chain of responsibility that involves several PHP objects, and applies this concept to creating an expandable error logging mechanism.

After introducing you to the subject of this series, I’d like to step back quickly to the previous tutorial and recall the topics covered in it. This will make it a bit easier for you to grasp the concepts that I plan to explain in this final part.

As you’ll possibly remember, in the previous article I went through the development of a comprehensive error logging system. It used the chain of responsibility pattern to establish the scope of where each involved PHP class should act.

By following this approach, it was feasible to create an error handling mechanism where every component was initially provided with a limited capacity for processing a particular failure — and when the error in question couldn’t be properly handled, it would be immediately transferred to the corresponding parent module.

Indeed, if you reread the above paragraph, it should be clear to you what a chain of responsibility is all about: once a group of hierarchically organized classes have been created, the responsibility for handling a given task is moved from the bottom to the top of the stack structure. Sounds good, doesn’t it?

Now, paying attention to the topics that will be covered in this tutorial, what you’ll learn here will consist essentially of applying the chain of responsibility schema to expand the capacity of the error logging system that was developed  previously.

Are you intrigued about how this will done? Then click the link below and keep reading!

{mospagebreak title=The error logging system’s responsibility chain}   

As I explained earlier, this final article will be focused on extending the functionality of the error logging system that I created in the previous part by applying a proper chain of responsibility schema.

Since this sounds pretty simple, I’ll start listing the base error logging classes, which sit on top of the mentioned responsibility chain. Here is the signature of the two classes that I referenced above:

// 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(){}
}

As you’ll possibly remember, the above two error logging classes establish the top of the corresponding responsibility chain, from which all the eventual subclasses will be derived. Basically, the first abstract class defines the generic model of any possible error logger, while the second one implements concretely most of the abstract methods declared previously.

So far, the respective definitions of the above base classes aren’t difficult to understand. However, it’s worthwhile to stress here the way that the “getErrorLogger()” method works. As you can see, this method sets up the top of the responsibility chain when handling an error, because if the appropriate error logger  has not been defined (represented by the condition $this->errorLogger==NULL), then it throws an exception and program execution will be eventually halted.

From this point on, all the sub classes created from the previous “ErrorLogger” class will stick to the following logic: if a particular error condition can be properly handled by the class in question, then the error will be automatically transferred to its nearest parent, which as you saw a few lines above, will trigger an exception. That’s what I call a well-defined chain of responsibility between a few PHP classes!

All right, after explaining the fairly relevant role played by the two pair of error classes created before, it’s time to learn how the core error logging system can be expanded to register more specific failures.

In this particular case, I’ll simply derive a child class from the parent “ErrorLogger,” which will be provided with the capacity to register specific errors to the system’s error logger.

In addition, based upon the correct application of the chain of responsibility schema, this new class will delegate the handling of a specific error to its parent, when this failure can be processed at the current level.

To learn more about how this new error logging class will be created, please keep reading.

{mospagebreak title=Expanding the basic error logging system}

As I expressed in the previous section, expanding the basic error logging mechanism that was shown before consists essentially of deriving a brand-new sub class from the base “ErrorLogger.” This creates a mechanism that will be capable of registering specific errors to the system’s error logger.

Based on this premise, here is the signature of this concrete child class, which I called “FileErrorLogger." Please take a look at its definition:

// define ‘FileErrorLogger’ class
class FileErrorLogger 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!=’File Error Logger’){
            throw new Exception(‘Invalid error logger’);
        }
        $this->errorLogger=$errorLogger;
    }
    // log error to file
    public function logError(){
        error_log(‘Message from :’.$this->getErrorLogger(),0);
    }
}

If you take an in-depth look at the above error logger class, you’ll understand quickly how it does its thing. In simple terms, the “FileErrorLogger” class has been provided with the ability to register specific errors to the system’s error logger via the implementation of its respective “logError()” method. Really simple, isn’t it?

Nevertheless, I actually want you to focus your attention on the definition of another handy method: ”getErrorLogger().” It shows in a nutshell how the chain of responsibility model works. As you can see, the aforementioned method reveals the power of this schema by transferring the program’s flow to its corresponding parent when a specific error condition can’t be properly handled at that stage. Obviously, this condition is represented by the following expression:

if($this->errorLogger==NULL){
    // call parent object in chain of responsibility
    return $this->parentErrorLogger->getErrorLogger();
}
else{
   return $this->errorLogger;

In this situation, when a concrete failure can’t be appropriately processed by the pertinent “FileErrorLogger” class, the error condition will be delegated to its parent, which has been previously passed as an input argument via the corresponding constructor. At this point, are you starting to grasp the logic behind the chain of responsibility pattern? I hope you are!

So far, the file error logging class that I defined a few lines above will hopefully be more than enough to demonstrate how to create a responsibility chain between some PHP classes. However, I must say there’s still a missing link inside this chain. I’ve not yet built a sample class capable of using the capabilities embedded into the previous “FileErrorLogger.” Therefore, the question is: how can this be achieved?

Fortunately, creating a new class that utilizes the handy features provided by the prior “FileErrorLogger” class is indeed a no-brainer process, certainly a fact that I’m going to demonstrate over the course of the following section. Therefore, I suggest you click on the link below and keep reading.

{mospagebreak title=Logging errors when something goes wrong}

To illustrate the functionality of the error logging system that I created earlier in this article, I’ll define a sample email checking class. It will work with the file error logger mechanism that you saw before, to implement in an efficient way the corresponding chain of responsibility model.

That being said, here is the respective signature of this new email verification class:

// define ‘EmailValidator’ class
class EmailValidator{
    private $email;
    private $fileErrorLogger;
    public function __construct($email,ErrorLogger
$fileErrorLogger){
        $this->fileErrorLogger=$fileErrorLogger;
        if(!preg_match("/^.+@.+$/",$email)){
            $this->fileErrorLogger->logError();
        }
        $this->email=$email;
    }
    // validate email
    public function validate(){
        if(!$this->windnsrr(array_pop(explode("@",$this-
>email)))){
            $this->fileErrorLogger->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 you can see, the logic followed by the above “EmailValidator” class is fairly comprehensive, not only with reference to its limited functionality, but because this class was shown in the previous article of the series too.

In this case, the class in question is capable of validating a given email address on any Window-based system by mean of its “validate()” method, and not surprisingly when the email fails to pass the verification process, the failure is logged via the intuitive “FileErrorLogger” class.

Of course, aside from the features that I explained previously, the only thing worth mentioning here is the appropriate delegation of responsibility that takes place when the error condition can’t be handled by the file error logging class, which, as you learned before, results in moving the program’s flow to its respective parent.

At this stage, I’m sure that you understood how the “EmailValidator” class does its business, as well as how the chain of responsibility works across all the previously defined error loggers. Therefore it’s time to move on and see a concrete example where all the classes will be put to work together.

Want to see how this hands-on example will be developed? Go ahead and read the next few lines.

{mospagebreak title=The error logging system in action}

If you’re like me, then you’ll think that the best way of understanding how the  error logging system works is by developing a comprehensive example which uses all the classes in conjunction.

Therefore, below you’ll see a simple script I coded that shows the respective behaviors followed by all the classes defined over the previous sections, whether or not a concrete error logger has been set. Please look at this handy group of examples:

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 ‘FileErrorLogger’
    $fileErrorLogger=new FileErrorLogger($errorLogger);
    // instantiate ‘EmailValidator’ object
    //$emailValidator=new EmailValidator(‘username@domain.com’,$fileErrorLogger);
    //$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
    $fileErrorLogger=new FileErrorLogger($errorLogger);
    $fileErrorLogger->setErrorLogger(‘File Error Logger’);
    $emailValidator=new EmailValidator(‘username@domain.com’,$fileErrorLogger);
    $emailValidator->validate();
}
catch(Exception $e){
    echo $e->getMessage();
    exit();
}

As shown above, the first two examples demonstrate clearly how the chain of responsibility is moved up toward the base “ErrorLogger” class when an appropriate error logger isn’t provided to the scripts. This condition is reflected by the outputs generated by each script, since they complain loudly about this condition by displaying the following message:

No error logger has been set!

Finally, the last example illustrates a concrete case where a “FileErrorLogger” object is injected straight into the respective “EmailValidator” class. As you’ll realize, this fact obviously allows the correct implementation of its “validate()” method. As usual, I suggest you to try modifying the previous examples and see what happens in each case.

Final thoughts

I’m finished now. In this three-part series, I introduced you to the basics of how to implement the chain of responsibility pattern with PHP 5. I hope that all the examples that were shown in this set of articles will help you start applying this schema in your own PHP applications. See you in the next PHP tutorial! 

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan