Поводження з помилками в PHP при використанні MVC


12

Я дуже часто використовую Codeigniter останнім часом, але одне, що мені стає на нерви, - це обробляти помилки та показувати їх користувачеві. Я ніколи не мав успіху в обробці помилок, не стаючи безладним. Моя головна проблема - повернення помилок користувачеві.

Чи корисно використовувати винятки та кидати / ловити винятки, а не повертати 0 або 1 з функцій, а потім використовувати if / else для обробки помилок. Таким чином, полегшуючи інформування користувача про проблему.

Я схильний відходити від винятків. Мій викладач Java в університеті кілька років тому сказав мені: "винятки не слід використовувати у виробничому коді, це більше для налагодження". Я відчуваю, що він бреше.

Але, наприклад, у мене є код, який додає користувача до бази даних. Під час процесу більше 1 речі може піти не так, як, наприклад, проблема з базою даних, копія запису даних, проблема із сервером тощо. Коли проблема трапляється під час реєстрації, користувач повинен знати про це.

Який найкращий спосіб вирішити помилки в PHP, маючи на увазі, що я використовую MVC-фреймворк.

Відповіді:


14

Чи корисно використовувати винятки та кидати / ловити винятки, а не повертати 0 або 1 з функцій, а потім використовувати if / else для обробки помилок. Таким чином, полегшуючи інформування користувача про проблему.

Ні-ні-ні!

Не змішуйте винятки та помилки. Винятки є, ну, винятковими. Помилок немає. Коли ви запитуєте користувача ввести кількість товару, а користувач вводить "привіт", це помилка. Це не виняток: немає нічого виняткового в тому, щоб побачити недійсний вхід від користувача. Чому ви не можете використовувати винятки в не виняткових випадках, наприклад, під час перевірки введення? Інші люди це вже пояснили та показали дійсну альтернативу для перевірки введення даних.

Це також означає, що користувач не піклується про ваші винятки , а показ винятків є недоброзичливим і небезпечним . Наприклад, виняток під час виконання запиту SQL часто виявляє сам запит. Ви впевнені, що хочете ризикнути показати таке повідомлення всім?

більше ніж одна річ може піти не так, як, наприклад, проблема з базою даних, копія запису, проблема із сервером тощо. Коли проблема трапляється під час реєстрації, користувач повинен знати про це.

Неправильно. Як користувач, мені не потрібно знати ваші проблеми з базою даних, дублікати записів і т. Д. Мені справді не цікаво ваших проблем. Що мені робити потрібно знати, що я увійшов в ім'я користувача , яке вже існує. Як уже було сказано, неправильне введення від мене повинно викликати помилку, а не виняток.

Як вивести ці помилки? Це залежить від контексту. Для вже використовуваного імені користувача я хотів би побачити невеликий червоний прапор, який з’являється біля імені користувача, перш ніж навіть надсилати форму, кажучи, що ім’я користувача вже використовується. Без JavaScript, той самий прапор повинен з’явитися після надсилання.

Приклад помилки з підтримкою AJAX

У разі інших помилок ви б показали повну сторінку з помилкою або обрали інший спосіб повідомити користувача про те, що щось пішло не так (наприклад, повідомлення, яке з’явиться, а потім зникне вгорі сторінки). Тоді питання стосується більше досвіду користувачів, ніж програмування.

З точки зору програмістів, залежно від типу помилки, ви поширите її різними способами. Наприклад, у випадку вже взятого імені користувача, запит AJAX http://example.com/?ajax=1&user-exists=Johnповернути об'єкт JSON із зазначенням:

  • Що користувач вже існує,
  • Повідомлення про помилку, яке потрібно показати користувачеві.

Важливий другий момент: ви хочете бути впевненим, що те саме повідомлення з’являється і при поданні форми з відключеною JavaScript, і при введенні дубліката імені користувача з увімкненим JavaScript. Ви не хочете дублювати текст повідомлення про помилку у вихідному коді на сервері та в JavaScript!

