Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Jak duży blok try catch
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
hugo_amv
Na pewnej mądrej stronie ( nie pamiętam jakiej, może na java.sun.com, ale na pewno źródło było dość pewne) spotkałem się z opinią, że nie powino się umieszczać duży bloków kodu pomiędzy try catch, a jedynie krótkie fragmetny kodu i odrazu przechwytywać błędy. Ja wolę wszystkie wyjątki przechwytywać w silniku strony, a dopiero potem zajmować się ich obsługą.

  1. <?php
  2. try{
  3. /**
  4.  * Tutaj różne moduły, uruchamiaja różne klasy,
  5.  * które zwracają różne wyjątki :)
  6.  */
  7. }catch (SQLException $e){
  8. // Obługa wyjątków związanych z bazą danych
  9. echo $e;
  10. }catch (FileException $e){
  11. // Inny typ wyjątków
  12. echo $e;
  13. }catch (Exception $e){
  14. // Pozostałe rodzaje błędów
  15. }
  16. ?>


Jednak na tamtej stronie było wyraźnie napisane, że jest to złą praktyką programistyczną. Jak to w końcu jest?
SongoQ
No pomysl sobie czy jesli bedziesz mial powiedzmy tysiac lini kodu i rzuci CI wyjatek czy aby wszystko dobrze potrafisz osbluzyc i bedziesz wiedzial w ktorym miejscu to wystapilo. Zaleceniem jest stosowanie jak najmniejszej ilosci kodu w bloku try
zulus
Wyobraź sobie że moduł napiszę Ci ktoś inny. Z kąd będziesz wiedział czy nie stworzy nowego wyjątku, i jak go obsłużyć.

Po za tym im mniejsze bloki try, tym mniej wyjątków umieścisz jednocześnie, więc mniej siedzi w pamięci (oszczędność zasobów winksmiley.jpg)
hugo_amv
Cytat(SongoQ @ 3.06.2006, 13:28 ) *
No pomysl sobie czy jesli bedziesz mial powiedzmy tysiac lini kodu i rzuci CI wyjatek czy aby wszystko dobrze potrafisz osbluzyc i bedziesz wiedzial w ktorym miejscu to wystapilo. Zaleceniem jest stosowanie jak najmniejszej ilosci kodu w bloku try

Tworze klasy dziedziczące po Exception i jestem w stanie każdy wyjątek odpowiednio obsłużyć. Jak padła baza danych to wyświetla się 'awaria bazy danych, przepraszamy', jak użytkownik nie ma praw dostępu do pliku to inny komunikat.

Cytat(zulus @ 3.06.2006, 13:47 ) *
Wyobraź sobie że moduł napiszę Ci ktoś inny. Z kąd będziesz wiedział czy nie stworzy nowego wyjątku, i jak go obsłużyć.

Jak ktoś inny stworzy moduł to będzię musiał ze mną skontaktować jakie może zwracać wyjątki smile.gif A tak poważnie to tu masz racje, mała niedogodność.
Cytat(zulus @ 3.06.2006, 13:47 ) *
Po za tym im mniejsze bloki try, tym mniej wyjątków umieścisz jednocześnie, więc mniej siedzi w pamięci (oszczędność zasobów winksmiley.jpg)

Wydaje mi się, że tylko jeden wyjątek jest zgłaszany ( umieszczany w pamięci), a nie wszystie pokolei, a program odrazu przechodzi do pierwszego napotkanego boku catch.
sobstel
Cytat(zulus @ 3.06.2006, 15:47 ) *
Wyobraź sobie że moduł napiszę Ci ktoś inny. Skąd będziesz wiedział czy nie stworzy nowego wyjątku, i jak go obsłużyć.


aby zbierać nieprzewidziane pierwotnie wyjątki, na samym końcu łańcucha jest :

  1. <?php
  2. }catch (Exception $e){
  3. // Pozostałe rodzaje błędów
  4. }
  5. ?>



co do samego tematu to osobiście ciągle nie widzę dlaczego jest to złą praktyką programistyczną (może jakieś linki z krwi i kości a nie suche słowa?). przechwytywanie i obsluga bledow w jednym miejscu sprzyja przejrzystosci, a po to mam takie narzedzia jak backtrace zeby dojsc do tego gdzie i dlaczego blad ten wystapil.
zulus
Cytat(hugo_amv @ 3.06.2006, 16:06 ) *
Wydaje mi się, że tylko jeden wyjątek jest zgłaszany ( umieszczany w pamięci), a nie wszystie pokolei, a program odrazu przechodzi do pierwszego napotkanego boku catch.

