This is a question about best practices. I have a project I am building and I have the following base Exception class:
Namespace Project;
class Exception extends \Exception{
//=============== BASE EXCEPTIONS 0 - 1000 ===============//
/**
* placeholder for unknown exeptions - the default type
* @var number
*/
const UNKNOWN_ERROR = 0;
//===================== GENERAL =======================//
const NOT_YET_IMPLIMENTED = 1001;
const NON_UNIQUE_EXCEPTION = 1002;
/**
*
* @param string $message
* @param number $code
* @param \Exception $previous
*/
public function __construct( $message="", $code = 0, \Exception $previous = null ){
if( $previous && $previous->getCode() == $code ){
//we do some appending we don't wan't to re-append when re-throwing with the same code
$message = $previous->getMessage();
}else{
$message = $this->getCustomMessage($code, $message);
}
parent::__construct($message, $code, $previous);
}
/**
* Convert the __CLASS__::* constants into a basic error message and add
* the extra bit for some more granularity
* @param int $code
* @param string $extra
* @return string
*/
public function getCustomMessage( $code, $extra ){
$extra = trim( $extra );
//get an array of class constants
$ReflectionObj = new \ReflectionObject( $this );
$constants = $ReflectionObj->getConstants();
//find the constant by value ( values must be unique )
$message = array_search($code, $constants);
//format the message
$message = ucwords( strtolower( str_replace("_", " ", $message)));
$message .= ( $extra == '' ) ? '' : ': '.$extra ;
return $message;
}
}
This all works as desired and allows me to use the error constants as the message, such as:
throw new Exception();
throw new Exception('', Exception::UNKNOWN_ERROR);
throw new Exception('I know what this error is', Exception::UNKNOWN_ERROR);
Which for the $e->message
is:
- 'Unkown Error';
- 'Unkown Error';
- 'Unkown Error: I know what this error is';
Etc...
What I would like to do is by employing the magical power of eval (with the appropriate safeguards of course):
eval( "
namespace Project\Exception;
class $classname extends \Project\Exception{}
");
Where $classname
would also be the error constant. So that I could essentially throw exceptions with an appropriate class for each without having to actually create the minimalistic class for each one.
An example would be:
try{
$error = Exception::UNKNOWN_ERROR; // I know this is a number but for example sake we will say it equates to 'UNKNOWN_ERROR'
throw new $error;
}catch( \Project\Exception\UNKNOWN_ERROR $e ){
}
Thus I would be able to catch the errors by checking the class names, not the error codes, while still maintaining a small code-base for the exception handler (I plan to have a lot of exceptions). My fear is that when extending exceptions I may lose track of the error numbers and may have some exception classes with conflicting error numbers, which I want to be unique for the whole project. So by employing this method, I have only the one main class to store my constants in but still get the benefits of having many exception classes.
Here is a little update on a new test I just ran. It seems that it is quite possible to throw a dynamic exception from the controller of the parent exception. This is pretty fantastic. To achieve this, a few special steps must be taken but nothing to radical.
"555" => "MyException"
and runeJinn
(command line etc) and it will build them for you. \$\endgroup\$