Це фактично техніка, що використовується на веб-сайтах Stack Exhange. Наприклад, якщо я намагаюся підтвердити власну відповідь, відповідь AJAX містить помилку для відображення:

{"Success":false,"Warning":false,"NewScore":0,"Message":"You can't vote for your own post.",
"Refresh":false}

Ви також можете вибрати інший підхід та встановити помилки на HTML-сторінці до заповнення форми. Плюси: вам не потрібно надсилати повідомлення про помилку у відповіді AJAX. Мінуси: як щодо доступності? Спробуйте переглядати сторінку без CSS, і ви побачите всі можливі помилки.


Я ціную відповідь. Це саме те, з чим я борюся. Чи є у вас ресурси щодо повідомлення про помилки, особливо щодо досвіду користувачів?
Джеймс Джеффі

Ну, як я вже казав, це дійсно залежить від помилки, і повідомлення про помилки користувачеві сильно пов'язане з користувальницьким інтерфейсом. Я також виділив два основні способи повідомляти про помилки: щільна інтеграція (AJAX-червоний прапор біля входу з неправильним значенням) та помилки на повній сторінці, набагато менш дружні, використовувані для більш важких випадків. Це не відповідає на ваше запитання?
Арсеній Муренко

2
+1, оскільки це більше проблема з користувацьким досвідом, а не технічна
Чарльз Спрейберрі

2
Дурень, MainMa. Просто фігня. Коди помилок такі 80-х та 90-х. Винятки - це набагато більш чистий спосіб поводження з особливими обставинами, наприклад, неправильним введенням (наприклад, ValidationException). Ви не змушені показувати користувачеві кожен виняток. Я бачив кращі ваші відповіді.
Сокіл

2
І про всяк випадок, коли ви цього не знали: Ви можете контролювати, які винятки ви хочете представити користувачеві, а які - не бажані. Тож це насправді зовсім не аргумент.
Сокіл

13

Чи корисно використовувати винятки та кидати / ловити винятки, а не повертати 0 або 1 з функцій, а потім використовувати if / else для обробки помилок. Таким чином, полегшуючи інформування користувача про проблему.

Так Так Так!

Якщо ви хочете мати чистий код, ви повинні використовувати виключно винятки і не турбуватися з використанням кодів помилок. Коди помилок безглузді. Вони майже завжди прив’язані до якоїсь числової константи, яка не розкриває багато інформації. Це може зробити ваш код нечитабельним, і їм буде важко поширювати дані поряд із помилкою.

Виняток, однак, становлять класи та можуть містити будь-яку інформацію, яка вам подобається. Таким чином, користувач ввів неправильне введення, наприклад, "abc" для числового поля. За допомогою коду помилки ви не зможете поширювати цю інформацію на оброблювача помилки без великого барботажу. Щось, що винятки передбачають безкоштовно. Крім того, винятки дозволяють мати значущі значення, що повертаються у функціях та методах, при цьому все ще є спосіб вийти з ладу. Ще краще, що винятки поширюються прямо там, де ви хочете обробити їх! Уявіть кількість коду спагетті, який вам знадобиться для розповсюдження коду помилки зі значущими даними для обробника на один або два шари вище.

Крім того, винятки виражають набагато семантичніше, ніж коди помилок. Коди помилок призводять до коду спагетті, де обробка виключень призводить до чистого коду.