W sumie to się za bardzo rozpędziłem. Może inaczej. php po wyrzuceniu wyjątku przecodzi na koniec try{} i przechodzi przez wszystkie catch aż znajdzie odpowiedni. Przy dużej ilości wyjątków po jednym catch może to na prawdę trochę zająć.


Wiesz co do obsługi nieznanych wyjątków. Po to się tworzy nowe typy wyjątków żeby je odpowiednio obsłużyć. Reszte możesz co najwyżej wyświetlić albo zrobić ew jeszcze switch{}(w domyslnym bloku) i sprawdzać kody błędów. TYLKO PO CO? Czytelność i przenośność to podstawa.

Masz tu chipotetyczną sytuację.
Tworzysz jakąś klasę np do obsługi księgi gości. Genreuje ona ew kilka charakterystycznych wyjątków. Jeżeli to twój projekt to pozostaje Ci tylko przekopiowanie wszystkich bloków catch które dotyczą tych wyjątków (tutaj łatwo o pomyłkę) i wklejenie ich do nowego projektu.
Gorzej jeżeli to projekt zewnętrzny(jak większy to pewnie jeszcze z wykorzystaniem MVC). Z resztą wyjątki możesz podzielić na 2 grupy:
1. Te które może obsłużyć sam moduł.
2. Te które wymagają akcji konkretnego programisty.
Skąd możesz wiedzieć czy ICH projekt też jest cały w try{}. Może zależnie od widoku admin będzie chciał inaczej obsłużyć konkretny wyjątek? I za każdym razem wklejanie kodu z catch{} wyjątków typu 1 tam gdzie używasz klasy/modułu? Masz wtedy trochę zabawy. :/

Ale to moje zdanie. Jak obsługuję wyjątki odrazu to się potem nie zastanawiam czy na pewno zająłem się wszystkim, zwłaszcza jak robię coś większego.
hugo_amv
Cytat(zulus @ 3.06.2006, 15:11 ) *
W sumie to się za bardzo rozpędziłem. Może inaczej. php po wyrzuceniu wyjątku przecodzi na koniec try{} i przechodzi przez wszystkie catch aż znajdzie odpowiedni. Przy dużej ilości wyjątków po jednym catch może to na prawdę trochę zająć.

Masz na myśli dużej ilości rodzajów wyjątków (różne klasy wyjątków)? U mnie nie ma dużej liczby 3, 4 podstawowe klasy wyjątków, reszta do domyślnego boku catch
Cytat(zulus @ 3.06.2006, 15:11 ) *
Wiesz co do obsługi nieznanych wyjątków. Po to się tworzy nowe typy wyjątków żeby je odpowiednio obsłużyć. Reszte możesz co najwyżej wyświetlić albo zrobić ew jeszcze switch{}(w domyslnym bloku) i sprawdzać kody błędów. TYLKO PO CO? Czytelność i przenośność to podstawa.

No właśnie! Moim zdaniem obsługa wyjątków jednym miejscu jest bardziej czytelna niż rozdzielanie tego na kilka/ kilkanaście bloków try catch
Cytat(zulus @ 3.06.2006, 15:11 ) *
Masz tu chipotetyczną sytuację.
Tworzysz jakąś klasę np do obsługi księgi gości. Genreuje ona ew kilka charakterystycznych wyjątków. Jeżeli to twój projekt to pozostaje Ci tylko przekopiowanie wszystkich bloków catch które dotyczą tych wyjątków (tutaj łatwo o pomyłkę) i wklejenie ich do nowego projektu.

Nierozumiem co gdzie wklejam smile.gif
Cytat(zulus @ 3.06.2006, 15:11 ) *
Gorzej jeżeli to projekt zewnętrzny(jak większy to pewnie jeszcze z wykorzystaniem MVC). Z resztą wyjątki możesz podzielić na 2 grupy:
1. Te które może obsłużyć sam moduł.
2. Te które wymagają akcji konkretnego programisty.
Skąd możesz wiedzieć czy ICH projekt też jest cały w try{}. Może zależnie od widoku admin będzie chciał inaczej obsłużyć konkretny wyjątek? I za każdym razem wklejanie kodu z catch{} wyjątków typu 1 tam gdzie używasz klasy/modułu? Masz wtedy trochę zabawy. :/

Jeżeli pisze jakiś moduł / klase do istniejącego już projektu to najpierw czytam jego dokumentacje, komentarze w kodzie, a potem w zależności jak autor rozwiązał mechanizm obsługi wyjątków dostosowuje swój moduł.

