Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Обработка ошибок MySQLi
Форумы портала PHP.SU » » Объектно-ориентированное программирование » Обработка ошибок MySQLi

Страниц (2): [1] 2 »
 

1. _Dark_ - 07 Февраля, 2013 - 19:17:01 - перейти к сообщению
Доброго всем дня.
Попытка получить помощь на StackOverflow провалилась, может звезды на небе не так расположились, но на вопрос так внятного ответа я так и не получил, хотя обычно все не так, поэтому решил задать вопрос здесь. Я вообще не активный пользователь, мне документации PHP более чем хватает, но вот такой случай, что нужна помощь сообщества.

Решил вернуться в PHP после некоторого перерыва, начал писать систему "для себя", разработка идет нормально, архитектура системы в общем-то есть, кодовая база тоже есть, но вот остановился на этой проблеме.

Расширение MySQL устарело уже и морально, и вообще, как только можно, вначале я хотел работать с PDO, но пришел к выводу, что это лишнее и что объектно-ориентированного MySQLi мне более чем хватит.

В моей системе все системные ошибки отображаются в виде оформленной страницы, ошибки MySQLi не исключение, поэтому их нужно отлавливать.
В документации продемонстрирован вот такой способ делать это:
PHP:
скопировать код в буфер обмена
  1. if (!$mysqli->query("SET a=1")) {
  2.     exit('An error occurred: ' . $mysqli->error);
  3. }

(простой пример)

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

Само собой я могу наследовать класс mysqli и сделать что-то вроде
PHP:
скопировать код в буфер обмена
  1. class myMysqli {
  2.     public function __construct(/* ... */)
  3.     {
  4.         parent::__construct(/* ... */);
  5.     }
  6.  
  7.     public function query(/* .. */)
  8.     {
  9.         parent::query(/* ... */);
  10.  
  11.         if($this->errno !== 0)
  12.         {
  13.             // An error occurred
  14.         }
  15.     }
  16. }
  17. $mysqli = new myMysqli(/* ... */);
  18. $mysqli->query(/* ... */);


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

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

Как я понял, мне предлагали что-то вроде
PHP:
скопировать код в буфер обмена
  1. try {
  2.     $mysqli->query(/* ... */);
  3. } catch (Exception $e) {
  4.     // An error occurred
  5. }

но я не понимаю, чем это в принципе отличается от окружения блоком if/else.

В общем, сам вопрос: есть ли способ получше, чем переопределять большое количество методов или окружать каждый вызов блоком if/else (try/catch(?))
Возможно, проблема в самой концепции моей идеи, в таком случае я так же буду рад услышать более лучший способ работать с БД (?).

Спасибо.
2. esterio - 07 Февраля, 2013 - 19:25:02 - перейти к сообщению
Самым лучим для меня обьяснением try...catch стал следующий пример

PHP:
скопировать код в буфер обмена
  1. function f1($a)
  2. {
  3.         return f2($a);
  4. }
  5.  
  6. function f2($a)
  7. {
  8.         return f3($a);
  9. }
  10.  
  11. function f3($a)
  12. {
  13.         if(!$a)
  14.                 throw new Exception(__FUNCTION__);
  15.  
  16.         return $a;
  17. }
  18.  
  19. try {
  20.         echo f1('Hello World');
  21.         echo f1(false);
  22. }(Exception $e){
  23.         echo $e->getMessage();
  24. }


Думаю и Вам станет более понятно что ето такое после даного примера. Тепер подумайте если бы нужно было обработать ошыбку на самом верху при визове функции f1 - нужно бы было всюду возвращать false. а так только в одном месте
3. DeepVarvar - 07 Февраля, 2013 - 19:28:45 - перейти к сообщению
_Dark_ пишет:
исключениями, но, честно говоря, я не очень понимаю их концепцию и принцип работы и вообще избегаю их
Зря.
_Dark_ пишет:
есть ли способ получше, чем переопределять большое количество методов или окружать каждый вызов блоком if/else (try/catch(?))
Это и есть тот самый лучший способ.
4. _Dark_ - 07 Февраля, 2013 - 19:29:21 - перейти к сообщению
Я понимаю, что исключение выбрасывается по цепочке вверх, просто не понимаю саму их идею, конкретно зачем это надо и когда их использовать.
5. OrmaJever - 07 Февраля, 2013 - 19:31:59 - перейти к сообщению
_Dark_ пишет:
но я не понимаю, чем это в принципе отличается от окружения блоком if/else.

