Jump to content

Erroring/debugging system in a framework


Liquid Fire

Recommended Posts

I have got to a point n my framework where I have all my features I need to having and now am going to go through the codebase to do basically a code audit and see if there are places where I can improve the core system.  One thing I want to do is and an erroring and debugging system.

 

First questions i have about the debugging system I am planning to put into place.  Every class has a member called debug which is eithertrue or false.  I plan on add code into the core that will print out useful information for developers when the debug is true.  Now add all these if statement based on the debug member should not effect the speed of the system at all when debug is set to false, should it.  I mean i can't imagine have more then a few hundred if statements(and i think that a really high esitmation) for debugging purposes.  Is there a better method of doing a debugging system for a framework that you would recommend?

 

Second about the erroring system.  It has been suggested to use exceptions but that would require the user to use try/catched in the model/controller files and i really don't want to do that.  I was figure I would create my own error class the would print out my own message and then kill the script.  is there any real reason not to do that and use exceptions instead?

 

any feedback would be great.

Link to comment
Share on other sites

Second about the erroring system.  It has been suggested to use exceptions but that would require the user to use try/catched in the model/controller files and i really don't want to do that.  I was figure I would create my own error class the would print out my own message and then kill the script.  is there any real reason not to do that and use exceptions instead?

 

You're trying to handle framework errors, not errors in your users' controllers or models.  The try / catch blocks belong inside your framework.  For the catch, you should try and handle the error, but if you can't you can error out and kill the script.

 

The users of your framework can still use try / catch blocks in their client code for their own purposes.

Link to comment
Share on other sites

You shouldn't need a debugging flag.

 

As for exceptions: to successfully implement them, you have start thinking a bit differently. Say you have a method that would before return false on failure, it would throw an exception instead.

 

I'm also a fan of using default messages for different types of exceptions, e.g.:

 

<?php
class Backbone_Exception_InvalidArgument extends Backbone_Exception_Runtime {
const MSG_DEFAULT = 0;
const MSG_EXPECTOBJECT = 1;
const MSG_EXPECTSTRING = 2;
const MSG_EXPECTINT = 3;

protected $messages = array(
	self::MSG_DEFAULT => 'An invalid argument was passed.',
	self::MSG_EXPECTOBJECT => 'Expected object, got %s.',
	self::MSG_EXPECTOBJECTTYPE => 'Expected object of type %s, got %s.',
	self::MSG_EXPECTSTRING => 'Expected string, got %s.',
	self::MSG_EXPECTINT => 'Expected integer, got %s.'
);
}
?>
<?php
class Backbone_Exception extends Exception {

const MSG_DEFAULT = 0;

protected $messages = array(
	self::MSG_DEFAULT =>
	'An unknown error occurred.'
);

/**
 * Create a new exception.
 * 
 * You may use a format string (using %, as used by printf()) 
 * and add an arbitrary number of arguments to be formatted.
 *
 * @param unknown_type $message
 */
public function __construct($message = null){
	if($message === null){
		$message = reset($this->messages);
	}
		elseif(is_int($message)){
		if(!isset($this->messages[$message])){
			$message = $this->messages[self::MSG_DEFAULT];
		}
			else {
			$message = $this->messages[$message];			
		}
	}
	if(func_num_args() > 1){
		$message = vprintf($message, array_shift(func_get_args()));
	}
	parent::__construct($message);	
}
public function __toString(){
	return get_class($this). " [code {$this->code}]: {$this->getMessage()}\nBacktrace:\n{$this->getTraceAsString()}";
}
}
?>

Link to comment
Share on other sites

Correct me if I'm wrong, but I think Liquid Fire was thinking more along the lines of a way of reporting errors/debugging information if a flag was enabled.... more like a stack trace kind of thing so that you can see what is going on.

 

In my opinion a framework itself can use exception handling or whatever other method you prefer, but I would think it is better to make it flexible so that a user can decide how they want to use it.

 

To me it should be something like:

- A flag to enable/disable PHP error reporting (ini_set)

- A stacktrace kind of thing so that you can watch the values of variables/functions they enter (maybe line numbers?)

- Exception handling... or not