A gdy ktoś będzie chciał napisać moduł do mojego projektu smile.gif lub wykorzystać moją klase do komunikacji z bazą danych, zapozna się z kodem (komentarzami) i zobaczy, że zwraca ona wyjątek SQLException, który musi obsłużyć.

Może jestem wyjątkowo uparty, ale narazie żadne argumenty to mnie nie trafiają. Nie otrzymałem jednoznaczej odpowiedzi co jest złego w moim podejściu do łapania wyjątków. Jeśli pracuje w zespole to zasady są odgórnie ustalone. Albo jest po mojemu albo po waszemu winksmiley.jpg
Ludvik
Powszechnie używa się jednego typu wyjątków w całej bibliotece, co nie znaczy, że ten wyjątek w każdej sytuacji znaczy to samo. Przyglądnij się na przykład PDO, które zawsze wyrzuca PDOException. Jeżeli w jednym bloku try będziesz przechwytywał wyjątki z konstruktora i wywołań kilku zapytań, to po prostu zgubisz się i nie będziesz wiedział co się stało. Poza tym pisanie w długim bloku try i wyłapywanie n wyjątków jest po prostu nieeleganckie i mało wydajne. Co do czytelności... nie sądzę, żeby było czytelne oczekiwanie na wyjątek, w miejscu, w którym nie wystąpi. Chyba, że u ciebie w większości instrukcji w bloku try mogą zostać wyrzucone wyjątki. Jest jeszcze jedna sytuacja, w której można przywrócić poprawne działanie skryptu poprzez wykonanie konkretnych instrukcji po przechwyceniu wyjątku. W tym przypadku rozdzielenie kodu na kilka bloków jest konieczne.
hugo_amv
Cytat(Ludvik @ 3.06.2006, 17:08 ) *
Powszechnie używa się jednego typu wyjątków w całej bibliotece, co nie znaczy, że ten wyjątek w każdej sytuacji znaczy to samo. Przyglądnij się na przykład PDO, które zawsze wyrzuca PDOException. Jeżeli w jednym bloku try będziesz przechwytywał wyjątki z konstruktora i wywołań kilku zapytań, to po prostu zgubisz się i nie będziesz wiedział co się stało.

Wyjątek wyrzuca treść błedu oraz kod błędu. Wieć nierozumiem po co piszesz, że wyrzucone wyjątki nie zawsze znaczą to samo? Przecież to oczywiste. Jak będe wiedział co się stało? Będe miał kod błędu i treść.
Cytat(Ludvik @ 3.06.2006, 17:08 ) *
Poza tym pisanie w długim bloku try i wyłapywanie n wyjątków jest po prostu nieeleganckie i mało wydajne.

Ale dlaczego jest nieelegackie? Dlaczego mało wydajne? Argument o małej wydajności zbiłem na samym początku. Musisz czymś poprzeć swoje tezy smile.gif a nie pisać, że coś jest brzydkie bo jest brzydkie...
Cytat(Ludvik @ 3.06.2006, 17:08 ) *
Co do czytelności... nie sądzę, żeby było czytelne oczekiwanie na wyjątek, w miejscu, w którym nie wystąpi.
Chyba, że u ciebie w większości instrukcji w bloku try mogą zostać wyrzucone wyjątki.

Ale skoro łapie wyjątki z całego kodu aplikacji to na pewno gdzieś te wyjątki są generowane.
Cytat(Ludvik @ 3.06.2006, 17:08 ) *
Jest jeszcze jedna sytuacja, w której można przywrócić poprawne działanie skryptu poprzez wykonanie konkretnych instrukcji po przechwyceniu wyjątku. W tym przypadku rozdzielenie kodu na kilka bloków jest konieczne.

Jaka to sytuacja, podaj przykład?
Termit_
A ja pytam po co do żądania o wyświetlenie newsa wraz z komentarzami wysyłać do parsera php kod odpowiedzialny za obsługę wyjątków LoginErrorException czy GalleryImageUploadException? Bo skoro WSZYSTKIE typy wyjątków chcecie mieć w jednym miejscu... przy dużym projekcie to może być spory kawał zbędnego kodu, który można by przenieść do /login.phpm czy /admin/gallery.phpm.
hugo_amv
Cytat(Termit_ @ 3.06.2006, 18:36 ) *
A ja pytam po co do żądania o wyświetlenie newsa wraz z komentarzami wysyłać do parsera php kod odpowiedzialny za obsługę wyjątków LoginErrorException czy GalleryImageUploadException? Bo skoro WSZYSTKIE typy wyjątków chcecie mieć w jednym miejscu... przy dużym projekcie to może być spory kawał zbędnego kodu, który można by przenieść do /login.phpm czy /admin/gallery.phpm.