в том что исключение выйдет из любой вложености и дойдёт до цели (catch)
например

PHP:
скопировать код в буфер обмена
  1. function a1()
  2. {
  3.    throw new Exception("1");
  4. }
  5. function a2()
  6. {
  7.    a1();
  8. }
  9. try {
  10.   for($i=0;$i<10;++$i)
  11.   {
  12.     a2();
  13.   }
  14. } catch(Exception $e) { ... }

исключение попадёт в catch через 2 функции и цикл, а с обычными условиями это наверно выглядело бы так.
PHP:
скопировать код в буфер обмена
  1. function a1()
  2. {
  3.   return false;
  4. }
  5. function a2()
  6. {
  7.    if(a1() === false) return false;
  8. }
  9. for($i=0;$i<10;++$i)
  10. {
  11.   if(a2() === false) break;
  12. }

Вобще сам работаю с бд с помощью mysqli но такой задачи никогда небыло и не задумывался про исключения, и скорее всего mysqli их не кидает, а вот PDO точно знаю что кидает, возможно лучшим вариантом будет использовать его чем переопределять класс mysqli Растерялся
6. DeepVarvar - 07 Февраля, 2013 - 19:32:52 - перейти к сообщению
_Dark_ пишет:
зачем это надо и когда их использовать
А вы попробуйте, вдруг поймете Закатив глазки
7. OrmaJever - 07 Февраля, 2013 - 19:33:29 - перейти к сообщению
_Dark_ пишет:
Я понимаю, что исключение выбрасывается по цепочке вверх, просто не понимаю саму их идею, конкретно зачем это надо и когда их использовать.

когда из-за даной ошибки код дальше не может правельно исполнятся.
8. DeepVarvar - 07 Февраля, 2013 - 19:34:41 - перейти к сообщению
OrmaJever пишет:
mysqli их не кидает
Верно, но всегда можно проверить св-во error завернув это дело в свой трай-кеч
(Добавление)
OrmaJever пишет:
когда из-за даной ошибки код дальше не может правельно исполнятся.
Уточняю: Когда разработчик возжелал такого поведения.
9. _Dark_ - 07 Февраля, 2013 - 19:38:33 - перейти к сообщению
DeepVarvar пишет:
Это и есть тот самый лучший способ.

Хорошо, спасибо.

DeepVarvar пишет:
А вы попробуйте, вдруг поймете

Окружать весь потенциально опасный код блоком try/catch?
10. esterio - 07 Февраля, 2013 - 19:41:04 - перейти к сообщению
Можна и через triger_error как делали бородатые дяди( Радость ) до ПыХы 5, но исключения куда красивей.
(Добавление)
_Dark_ пишет:
Окружать весь потенциально опасный код блоком try/catch?

