PHP: исключения против ошибок?

Может быть, я пропускаю его где-то в руководстве по PHP, но в чем разница между ошибкой и исключением? Единственное отличие, которое я вижу, это то, что ошибки и исключения обрабатываются по-разному. Но что вызывает исключение и что вызывает ошибку?

Исключения выбрасываются – они должны быть пойманы. Ошибки обычно невосстанавливаются. Скажем, например, у вас есть блок кода, который будет вставлять строку в базу данных. Возможно, этот вызов не удался (дублированный идентификатор) – вы захотите иметь «ошибку», которая в этом случае является «Исключением». Когда вы вставляете эти строки, вы можете сделать что-то вроде этого

try { $row->insert(); $inserted = true; } catch (Exception $e) { echo "There was an error inserting the row - ".$e->getMessage(); $inserted = false; } echo "Some more stuff"; 

Выполнение программы будет продолжаться – потому что вы «поймали» исключение. Исключение будет считаться ошибкой, если оно не будет обнаружено. Это позволит вам продолжить выполнение программы после ее срыва.

Я обычно set_error_handler для функции, которая принимает ошибку и генерирует исключение, поэтому, что бы ни случилось, у меня будут исключения, с которыми приходится иметь дело. Больше @file_get_contents просто приятно и аккуратно try / catch.

В ситуациях отладки у меня также есть обработчик исключений, который выводит страницу asp.net как. Я отправляю это на дороге, но, если потребуется, я отправлю пример источника позже.

редактировать:

Дополнение, как и было обещано, я вырезал и вставлял часть своего кода вместе, чтобы сделать образец. Я сохранил файл ниже на моей рабочей станции, здесь вы можете увидеть результаты .

 <?php define( 'DEBUG', true ); class ErrorOrWarningException extends Exception { protected $_Context = null; public function getContext() { return $this->_Context; } public function setContext( $value ) { $this->_Context = $value; } public function __construct( $code, $message, $file, $line, $context ) { parent::__construct( $message, $code ); $this->file = $file; $this->line = $line; $this->setContext( $context ); } } /** * Inspire to write perfect code. everything is an exception, even minor warnings. **/ function error_to_exception( $code, $message, $file, $line, $context ) { throw new ErrorOrWarningException( $code, $message, $file, $line, $context ); } set_error_handler( 'error_to_exception' ); function global_exception_handler( $ex ) { ob_start(); dump_exception( $ex ); $dump = ob_get_clean(); // send email of dump to administrator?... // if we are in debug mode we are allowed to dump exceptions to the browser. if ( defined( 'DEBUG' ) && DEBUG == true ) { echo $dump; } else // if we are in production we give our visitor a nice message without all the details. { echo file_get_contents( 'static/errors/fatalexception.html' ); } exit; } function dump_exception( Exception $ex ) { $file = $ex->getFile(); $line = $ex->getLine(); if ( file_exists( $file ) ) { $lines = file( $file ); } ?><html> <head> <title><?= $ex->getMessage(); ?></title> <style type="text/css"> body { width : 800px; margin : auto; } ul.code { border : inset 1px; } ul.code li { white-space: pre ; list-style-type : none; font-family : monospace; } ul.code li.line { color : red; } table.trace { width : 100%; border-collapse : collapse; border : solid 1px black; } table.thead tr { background : rgb(240,240,240); } table.trace tr.odd { background : white; } table.trace tr.even { background : rgb(250,250,250); } table.trace td { padding : 2px 4px 2px 4px; } </style> </head> <body> <h1>Uncaught <?= get_class( $ex ); ?></h1> <h2><?= $ex->getMessage(); ?></h2> <p> An uncaught <?= get_class( $ex ); ?> was thrown on line <?= $line; ?> of file <?= basename( $file ); ?> that prevented further execution of this request. </p> <h2>Where it happened:</h2> <? if ( isset($lines) ) : ?> <code><?= $file; ?></code> <ul class="code"> <? for( $i = $line - 3; $i < $line + 3; $i ++ ) : ?> <? if ( $i > 0 && $i < count( $lines ) ) : ?> <? if ( $i == $line-1 ) : ?> <li class="line"><?= str_replace( "\n", "", $lines[$i] ); ?></li> <? else : ?> <li><?= str_replace( "\n", "", $lines[$i] ); ?></li> <? endif; ?> <? endif; ?> <? endfor; ?> </ul> <? endif; ?> <? if ( is_array( $ex->getTrace() ) ) : ?> <h2>Stack trace:</h2> <table class="trace"> <thead> <tr> <td>File</td> <td>Line</td> <td>Class</td> <td>Function</td> <td>Arguments</td> </tr> </thead> <tbody> <? foreach ( $ex->getTrace() as $i => $trace ) : ?> <tr class="<?= $i % 2 == 0 ? 'even' : 'odd'; ?>"> <td><?= isset($trace[ 'file' ]) ? basename($trace[ 'file' ]) : ''; ?></td> <td><?= isset($trace[ 'line' ]) ? $trace[ 'line' ] : ''; ?></td> <td><?= isset($trace[ 'class' ]) ? $trace[ 'class' ] : ''; ?></td> <td><?= isset($trace[ 'function' ]) ? $trace[ 'function' ] : ''; ?></td> <td> <? if( isset($trace[ 'args' ]) ) : ?> <? foreach ( $trace[ 'args' ] as $i => $arg ) : ?> <span title="<?= var_export( $arg, true ); ?>"><?= gettype( $arg ); ?></span> <?= $i < count( $trace['args'] ) -1 ? ',' : ''; ?> <? endforeach; ?> <? else : ?> NULL <? endif; ?> </td> </tr> <? endforeach;?> </tbody> </table> <? else : ?> <pre><?= $ex->getTraceAsString(); ?></pre> <? endif; ?> </body> </html><? // back in php } set_exception_handler( 'global_exception_handler' ); class X { function __construct() { trigger_error( 'Whoops!', E_USER_NOTICE ); } } $x = new X(); throw new Exception( 'Execution will never get here' ); ?> 

Одна вещь, которую нужно добавить здесь, это обработка исключений и ошибок. Для разработчиков приложений, как ошибки, так и исключения – это «плохие вещи», которые вы хотите записать, чтобы узнать о проблемах, которые имеет ваше приложение, – чтобы ваши клиенты имели лучший опыт в долгосрочной перспективе.

Поэтому имеет смысл написать обработчик ошибок, который делает то же самое, что и для исключений.

Ответ заслуживает того, чтобы говорить о слоне в комнате

Ошибки – это старый способ обработки условия ошибки во время выполнения. Как правило, код выполняет вызов некоторого типа set_error_handler перед выполнением некоторого кода. Следуя традиции прерывания языка ассемблера. Вот как выглядит код BASIC.

 on error :divide_error print 1/0 print "this won't print" :divide_error if errcode = X print "divide by zero error" 

Было трудно убедиться, что set_error_handler будет вызван с правильным значением. И что еще хуже, вызов может быть сделан для отдельной процедуры, которая изменит обработчик ошибок. Плюс много раз звонки были перемежаны вызовами и обработчиками set_error_handler . Кодексу было легко быстро выйти из-под контроля. Обработка исключений пришла на помощь путем формализации синтаксиса и семантики того, что действительно делал хороший код.

 try { print 1/0; print "this won't print"; } catch (DivideByZeroException $e) { print "divide by zero error"; } 

Никакой отдельной функции или риска вызова неправильного обработчика ошибок. Теперь код гарантированно находится в одном месте. Плюс мы получаем сообщения об ошибках.

PHP использовал только обработку ошибок, когда многие другие языки уже превратились в предпочтительную модель обработки исключений. В конечном итоге разработчики PHP реализовали обработку исключений. Но, вероятно, поддержка старого кода, они сохраняли обработку ошибок и предоставляли способ заставить обработку ошибок выглядеть как обработка исключений. Кроме того, нет никакой гарантии, что какой-то код не может сбрасывать обработчик ошибок, который должен был точно представлять собой обработку исключений.

Окончательный ответ

Ошибки, которые были закодированы до обработки исключений, были реализованы, вероятно, все еще ошибки. Новые ошибки, вероятно, являются исключениями. Но нет никакой конструкции или логики, к которой относятся ошибки и которые являются исключениями. Это просто основано на том, что было доступно в то время, когда оно было закодировано, и предпочтение программиста, кодирующего его.

Re: «но в чем же разница между ошибкой и исключением?»

Здесь есть много хороших ответов о различиях. Я просто добавлю то, о чем еще не говорили – производительность. В частности, это разница между исключениями броска / обработки и обработкой кода возврата (либо успеха, либо некоторой ошибки). Обычно в php это означает возврат false или null , но они могут быть более подробными, например, при загрузке файла: http://php.net/manual/en/features.file-upload.errors.php. Вы даже можете вернуть Объект исключения!

Я сделал несколько прогонов производительности на разных языках / системах. Вообще говоря, обработка исключений примерно на 10 000 раз медленнее, чем проверка кода возврата ошибки.

Итак, если это абсолютно необходимо, нужно закончить выполнение, прежде чем он даже начнется – ну, вам не повезло, потому что путешествия во времени не существует. Без временного путешествия наиболее эффективными являются коды возврата.

Редактировать:

PHP оптимизирован для обработки исключений. Тесты реального мира показывают, что выброс исключения составляет всего 2-10x медленнее, чем возврат значения.

Как указано в других ответах, установка обработчика ошибок для метаданных исключений – лучший способ обработки ошибок в PHP. Я использую немного более простую настройку:

 set_error_handler(function ($errno, $errstr, $errfile, $errline ) { if (error_reporting()) { throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); } }); 

Обратите внимание на error_reporting() чтобы оператор @ работал. Кроме того, нет необходимости определять настраиваемое исключение, PHP имеет для этого один класс.