Hm.. tu akurat masz racje jeśli by wszystkie wyjątki przychwytywać w jedym miejscu. Ale ja nie napisałem, że wszystkie wyjątki mają być łapane w jednym miejscu. Po pierwsze zakładam, że nie każda klasa ma obsługę błędów poprzez wyjątki. Czasem wystarczy sprawdzić czy np. $user->isLogin() zwraca true. Na końcu kodu przechwycam tylko ważne wyjątki (informujące o braku możliwości wykonania jakieś ważnej operacji: na bazie danych, systemie plików) Zamiast GalleryImageUploadException byłby tylko jeden wyjątek FileException z klasy odpowiedzialne za zarządzanie plikami.

Nikt nie zabrania używania krótkich bloków try catch wewnątrz modułów czy klas. Wyjątek klasy SQLException i tak znajdzie swój blok catch, który go obsłuży.
Ludvik
Cytat
Wyjątek wyrzuca treść błedu oraz kod błędu. Wieć nierozumiem po co piszesz, że wyrzucone wyjątki nie zawsze znaczą to samo? Przecież to oczywiste. Jak będe wiedział co się stało? Będe miał kod błędu i treść.

I co zrobisz z treścią czy kodem? Będziesz sprawdzał switchem po kolei kody czy opisy błędów? To zajmuje dużo miejsca i nikt, kto popatrzy na taki kod, nie będzie zachwycony, szczególnie, kiedy będzie musiał dowiedzieć się o co w nim chodzi... Wykorzystując cudzą bibliotekę możesz dostawać puste wyjątki, wtedy nie będziesz miał innego wyjścia.

Cytat
Ale skoro łapie wyjątki z całego kodu aplikacji to na pewno gdzieś te wyjątki są generowane.

Na pewno gdzieś są generowane. To teraz powiedz mi, czy łatwiej ci będzie czytać kod, w którym wyjątek może być wyrzucany w 100 czy w 5 miejscach? Po co wprowadzać zamieszanie sygnalizując możliwość wystąpienia błędu w miejscu, w którym go na pewno nie będzie...

Cytat
Jaka to sytuacja, podaj przykład?

Chociażby próba uruchomienia jakiejś akcji przez kontroler MVC. Wyjątek zwraca fabryka w przypadku braku klasy reprezentującej tą akcję. Łańcuch akcji u mnie przyjmuje postać pętli. Zawsze mogę wciąż w tej samej pętli wyłapać wyjątek i użyć domyślnej nazwy akcji nie wychodząc z łańcucha. Nie obejmuję blokiem try...catch całego kontrolera.

Termit pokazał Ci, że możesz mieć problem z ilością wyjątków. Twoim rozwiązaniem jest uogólnienie podobnych klas. Tracisz możliwość rozróżniania wyjątków po nazwach. Jeżeli w jednym bloku wyjątek może wyrzucić ci moduł obsługujący upload plików, moduł cache i jeszcze trzeci inny, to nie dowiesz się, która klasa odpowiada za błąd. Wtedy prawdopodobnie poprzenosisz różne moduły do różnych bloków.

Tak jak pisałem, wstawianie wielkiego bloku try...catch wpływa negatywnie na estetykę kodu. Nie mówię tego, bo tak mi się podoba, tylko dlatego, że swoje widziałem i wiem, który kod mi się lepiej czyta.
Termit_
No, z takim czymś się jak najbardziej zgodzę. Ja również łapię kilka głównych wyjątków w bloku obejmującym niemal całą stronę. Później przerzucam to do funkcji handleError(Exception $e), w której badam już po instanceof (tam mam optException dla szablonów, ADODB_Exception dla kontrolera bazy danych, NoPageException dla żądań typu /blabla/ (404), ClassNotFoundException dla autoloadera i RedirectException kiedy wystąpi błąd przekierowania).

Po co funkcja? Funkcja po to, że jeśli tylko się da próbuję zachować GUI (za pomocą systemu szablonów).
bigZbig
Przede wszystkim wyjatek nie jest tozsamy z pojeciem bledu. Wyjatkow mozna uzywac niemalze tak samo jak warunku if i else. Zacznijcie myslec o blokach try i catch tak jak o if i else. Przecierz wyjatek rzucany jest wtedy kiedy nie zostanie spelniony pewien warunek. Od programisty zalezy czy bedzie to warunek krytyczny niezbedny dla prawidlowego funkcjonowania aplikacji czy tez warunek jedynie zmieniajacy sposob dzialania tej aplikacji, ale w sposob przewidziany i dopuszczalny.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.