Можно делать их сколько угодно и вложений тоже можно, главное не пересолить
11. DelphinPRO - 07 Февраля, 2013 - 19:43:42 - перейти к сообщению
Фишка в том, что вы можете выкидывать свой тип исключений, унаследовав его от \Exception и переопределив необходимые методы. Таким образом, вся обработка ошибок (Подготовка сообщений, логирование, etc...) будет сосредоточена в одном месте, а не по всему коду.
12. _Dark_ - 07 Февраля, 2013 - 19:44:40 - перейти к сообщению
Вот фрагмент метода
PHP:
скопировать код в буфер обмена
  1.     /**
  2.      * Запускает приложение
  3.      *
  4.      * @param int       $guid    Глобальный идентификатор приложения
  5.      * @param string    $module Модуль приложения
  6.      * @param string    $action Действие модуля
  7.      * @param array     $params Массив параметров действия модуля
  8.      */
  9.     public function start($guid, $module, $action, $params = array())
  10.     {
  11.         $appDir = $this->getAppDir($guid);
  12.  
  13.         $mainFile = "$appDir/main.php";
  14.         $moduleFile = "$appDir/modules/$module.php";
  15.  
  16.         if (!file_exists($mainFile) || !file_exists($moduleFile)) {
  17.             // TODO: Error
  18.         }

Вызывается вот так:
PHP:
скопировать код в буфер обмена
  1. $registry->application->start($info['app'], $info['module'], $info['action'], $params);

Там где стоит TODO'шка нужно вывести ошибку, для этого исключения можно использовать, если да, то примерно как?
13. esterio - 07 Февраля, 2013 - 19:50:33 - перейти к сообщению
PHP:
скопировать код в буфер обмена
  1. public function start($guid, $module, $action, $params = array())
  2.     {
  3.         $appDir = $this->getAppDir($guid);
  4.  
  5.         $mainFile = "$appDir/main.php";
  6.         $moduleFile = "$appDir/modules/$module.php";
  7.  
  8.         if (!file_exists($mainFile) || !file_exists($moduleFile)) {
  9.             throw new Exception('Error')
  10.         }
  11.         }
  12.  
  13.         try {
  14.                 $registry->application->start($info['app'], $info['module'], $info['action'], $params);
  15.         }(Exception $e){
  16.                 // ...
  17.         }
  18.  
14. _Dark_ - 07 Февраля, 2013 - 19:50:41 - перейти к сообщению
DelphinPRO пишет:
Фишка в том, что вы можете выкидывать свой тип исключений, унаследовав его от \Exception и переопределив необходимые методы. Таким образом, вся обработка ошибок (Подготовка сообщений, логирование, etc...) будет сосредоточена в одном месте, а не по всему коду.

Ну вот смотрите, у меня в index.php есть вызов

Уже оттуда пойдет большая часть работы системы именно насчет запроса, т.е. роутинг, обработка данных, отдача контента.
Например, где-то там, далеко, есть проверка
PHP:
скопировать код в буфер обмена
  1.         $file = JAME_USR . '/data-store/' . $guid . '/' . md5($key) . '.php';
  2.         if (!file_exists($file)) {
  3.             // TODO Error;
  4.         }

Значит ли это, что я могу в index.php сделать вот так:
PHP:
скопировать код в буфер обмена
  1. try {
  2.     \System\Controller::handleRequest();
  3. } catch (\Exception $e) {
  4.     // Произошла ошибка, здесь логирование, события и т.п.
  5. }

А вон там вот так:
PHP:
скопировать код в буфер обмена
  1.         $file = JAME_USR . '/data-store/' . $guid . '/' . md5($key) . '.php';
  2.         if (!file_exists($file)) {
  3.             throw new \Exception('Bla-bla-bla');
  4.         }

Просто не понимаю, ведь я могу в том месте просто вызвать свою ф-ию, например, вот так:
PHP:
скопировать код в буфер обмена
  1.         $file = JAME_USR . '/data-store/' . $guid . '/' . md5($key) . '.php';
  2.         if (!file_exists($file)) {
  3.             $this->registry->fatalError('bla-bla-bla');
  4.         }

(Добавление)
esterio пишет:
PHP:
скопировать код в буфер обмена
  1. public function start($guid, $module, $action, $params = array())
  2.     {
  3.         $appDir = $this->getAppDir($guid);
  4.  
  5.         $mainFile = "$appDir/main.php";
  6.         $moduleFile = "$appDir/modules/$module.php";
  7.  
  8.         if (!file_exists($mainFile) || !file_exists($moduleFile)) {
  9.             throw new Exception('Error')
  10.         }
  11.         }
  12.  
  13.         try {
  14.                 $registry->application->start($info['app'], $info['module'], $info['action'], $params);
  15.         }(Exception $e){
  16.                 // ...
  17.         }
  18.  

Ведь я могу просто вызвать там свою функцию в том месте, которая подготовит сообщение об ошибке, выведет его и exit();
Я прошу прощения, если я кажусь таким вот занудой, просто правда, пока не пойму саму суть будут всякие сомнения по этому поводу Закатив глазки
15. DelphinPRO - 07 Февраля, 2013 - 20:00:48 - перейти к сообщению
ну вы можете еще сделать так
PHP:
скопировать код в буфер обмена
  1. try {
  2.     \System\Controller::handleRequest();
  3. } catch (\FileSystemErrorException $e) {
  4.     // Один тип ошибки
  5. } catch (\Page404Exception $e) {
  6.     // Второй тип ошибки
  7. } catch (\Exception $e) {
  8.     // Хз какая ошибка
  9. }


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

 

Powered by ExBB FM 1.0 RC1