Можливо, я його десь пропускаю в керівництві 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";
Виконання програми буде продовжено, тому що ви "застали" виняток. Виняток буде трактуватися як помилка, якщо його не знайдено. Це дозволить продовжувати виконання програми і після її відмови.
Throwable
інтерфейсу), даючи набагато більш виразний та абсолютний спосіб відрізнити та правильно подати обидва реальних проблеми та дорадчі повідомлення
Error
В. С. нащадками Exception
.
Зазвичай я виконую set_error_handler
функцію, яка помиляється і викидає виняток, так що що б не трапилося, я маю просто винятки, з якими потрібно боротися. Не більше @file_get_contents
просто приємного та акуратного спробу / лову.
У ситуаціях налагодження у мене також є обробник винятків, який видає сторінку, схожу на 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
до виконання якогось коду. Слідуючи традиції складання мови переривається. Ось як виглядатиме якийсь базовий код.
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 впровадили обробку виключень. Але, ймовірно, підтримують старий код, вони продовжували обробляти помилки і надавали спосіб зробити обробку помилок схожим на обробку винятків. Крім того, немає гарантії, що деякий код не може скинути оброблювач помилок, що саме було призначено для обробки винятків.
Остаточна відповідь
Помилки, кодовані до того, як було здійснено обробку винятків, ймовірно, все ж є помилками. Нові помилки - ймовірні винятки. Але немає жодної конструкції чи логіки, в якій є помилки та які є винятки. Він просто базується на тому, що було доступно на той час, коли воно було закодовано, та перевазі програміста, що кодує це.
Тут слід додати одне про обробку винятків та помилок. З метою розробника програми, і помилки, і винятки - це "погані речі", які ви хочете записати, щоб дізнатися про проблеми, які має ваша програма - щоб ваші клієнти мали кращий досвід у довгостроковій перспективі.
Тому має сенс написати оброблювач помилок, який робить те саме, що ви робите для винятків.
Як зазначено в інших відповідях, встановлення обробника помилок на викид виключень - найкращий спосіб обробляти помилки в PHP. Я використовую трохи простішу настройку:
set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
if (error_reporting()) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}
});
Будь ласка, зверніть увагу на error_reporting()
чек, який потрібно зберегти@
оператор не працював. Крім того, не потрібно визначати спеціальні винятки, у PHP є один хороший клас для цього.
Велика перевага викидів винятків полягає в тому, що виняток має сліди стека, пов'язані з ними, тому легко знайти, де проблема.
Re: "але яка саме різниця між помилкою та винятком?"
Тут є багато хороших відповідей щодо відмінностей. Я просто додам щось, про що ще не говорили - виставу. Зокрема, це полягає в різниці між викидами / обробкою винятків та обробкою коду повернення (успіх чи помилка). Зазвичай у php це означає повернення false
або null
, але вони можуть бути більш детальними, наприклад, із завантаженням файлів: http://php.net/manual/en/features.file-upload.errors.php Ви навіть можете повернути об’єкт винятку !
Я зробив кілька циклів роботи на різних мовах / системах. Взагалі кажучи, обробка винятків приблизно на 10000 разів повільніше, ніж перевірка коду повернення помилки.
Отже, якщо це абсолютно, позитивно потрібно закінчити виконання ще до того, як воно ще почалося - ну, вам не пощастило, оскільки подорожі у часі не існують. Без подорожі в часі коди повернення - найшвидший доступний варіант.
Редагувати:
PHP дуже оптимізовано для обробки виключень. Тести реального світу показують, що кидання винятку лише на 2-10 разів повільніше, ніж повернення значення.
Я думаю, що коханець, якого ти шукає, це;
Помилки - це стандартний матеріал, до якого ви звикли, наприклад, повторення змінної $, яка не існує.
Винятки складаються лише з PHP 5 і надалі при роботі з об'єктами.
Щоб зробити це просто:
Виняток становлять помилки, які ви отримуєте під час роботи з об'єктами. Оператор try / catch дозволяє зробити щось з ними, хоча він використовується так само, як і if / else. Спробуйте зробити це, якщо проблема не має значення, зробіть це.
Якщо ви не «ловите» виняток, це перетворюється на стандартну помилку.
Помилки - це фундаментальні помилки php, які зазвичай зупиняють ваш сценарій.
Try / catch часто використовується для встановлення підключень до бази даних, таких як PDO, що добре, якщо ви хочете перенаправити сценарій або зробити щось інше, якщо з'єднання не працює. Але якщо ви просто хочете відобразити повідомлення про помилку і зупинити скрипт, тоді воно вам не потрібно, виняток, що виникла, перетворюється на фатальну помилку. Або ви також можете скористатися налаштуваннями обробки помилок на рівні сайту.
Сподіваюся, що це допомагає
Винятки кидаються навмисно кодом за допомогою кидка, помилок ... не так вже й багато.
Помилки виникають внаслідок чогось, що зазвичай не обробляється. (Помилки вводу-виводу, помилки TCP / IP, помилки з нульовою посиланням)
Я маю намір дати вам найбільш незвичайне обговорення контролю помилок.
Я створив дуже хороший обробник помилок на мові років тому, і хоча деякі з назв змінилися, принципи обробки помилок є однаковими і сьогодні. У мене була створена спеціальна багатозадачна ОС, і я мав змогу відновлюватися після помилок даних на всіх рівнях без витоків пам'яті, зростання стека або збоїв. Отже, наступне - це моє розуміння того, як повинні діяти помилки та винятки та як вони відрізняються. Я просто скажу, що я не розумію, як працює внутрішня спроба лову, тому я певною мірою здогадуюсь.
Перше, що трапляється під обкладинками для обробки помилок - це перехід з одного програмного стану в інший. Як це робиться? Я доберусь до цього.
Історично помилки старіші та простіші, а винятки - новіші та трохи складніші та спроможні. Помилки справно працюють, доки вам не доведеться їх замішувати, що є еквівалентом передачі важкої проблеми своєму керівнику.
Помилками можуть бути числа, як номери помилок, а іноді з одним або кількома пов'язаними рядками. Наприклад, якщо виникла помилка читання файлів, ви можете повідомити, що це таке, і, можливо, витончено вийти з ладу. (Сена, це крок від простої аварії, як колись.)
Що не часто говорять про винятки, це те, що винятки - це об'єкти, які розташовуються на спеціальній степі винятків. Це як стек повернення для потоку програми, але він утримує стан повернення лише для спроб помилок та перехоп. (Раніше я називав їх ePush та ePop, і? Abort був умовним кидком, який би ePop і відновився до цього рівня, тоді як Abort був повноцінним штампом або виходом.)
У нижній частині стеку розміщена інформація про початковий абонент, об'єкт, який знає про стан, коли була запущена зовнішня спроба, що часто відбувається при запуску вашої програми. На додаток, що або наступний шар у стеці, доки діти, а внизу - батьки, є об’єктом винятку наступного внутрішнього блоку спробу / лову.
Якщо ви поставите спробу всередині спроби, ви кладете внутрішню спробу поверх верхньої. Коли у внутрішній спробі виникає помилка і або внутрішній лов не може її впоратися, або помилка перекидається на зовнішню спробу, тоді керування передається зовнішньому блоку захоплення (об'єкту), щоб побачити, чи може він впоратися з помилкою, тобто ваш керівник.
Отже, що справді робить цей стек помилок - це можливість маркувати та відновлювати потік програми та стан системи, інакше кажучи, це дозволяє програмі не руйнувати зворотний стек і псувати речі для інших (даних), коли справи йдуть не так. Таким чином, це також економить стан будь-яких інших ресурсів, таких як пул розподілу пам’яті, і таким чином він може очистити їх, коли виконано вилов. Взагалі це може бути дуже складною справою, і саме тому обробка винятків часто повільна. Загалом у ці блоки виключень потрібно зайняти небагато держав.
Таким чином, блок "try / catch" встановлює стан, до якого можна повернутися, якщо все інше зіпсується. Це як батько. Коли наше життя зіпсується, ми можемо впасти назад у колі наших батьків, і вони знову зроблять це все добре.
Сподіваюся, я вас не розчарував.
Після того, як set_error_handler () визначений, обробник помилок схожий на виняток. Дивіться код нижче:
<?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
?>
Errors are generally unrecoverable
<- насправді це насправді не так.E_ERROR
іE_PARSE
є двома найбільш поширеними невиправні помилки (є кілька інших) , але переважна більшість помилок , які ви побачите в розробника видобувні (E_NOTICE
, іE_WARNING
ін). На жаль, поводження з помилками PHP - це повний безлад - всілякі речі викликають помилки без потреби (наприклад, переважна більшість функцій файлової системи). Загалом винятки становлять "шлях OOP", але, на жаль, деякі з рідних API API PHP використовують помилки замість винятків :-(