Link to comment
Share on other sites

I use this (sorry for the lack of docblocks, it's a work in progress):

 

<?php
/**
* Error and uncaught exception handler.
* 
* @uses Backbone_Exception
* @throws Backbone_Exception_Singlestantiator
* 
*
*/
class Backbone_Core_Error_Handler implements Backbone_Core_Interface_Singlestantiator {

    private $observers = array();
    private static $instantiated;

    public function __construct(Array $observers) {
    	Backbone_Core_Assert::isNull(self::$instantiated, new Backbone_Exception_Singlestantiator);
    	Backbone_Core_Assert::minCount($observers, 1);
    	Backbone_Core_Assert::areInstancesOf(
    		$observers, 'Backbone_Core_Error_Observer'
    	);
    	$this->observers = $observers;
        set_error_handler(array($this, 'dispatchError'));
        set_exception_handler(array($this, 'dispatchUncaughtException'));
    }
    public function notifyObservers($e){
	foreach($this->observers as $observer){
		$observer->notify($e);
	}    	
    }
    public function dispatchError($type, $msg, $file, $line, $context) {
    	
    	$e = new Backbone_Exception($msg);
    	$e->setCode($type);
    	$e->setLine($line);
    	$e->setFile($file);
    	
    	switch($type){
    		case E_ERROR:
    		case E_USER_ERROR:
    		case E_RECOVERABLE_ERROR:
    			$e->setErrorTypeString('Fatal error');
    		break;
    		case E_NOTICE:
    		case E_USER_NOTICE:
    			$e->setErrorTypeString('Notice');
    			$e->setNonFatal();
    		break;
    		case E_STRICT:
    			$e->setErrorTypeString('Strict standards');
    			$e->setNonFatal();
    		break;
    		case E_WARNING:
    		case E_USER_WARNING:
    			$e->setErrorTypeString('Warning');
    			$e->setNonFatal();
    		break;
    		default:
    			$e->setErrorTypeString('Unkown error');
    	}
    	$this->dispatch($e);
    }
    public function dispatchUncaughtException(Exception $e){
	$e = $this->ensureBackboneException($e);
    	$e->setErrorTypeString('Uncaught exception');
	$this->dispatch($e);
    }
    private function ensureBackboneException(Exception $e){
     	if(!$e instanceof Backbone_Exception){
    		$e = Backbone_Exception::factory($e);
    	} 
    	return $e;  	
    }
    public function dispatchCaugthException(){
	$e = $this->ensureBackboneException($e);
    	$e->setErrorTypeString('Caught exception');
	$this->dispatch($e);    	
    }
private function dispatch(Backbone_Exception $e){
	$this->notifyObservers($e);
	if($e->isFatal()){
		die();
	}
}
public function isInstantiated(){
	return self::$instantiated;
}
}
?>

 

Both errors and exceptions are uniformly handled. I currently have three Observer classes: one that emails, one that logs and one that outputs html or plain text.

 

For debugging while developing I have two aids: 1) SimpleTest and 2) Zend Studio's internal debugger.

 

I don't think anyone would need more. Maybe a little benchmarking, but just for debugging and error reporting, this is working or me.

 

I really don't like the idea of littering my app with checks whether it is running in debugging mode. While doing acceptance test I add the ScreenWriter observer, when going into production it is not added, which is more or less like turning off display_errors.

Link to comment
Share on other sites

I personally just wrote my own error handler so that I don't have to worry about keeping a certain type of try-catch method or debugger in-bedded into my system. Then I wrote my objects and classes so that with or without the proper variables or anything they still don't kill the system. I picture each class as a indestructible object that should be able to stand on it's own and simply trigger_error()'s when ever something really bad happens.

 

My Error class will send me an email if it is a serious error and the rest are logged into the database.

Link to comment
Share on other sites

I personally just wrote my own error handler so that I don't have to worry about keeping a certain type of try-catch method

 

Try/catch blocks are part of normal execution logic. They allow to respond to failure of an internal component. So there's nothing to 'worry' about, it's just very useful execution logic. Do you worry about a function failing and returning false?

 

An exception is NOT an application error, an uncaught exception is.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.