Крім того, легко забути перевірити коди статусу. У таких мовах, як Java, ви змушені обробляти винятки (те, що, наприклад, C # не вистачає).

Який найкращий спосіб вирішити помилки в PHP, маючи на увазі, що я використовую MVC-фреймворк.

Використовуйте винятки та обробляйте їх у своїх контролерах.


Я дуже з вами згоден !! Хоча винятки не настільки примусові n PHP, як на інших мовах, добре знати, що багато людей їх включають ...
Девід Конде

6
Я згоден, що в більшості випадків коди помилок є досить безглуздими. Однак кидати винятки мимоволі невільно вкрай погано! Винятки мають бути зарезервовані лише для виняткових обставин. Винятки спричиняють непередбачуваний потік програми, можуть зробити код важким для дотримання (і тому підтримувати), а в PHP вони несуть досить значну штрафну ефективність порівняно з IF / THEN / ELSE. Я, як правило, віддаю перевагу методам повернути правду на успіх, помилково на невдачу, і лише викинути виняток, якщо щось піде зовсім не так.
GordonM

6

Розглянемо цей зручний маленький клас:

class FunkyFile {               

    private $path;
    private $contents = null;

    public function __construct($path) { 
        $this->setPath($path); 
    }

    private function setPath($path) {
        if( !is_file($path) || !is_readable($path) ) 
            throw new \InvalidArgumentException("Hm, that's not a valid file!");

        $this->path = realpath($path);
        return $this; 
    }

    public function getContents() {
        if( is_null($this->contents) ) {
            $this->contents = @file_get_contents( $this->path );
            if($this->contents === false) 
                throw new \Exception("Hm, I can't read the file, for some reason!");                                 
        }

        return $this->contents;            
    }

}

Це виключно прекрасне використання винятків. З FunkyFile'sточки зору абсолютно нічого не можна зробити, щоб виправити ситуацію, якщо шлях недійсний або file_get_contentsне виконаний . Справді виняткова ситуація;)

Але чи є якесь значення для вашого користувача, щоб знати, що ви натрапили на неправильний шлях до файлу, десь у вашому коді? Наприклад:

class Welcome extends Controller {

    public function index() {

        /**
         * Ah, let's show user this file she asked for
         */                 
        try {
            $file = new File("HelloWorld.txt");
            $contents = $file->getContents();   
            echo $contents;
        } catch(\Exception $e) {
            log($e->getMessage());

            echo "Sorry, I'm having a bad day!"; 
        }                           
    }        
}

Крім того, щоб сказати людям, що у вас поганий день, ваші варіанти:

  1. Відступати

    Чи є у вас інший спосіб отримання інформації? У моєму простому прикладі вище це не здається ймовірним, але розглянемо схему бази даних master / slave. Майстер, можливо, не зміг відповісти, але, можливо, просто раб все ще там (або навпаки).

  2. Це вина користувача?

    Чи подав користувач несправний ввід? Ну, скажи їй про це. Ви можете або забракувати повідомлення про помилку, або бути приємним та супроводжувати це повідомлення про помилку формою, щоб вона могла набрати правильний шлях.

  3. Це ваша вина?

    Під вами я маю на увазі все, що не є користувачем, і це означає , що ви вводите неправильний шлях до файлу, і щось не відбувається на вашому сервері. Власне кажучи, настав час помилки HTTP 503 , оскільки послуга недоступна. CI має show_404()функцію, яку ви можете легко побудувати show_503().

Порада, вам слід врахувати шахрайські винятки. CodeIgniter - це безладний фрагмент коду, і ви ніколи не знаєте, коли з’явиться виняток. Так само ви можете забути про власні винятки, і найбезпечнішим варіантом є реалізація обробника винятків для всіх. У PHP це можна зробити за допомогою set_exception_handler :

function FunkyExceptionHandler($exception) {
    if(ENVIRONMENT == "production") {
        log($e->getMessage());
        show_503();
    } else {
        echo "Uncaught exception: " , $exception->getMessage(), "\n";
    }   
}

set_exception_handler("FunkyExceptionHandler");

Ви також можете потурбуватися про шахрайські помилки через set_error_handler . Ви можете або записати той же обробник, що і для винятків, або ж альтернативно перетворити всі помилки ErrorExceptionі дозволити вашому оброблювачу винятків вирішувати їх:

function FunkyErrorHandler($errno, $errstr, $errfile, $errline) {
    // will be caught by FunkyExceptionHandler if not handled
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("FunkyErrorHandler");

Це було справді інформативно, ура!
Джеймс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.