Exceptions are really the best option; they do everything you requested. Even a few messages are possible, since exceptions are just classes that you can extend. You can simply pass an object that throws an exception for the specified exception.
<?php class ExampleException extends Exception { private $secondMessage; private $objectThatCausedIt; public function __construct( $secondMessage, $objectThatCausedIt ) { parent::__construct( "Descriptive message for developer", // error code for this type of error 1000 ); $this->secondMessage = $secondMessage; $this->objectThatCausedIt = $objectThatCausedIt; } public function getSecondMessage() { return $this->secondMessage; } public function getObjectThatCausedIt() { return $this->objectThatCausedIt; } } class Example { public function causeException() { throw new ExampleException( "Second Message", $this ); } }
Now you just use the class and end the call, which may throw an exception in the try-catch block.
<?php $example = new Example(); try { $example->causeException(); } catch ( ExampleException $e ) {
Extending an exception has the advantage that you also get back stack traces. Backtrace contains information on how an exception occurred in which file, line and function. You can also access the error code, message, etc. I suggest you read the PHP documentation on exceptions ( http://php.net/manual/en/class.exception.php ) for more information.
Regarding error messages and logging, I usually use one class for this. The singleton class has only one instance of itself (if you did not know this). Here is a very simple example:
<?php class Log { private $logFile; private static $instance; private function __construct() { $this->logFile = fopen( "path/to/log/file", "a" ); } public logMessage( $message ) { fwrite( $this->logFile, $message ); } public static getInstance() { if ( !self::$instance ) self::$instance = new self(); return self::$instance; } }
Now, returning to the block of browns with exception handling, you can change it to something like this:
<?php $example = new Example(); try { $example->causeException(); } catch ( ExampleException $e ) { // log developer message and backtrace Log::getInstance()->logMessage( $e->getMessage() ); Log::getInstance()->logMessage( $e->getTraceAsString() ); // or more compact by casting to string Log::getInstance()->logMessage( (string)$e ); // and now print error for users echo "<p>An Error has occured: {$e->getSecondMessage()}</p>"; }
Instead of immediately responding to the error message, you can force the log class to have a property with an array of messages. You can then list them later in the script view all at once. You can also force the logMessage method to store messages in the session so that they can be displayed after the update (just remember to clear the messages from the session or they will be displayed again and again ;-).