Большая выгода от исключения исключений заключается в том, что у исключения есть связанная с ними трассировка стека, поэтому легко найти, где проблема.

Я думаю, что тот, кого вы ищете, таков;

Ошибки – это стандартный материал, к которому вы привыкли, например, повторение переменной $, которая не существует.
Исключения только с PHP 5 и далее при работе с объектами.

Чтобы это было просто:

Исключения – это ошибки, которые вы получаете при работе с объектами. Операция try / catch позволяет вам что-то делать с ними, и используется так же, как и оператор if / else. Попытайтесь сделать это, если проблема, не имеет значения, сделайте это.

Если вы не «поймаете» исключение, то оно превратится в стандартную ошибку.

Ошибки – это фундаментальные ошибки php, которые обычно останавливают ваш скрипт.

Try / catch часто используется для установления соединений с базой данных, таких как PDO, и это нормально, если вы хотите перенаправить сценарий или сделать что-то еще, если соединение не работает. Но если вы просто хотите отобразить сообщение об ошибке и остановить скрипт, тогда вам это не понадобится, неотображенное исключение превратится в фатальную ошибку. Или вы также можете использовать настройку обработки ошибок на всех сайтах.

надеюсь, это поможет

Исключения бросаются намеренно кодом с помощью броска, ошибок … не так много.

Ошибки возникают в результате чего-то, что обычно не обрабатывается. (Ошибки ввода-вывода, ошибки TCP / IP, ошибки нулевой ссылки)

Я намерен дать вам самое необычное обсуждение контроля ошибок.

Я построил очень хороший обработчик ошибок на языке много лет назад, и хотя некоторые из имен изменились, принципы обработки ошибок сегодня те же. У меня была специально построенная многозадачная ОС, и мне приходилось восстанавливать ошибки данных на всех уровнях без утечек памяти, роста стека или сбоев. Итак, что следует за моим пониманием того, как должны действовать ошибки и исключения и как они отличаются. Я просто скажу, что у меня нет понимания того, как работают внутренние попытки try catch, поэтому я догадываюсь в какой-то мере.

Первое, что происходит под обложками для обработки ошибок, – это переход из одного состояния программы в другое. Как это делается? Я доберусь до этого.

Исторически, ошибки более старые и более простые, а исключения новее и немного сложнее и способны. Ошибки работают нормально до тех пор, пока вам не понадобится их пузырь, что эквивалентно передаче сложной проблемы вашему руководителю.

Ошибки могут быть числами, такими как номера ошибок, а иногда и с одной или несколькими связанными строками. Например, если возникает ошибка чтения файла, вы можете сообщить, что это такое и, возможно, изящно выйти из строя. (Хей, это шаг от просто грохота, как в старые времена.)

То, что нередко говорят об исключениях, заключается в том, что исключения – это объекты, наложенные на специальный стеки исключений. Это похоже на стек возврата для потока программы, но он поддерживает состояние возврата только для попыток ошибок и уловов. (Я называл их ePush и ePop, и? Abort был условным броском, который бы ePop и восстанавливался до этого уровня, в то время как Abort был полной смертью или выходом.)

В нижней части стека находится информация о начальном вызывающем объекте, который знает о состоянии при запуске внешней попытки, что часто бывает при запуске вашей программы. Вдобавок к этому, или следующий слой в стеке, с тем, чтобы быть дочерними, а не являющимися родителями, является объектом исключения следующего внутреннего блока try / catch.

Если вы попробуете попробовать попробовать, вы укладываете внутреннюю попытку поверх внешней попытки. Когда во внутренней попытке возникает ошибка, и либо внутренний catch не может ее обработать, либо ошибка передается во внешнюю попытку, тогда управление передается внешнему блоку catch (object), чтобы увидеть, может ли он обрабатывать ошибку, т. Е. ваш руководитель.

Так что действительно делает этот стек ошибок, так это возможность отслеживать и восстанавливать поток программы и состояние системы, другими словами, она позволяет программе не сбрасывать стек возврата и беспорядок для других (данных), когда что-то идет не так. Таким образом, он также сохраняет состояние любых других ресурсов, таких как пулы распределения памяти, и поэтому может очищать их при завершении catch. В общем, это может быть очень сложной задачей, и поэтому обработка исключений часто медленная. В общем, довольно немного состояний нужно входить в эти блоки исключений.

Таким образом, элемент try / catch блокирует состояние, чтобы иметь возможность вернуться, если все остальное перепуталось. Это как родитель. Когда наши жизни перепутались, мы сможем вернуться на колени наших родителей, и они снова сделают все в порядке.

Надеюсь, я тебя не разочаровал.

Когда задан параметр set_error_handler (), обработчик ошибок похож на Exception. См. Следующий код:

  <?php function handleErrors( $e_code ) { echo "error code: " . $e_code . "<br>"; } set_error_handler( "handleErrors" ); trigger_error( "trigger a fatal error", E_USER_ERROR); echo "after error."; //it would run if set_error_handler is defined, otherwise, it wouldn't show ?>