Исключения действительно ваш лучший вариант, они делают все, что вы просили. Возможно даже несколько сообщений, поскольку исключения - это просто классы, которые вы можете расширять. Вы можете просто передать объект, который вызывает исключение, в указанное исключение.
<?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 );
}
}
Теперь вы просто используете класс и переносите вызов, который может вызвать исключение в блоке try-catch.
<?php
$example = new Example();
try {
$example->causeException();
}
catch ( ExampleException $e ) {
// kind of pointless here, just an illustration
// get object that caused it and do something with it.
dump_and_log_function( $e->getObjectThatCausedIt() );
// or just use $example, which is still "alive"
// and references the same instance
dump_and_log_function( $example );
}
Расширение Exception имеет то преимущество, что вы также получаете возврат стека. Обратный след содержит информацию о том, в каком файле, строке и функции произошло исключение. Вы также можете получить код ошибки, сообщение и многое другое. Я предлагаю вам прочитать документацию PHP об исключениях (http://php.net/manual/en/class.exception.php) для получения дополнительной информации.
Что касается сообщений об ошибках и регистрации, я обычно использую для этого одноэлементный класс. У одноэлементного класса есть только один экземпляр (если вы не знали). Вот очень простой пример:
<?php
class Log {
private $logFile;
private static $instance;
/* Log instances may only be constructed in Log::getInstance */
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;
}
}
Теперь, возвращаясь к блоку throw-catch обработки исключений, вы можете изменить его на что-то вроде этого:
<?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>";
}
Вместо того, чтобы сразу выводить сообщение об ошибке, вы можете сделать так, чтобы у класса Log было свойство с массивом сообщений. Затем вы можете перечислить их позже в скрипте представления сразу. Вы также можете заставить метод logMessage хранить сообщения в сеансе, чтобы они могли отображаться после обновления (просто не забудьте удалить сообщения из сеанса, иначе они будут отображаться снова и снова; -).