podgur
30.03.2010, 21:23:32
Witam. Chciałem się dowiedzieć, kiedy NALEŻY stosować wyjątki w OOP? Chodzi mi o konkretne przykłady i jakieś dobre wytłumaczenie.
Wyjątki jak sama nazwa wskazuje, ale np .
Kod
$a=5;
$b=0;
if($a<$5){
...
}
Też mogli byśmy użyć wyjątków? i czy powinno się?
bless
zend
30.03.2010, 21:38:56
function getDb() {
$database = mysqli();
if(!$database)
throw new Exception('xxx');
}
/*
* @returns array
* */
function getNews()
{
$db = getDb();
$db -> query('select * ...');
$results = array(); //tablica z wynikami return $results;
}
/*
* @returns mixed
* */
function getNewsNoException()
{
$db = getDb(); //gdyby baza danych nie wyrzucała wyjątków
if(!$db)
return false;
$results = array(); //tablica z wynikami return $results;
}
function index()
{
doSomethingWithArray(getNews());
$news = getNewsNoException();
if($news != false)
doSomethingWithArray($news);
}
Przeanalizuj ten kod, to powinno Ci się rozjaśnić, wyjątki znacznie upraszczają tworzenie aplikacji, nie musisz wszystkiego if'ować żeby się upewnić ze watrość jest ok
podgur
30.03.2010, 21:49:52
No tak, ale czy zamiast
Kod
function getDb() {
$database = mysqli();
if(!$database)
throw new Exception('xxx');
}
damy
Kod
function getDb() {
$database = mysqli();
if(!$database)
echo "Komunikat";
exit;
}
Dlatego czemu powinno się używać wyjątków?
Wyjątki
nie należą do programowania obiektowego. W wielu językach wyjątkiem może być cokolwiek - liczba, tekst, obiekt... jedyna rzecz wspólna z OOP w PHP to właśnie wymóg, że wyjątek musi być obiektem mającym gdzieś klasę
Exception.
Trochę praktycznych przykładów dotyczących wyjątków jest tutaj:
http://pl.wikibooks.org/wiki/PHP/WyjątkiWyjątki rozwiązują następujący problem: w jakiejś funkcji powstał błąd, ale czy dla tego, kto ją wywołał, jest on krytyczny czy nie? Co więcej - czy na błąd reagować ma ten, kto funkcję wywołał czy jakiś nadrzędny strażnik? Aby zaprogramować to przy pomocy ifów, funkcji itd. musiałbyś się sporo naklepać. Zamiast tego, po prostu rzucasz wyjątek. Ktoś "u góry" musi go odebrać i zdecydować, co z nim robić. Jako przykład może posłużyć jakaś biblioteka umożliwiająca chodzenie po katalogach. Chcemy utworzyć plik w jakimś katalogu, więc wywołujemy funkcję
createFile(). Jednak okazało się, że dany katalog nie istnieje, dlatego funkcja rzuca nam wyjątek. Jeśli realizujemy polecenie użytkownika "utwórz plik", możemy właśnie teraz zdecydować, że w tym przypadku błąd jest krytyczny i poinformować go o tym. Ale przecież
createFile() może być wywoływana przez inną funkcję biblioteki, która przy okazji musi stworzyć plik, a jeśli się nie uda, zająć się czymś innym. Tym razem otrzymanie wyjątku nie oznacza błędu krytycznego. Dlatego robimy:
Kod
try
{
createFile();
robA();
}
catch(Exception $wyjatek)
{
robB();
}
I zupełnie nie zajmujemy się treścią wyjątku, ponieważ on służy nam jedynie do dowiedzenia się, że pliku nie da się utworzyć (np. już istnieje), więc możemy to olać i zająć się dalszą częscią zadania.
W swoim kodzie wyjątki rzucam wszędzie tam, gdzie stwierdzam, że jest coś, czego nie powinno być, albo na odwrót - nie ma czegoś, co być powinno. Każde odstępstwo od spodziewanego w danym miejscu stanu jest raportowane w ten sposób (wbrew pozorom nie ma tego tak dużo, a już na pewno nie prowadzi to do sytuacji, gdy na 1000 linijek 500 to instrukcje
throw 
), dzięki czemu przy wywoływaniu danego kawałka kodu mam możliwość zdecydowania, co zrobić z ewentualnymi błędami.
podgur
31.03.2010, 07:22:42
Wiem że nie należy, ale zazwyczaj używa się ich w OOP z tego co czytałem.
Ok już rozumiem jak to działa, tylko nadal nurtuje mnie to, kiedy używać wyjątków a kiedy po prostu zwykłych funkcji warunkowych..
nospor
31.03.2010, 07:38:07
To zrob eksperyment:
raz uzywaj zwyklych IF a raz uzywac wyjątków. Napisz w ten sposob jeden projekt a sam stwierdzisz co ci wygodniej.
thek
31.03.2010, 09:19:32
Jak sama nazwa mówi, wyjątki powinno się stosować w sytuacjach możliwego, nietypowego zachowania skryptu. Niektórzy stosują to rozwiązanie jako swego rodzaju strukturę kontrolną, ale to moim zdaniem nadużywanie. Jako że często to jest stosowana rzecz w C++ i Javie to tutoriale tych języków tyczące najczęściej w najprostszy i najbardziej przystępny sposób stosowanie wyjątków opisują. Tam pojawią się zresztą nie tylko throw, try, catch, ale choćby rethrow, które także z wyjątkami jest związane.
podgur
31.03.2010, 09:22:58
W przypadku np. połączenia z baza danych i połączenie nie wykona się poprawnie powinno się
np. użyć wyjątków, tak?
a jak się validuje dane od użytkownika i np. sprawdza się czy zmienne nie są puste, to wystarczy użyć f. warunkowej?
zend
31.03.2010, 15:38:48
Tak, błąd przy wprowadzaniu danych od użytkownika nie jest sytułacją wyjątkową, więc wyjątki są nie na miejscu lepiej if'ować.
Natomiast gdybyś nie mógł odczytać danych z katalogu (co zawsze powinno się udać) najlepiej zastosować wyjątki. Sama teoria niewiele Ci da, sam musisz zaczą pisać, to zrozumiesz kiedy używać wyjątków a kiedy if'ować
podgur
1.04.2010, 22:18:07
zend dziękuje:) Posłucham się i poćwiczę

Pozdrawiam
Na podstawie waszych odpowiedzi, napisałem klasę do tworzenia miniatur.
Proszę o ocenę skryptu:) Napiszcie co można poprawić itd.
Za odpowiedzi dziękuje:)
Kod
<?php
//Autor: Podgur
class ImageException extends Exception {
public function __toString() {
$ret = 'Powstal blad<br />
Komunikat: '.$this->getMessage().'<br />Plik: '.$this->getFile().'<br />Wiersz: '.$this->getLine();
return $ret;
}
}
class ImageClass
{
public $image;
//konstruktor pobierający obrazek
function __construct($url)
{
//Sprawdzanie czy istnieje plik graficzny podany w konstruktorze
if(!file_exists($url))
{
//W przypadku nie istnienia pliku
throw new ImageException('Podany plik nie istnieje');
}else{
$this->image=$url;
}
}
public function resize($height,$width,$quality=60)
{
//Brak obsługi formatu png i bmp
//Pobranie nazwy pliku
$namefile = $this->image;
//Wycięcie rozszerzenia
$type = substr(strstr($namefile,'.'),1);
//Tablica z formatami
$rozszerzenia=array("jpg","jpeg","gif");
if(!in_array($type,$rozszerzenia))
{
throw new ImageException('Zly format pliku');
}
//Nagłówek
header("Content-Type: image/$type");
switch($type){
//Rozszerzenie *.jpg/jpeg
case "jpg":
$img = imagecreatefromjpeg($this->image);
break;
//Rozszerzenie *.gif
case "gif":
$img = imagecreatefromgif($this->image);
break;
}
$mini = imagecreatetruecolor($width,$height);
//Stworzenie miniatury
imagecopyresized($mini,$img,0,0,0,0,$width,$height,imagesx($img),imagesy($img));
switch($type){
//Rozszerzenie *.jpg/jpeg
case "jpg":
imagejpeg($mini, "mini".rand(1,100)."_$namefile", 70);
break;
//Rozszerzenie *.gif
case "gif":
imagegif($mini, "mini".rand(1,100)."_$namefile", 70);
break;
}
}
}
try
{
//wywolanie obiektu klasy. Jako parametr dajemy scieżke, bądź nazwę pliku
$photo = new ImageClass('a.jpg');
//wywolanie metody resize()
$photo->resize(1000,1000); //Przyjmuje 3 parametry: wysokosc,szerokosc i jakość miniatury
}
catch(ImageException $error)
{
echo $error;
}
?>
Crozin
2.04.2010, 00:05:27
Po co jakieś ImageException, które jedyne co robi to formatuje treść błędu (czego robić na dobrą sprawę nie powinno)? Co innego jeżeli byłoby to używane w celu wyłapania tego typu wyjątku w bloku catch, ale z tego co widzę to tutaj jedyny cel istnienia bloku catch, to wywalenie błędu.
Zamiast
ImageException('Podany plik nie istnieje') wolałbym otrzymać wyjątek typu: IOException, w którym jako parametr byłby przekazany URL obrazka itp., niż bardzo niewygodną w dalszej obróbce informację "obrazek nie istnieje".
Swoją drogą... nie stosuj zapisu typu:
if (...) {
throw..
} else {
//reszta kodu
}
Wystarczy:
if (...) {
throw..
}
//reszta kodu
Im mniej klamerek tym zazwyczaj lepiej.
ImageClass::$image (to Class to sobie daruj) mogłoby być już "zasobem" (wynikiem imagecreateformXXX() lub czegoś w tym stylu (jeżeli nie korzystałbyś z biblioteki GD).
Do pobrania rozszerzenia z ścieżki służy
pathinfoSprawdzaj czy aby przypadkiem wygenerowana nazwa pliku już nie istnieje.
Po co nagłówek Content-Type, skoro plik tylko zapisujesz, a nie wyświetlasz?
podgur
2.04.2010, 08:40:38
Zaraz pozmieniam:) dzięki.
Jeżeli ktoś ma jeszcze jakieś uwagi,to zapraszam:)
Postanowiłem mój pierwszy post, napisać właśnie w tym temacie. Może ktoś byłby mi w stanie rozjaśnić...
Czy w PHP istnieją jakieś standardowe funkcje rzucające wyjątki? Czy jest to tylko dodatkowy mechanizm który za każdym razem trzeba implementować samemu?
Próbuję porządnie zabrać się za te wyjątki, ale mam jakiś niesmak konwertując błędy na wyjątki
Fifi209
20.02.2011, 00:20:13
"Standardowo"
PDO rzuca wyjątkami z tego co pamiętam.
darko
20.02.2011, 00:23:17
Orzeszekk
31.10.2011, 11:37:42
Cytat(zend @ 31.03.2010, 15:38:48 )

Tak, błąd przy wprowadzaniu danych od użytkownika nie jest sytułacją wyjątkową, więc wyjątki są nie na miejscu lepiej if'ować.
Natomiast gdybyś nie mógł odczytać danych z katalogu (co zawsze powinno się udać) najlepiej zastosować wyjątki. Sama teoria niewiele Ci da, sam musisz zaczą pisać, to zrozumiesz kiedy używać wyjątków a kiedy if'ować
Przepraszam ze odkopie temat ale jest to dla mnie kompletnie niezrozumialem i chcialbym sie dowiedziec dlaczego akurat tak.
Dlaczego w sytuacji gdy wygodnie jest mi rzucic wyjatek gdy user wpisze błędne dane i zlapac go jeszcze w mojej klasie (zrobic specyficzna klasy błędów), zrobic sobie w swojej klasie bloki try catch dla roznych rodzajow moich błędów (i dodatkowo jesli kiedys mi sie zachce zmienic sposob reagowania na bledy to zmieniam to jedna linijka) mam robic ify i pisac 10x tyle kodu, i w razie zmiany reagowania na bledy wszystko lopatologicznie przepisywac.
Dla mnie gdy user tworząc jakis event gdzie jest potrzebna do utworzenia data jego startu, i wpisze sobie tam aa-aaaa-aa zamiast daty to i tak mu nie utworze tego eventu wiec to jest bląd krytyczny ktory powinien przerwac normalny bieg programu i spowodowac wyswietlenie komunikatu co user wpisal nie tak.
Crozin, styrałeś kolegę ze to niewygodne w obróbce bla bla bla. Co za problem dodac do klasy ImageException metode getErrorFilepath() i pole $filepath, a do konstruktora dodac dodatkowy parametr $filePath? A co jak komus sie zapomni przechwycic wyjątku i dopisac sensowny komunikat o bledzie do nazwy pliku?
Jako uzytkownik wolalbym dostac z dwojga zlego komunikat "nie odnaleziono pliku" niz "C:\windows\plik.txt".
darko
31.10.2011, 11:57:23
~Orzeszekk walidacja danych pochodzących od użytkownika to jest zwyczajna, normalna sytuacja, w której należy dane walidować i odpowiednio zareagować. Chodzi o to, że nie jest to nic nadzwyczajnego, z czym nawet przeciętnie napisana aplikacja nie mogłaby sobie poradzić, tym bardziej nie jest to sytuacja, której nie przewidział autor kodu. Tłumaczenie stosowania wyjątków i korzystanie z nich, gdzie popadnie, dla wygody, to nie jest - z wielu powodów - dobre podejście do tematu. Po pewnym czasie dojdziesz do sytuacji, w której atomowe operacje będą rzucały wyjątki, a kod aplikacji straci na czytelności. Wszystko to ma wpływ na późniejsze tzw. koszty konserwacji kodu.
Orzeszekk
31.10.2011, 14:25:07

OK, nie rozumiem nadal

ja jako autor kodu przewiduje i zakładam ze ktos mi poda poprawną datę a jak ktos wpisze błędną to jest to sytuacja wyjątkowa

Chodzi o to ze np. gdy ktos wpisze stringa o dlugosci 300 w pole do 255 to moge tego stringa obciac i nie musze rzucac wyjątku , jednak z daty "reghbgfww" zadnej sensownej wartosci nie zrobie, wiec dalsze wykonanie programu jest bez sensu wiec czemu nie skorzystac z wyjątku. Tym bardziej ze mechanizm wyjątków pozwala na zrobienie wyjatkow o roznym stopniu "błędności" i rozroznianie ich między sobą,
i mozna uzyc jednych klas wyjątków do oznaczania błędów - sytuacji wyjątkowych, a drugich - by uproscic sobie prace z walidatorem.
idąc twoim tokiem rozumowania co twój, źle napisany SQL string to rowniez nie jest sytuacja wyjątkowa, a przypadek walidacji danych a jednak ASP.NET w momencie proby wykonania takiego czegos rzuca wyjątek. Nie wiem jak w php bo nie korzystam z PDO.
Tak samo w niemal kazdym języku próba sparsowania tekstu na integer konczy sie rzuceniem wyjątku przez funkcje StrToInt, a czy to nie jest walidacja danych?
darko
31.10.2011, 14:52:54
Cytat(Orzeszekk @ 31.10.2011, 14:25:07 )


OK, nie rozumiem nadal

ja jako autor kodu przewiduje i zakładam ze ktos mi poda poprawną datę a jak ktos wpisze błędną to jest to sytuacja wyjątkowa

Nie. To nie jest sytuacja wyjątkowa i nie ma tutaj potrzeby ręcznego sterowania aplikacją. Zawsze można zablokować pole i wystawić jakiś cieszący oko kalendarz do wybrania daty.
Cytat(Orzeszekk @ 31.10.2011, 14:25:07 )

Chodzi o to ze np. gdy ktos wpisze stringa o dlugosci 300 w pole do 255 to moge tego stringa obciac i nie musze rzucac wyjątku , jednak z daty "reghbgfww" zadnej sensownej wartosci nie zrobie, wiec dalsze wykonanie programu jest bez sensu wiec czemu nie skorzystac z wyjątku.
jw. + zawsze możesz ustalić jakąś datę domyślną, to również nie jest sytuacja wyjątkowa.
Cytat(Orzeszekk @ 31.10.2011, 14:25:07 )

Tym bardziej ze mechanizm wyjątków pozwala na zrobienie wyjatkow o roznym stopniu "błędności" i rozroznianie ich między sobą,
i mozna uzyc jednych klas wyjątków do oznaczania błędów - sytuacji wyjątkowych, a drugich - by uproscic sobie prace z walidatorem.
Z pierwszą częścią zdania się zgodzę, z drugą już nie. Podstawowym problemem jest to, że nie rozumiesz zastosowania wyjątków. Wyjątki nie służą do "oznaczania błędów", a do nadzwyczajnego ręcznego sterowania aplikacją
w wyjątkowych, nieoczekiwanych sytuacjach.
Cytat(Orzeszekk @ 31.10.2011, 14:25:07 )

idąc twoim tokiem rozumowania co twój, źle napisany SQL string to rowniez nie jest sytuacja wyjątkowa, a przypadek walidacji danych a jednak ASP.NET w momencie proby wykonania takiego czegos rzuca wyjątek. Nie wiem jak w php bo nie korzystam z PDO. Tak samo w niemal kazdym języku próba sparsowania tekstu na integer konczy sie rzuceniem wyjątku przez funkcje StrToInt, a czy to nie jest walidacja danych?
Nie porównuj proszę C# z PHP. PDO obsługuje wyjątki. Każdy język zachowuje się nieco inaczej podczas konwersji zmiennych do określonego typu i nie ma to nic wspólnego z walidacją danych pochodzących od użytkownika. Znowu nie ma tutaj niczego nadzwyczajnego w takiej sytuacji, a rozwiązań pozornego problemu jest wiele, najprostsze z nich to konwersja zmiennej do oczekiwanego typu albo sprawdzenie typu jeszcze przed - jak to nazwałeś ładnie - sparsowaniem tekstu. Generalnie wyjątków powinno się używać wszędzie tam, gdzie faktycznie mogą pojawić się wyjątkowe sytuacje, które można obsłużyć, a następnie wznowić działanie aplikacji od instrukcji poprzedzających blok catch. W bardzo dużym uproszczeniu działa to w ten sposób, że do szczęścia nam czegoś tam brakuje, ale my, jako dobrzy programiści zostawiamy furtkę dla innych programistów korzystających z naszego kodu, zgłaszając im tylko tyle: "Hej! Tu czegoś brakuje! Coś tu nie gra." I zostawiamy im decyzję, co z tym faktem zrobią. Ogólnie ~Zyx bardzo ładnie to opisał kilka postów wyżej.
Crozin
31.10.2011, 15:27:42
@darko: Błędne dane pochodzące z żądania HTTP są tak samo wyjątkowe jak błędny format danych z pliku (np. przy odczytywaniu obrazu PNG) czy format daty przy inicjalizacji obiektu klasy data. Wyjątki służą ogólnie do obsługi błędów, a nie jakieś bliżej nieokreślonej "sytuacji wyjątkowej" bo każdy błąd taką jest, każdy musi zostać przez kogoś przewidziany (inaczej program może działać w sposób nieokreślony). Wyjątki miały na celu przede wszystkim wyeliminować takie konstrukcje:
if (cos_jest_niepoprawne()) {
blad('abc');
}
zrob_cos();
if (cos_wykonało_się_nieprawidłowo()) {
bląd('def');
}
Na rzecz:
try {
zrób_cos();
} catch (...) {
...
} [catch (...) {
} ]
// lub:
zrób_cos();
// + gdzieś "wyżej" w kodzie dopiero catch
Co miało na celu
wymuszenie obsługi błędów, czego pierwszy przykład nie robi. W PHP sprawa jest jednak nieco skopana bo obsługa wyjątków nie jest wymuszona na poziomie języka / składni, przez co drugi wariant również tej gwarancji nie daje.
Orzeszekk
31.10.2011, 15:42:51
Darko to ze wyjątki służą do sterowania aplikacją w nieoczekiwanych sytuacjach to nie wiem czy ty to sobie wymysliles, czy jakis teoretyk programowania akademicki, tak czy siak wyjątki są powszechnie stosowane do oznaczania błędów chociazby w bibliotekach standardowych roznych języków.
Dla mnie sytuacją wyjątkową jest KAŻDE odstępstwo od zamierzonego przeze mnie biegu programu.
zeby pokazac darko jak dziwne i naokoło jest twoje rozumowanie przytocze ci przykład:
skoro brak poprawnej daty w miejscu gdzie jest ona wymagana jest wg ciebie normalna sytuacją i zalecasz mi ustawic bez wiedzy uzytkownika datę domyslną, to w takim razie np. zablokowanie pliku do którego chcesz zapisać dane, również nie jest sytuacją wyjątkową i powinieneś wtedy również bez wiedzy użytkownika (bez wyświetlania komunikatu o błędzie i rzucenia wyjątku) zapisać do zdefiniowanego przez siebie domyślnego pliku.
Próba otwarcia nieistniejącego pliku również nie jest sytuacją wyjątkową, jako autor powinienes to przewidzieć i w takiej sytuacji zapełnić plik losowymi danymi. albo domyslnie zdefiniowanymi danymi dla tego pliku.
Albo jesli np tym plikiem jest plik bazy danych, zawsze mozesz za pomocą exec odpalic instancje mysql workbencha i wyswietlic ja uzytkownikowi aby zapelnil twoj plik domyslny danymi.
darko
31.10.2011, 16:03:17
~Orzeszekk
To, że nie jest to sytuacja wyjątkowa, nie oznacza, że jest to sytuacja normalna. Poniekąd sam sobie zapracowałeś na to odstępstwo pozwalając wpisywać użytkownikowi cokolwiek w pole przeznaczone na datę. Ja wolę zapobiegać niż leczyć i nie muszę komplikować kodu stosując wyjątki tam, gdzie nie jest ich miejsce. Oczywiście nie mogę i nie chcę nikomu zabronić stosowania wyjątków do sterowania programem w normalnych sytuacjach, przewidzianych przez programistę poprzez odpowiednią walidację danych (po to piszesz walidację, żeby takie sytuacje przewidzieć i dopiero to, czego nie przewidziałeś lub nie mogłeś przewidzieć - obejmujesz w klamry try {(...) throw (...)} catch(...){}). Nie stosuję wyjątków do kontrolowania danych pochodzących od użytkownika, php oferuje tyle standardowych narzędzi, że w zupełności wystarczy:
- wymuszenie określonego typu
- i długości danych
- rzutowanie zmiennej do określonego typu
- ustawienie domyślnej wartości w przypadku danej spoza zakresu
~Crozin
Oprócz tego, co napisałeś czy nie jest tak, że wyjątki stosuje się wtedy, jeśli można przywrócić normalny stan aplikacji sprzed wystąpienia problemu (tj. po obsłużeniu błędu)? Czy funkcja w php czytająca plik rzuci wyjątek czy zwróci false? Znowu wracamy do kwestii indywidualnej każdego z nas - tj. czy używać wyjątków do sterowania logiką aplikacji czy tylko w sytuacjach faktycznie wyjątkowych, gdzie zostawiamy wolne pole do obsługi napotkanego problemu? Uważam, że wyjątki powinno stosować się tylko wtedy, jeśli nie możemy określić powodu napotkanego błędu lub przewidzieć zachowania danego bloku instrukcji z zestawem danych, których nie możemy ani sprawdzić, ani zawczasu przewidzieć ich wartości.
Crozin
31.10.2011, 16:17:59
@darko: A masz jakiś pomysł jak zareagować na sytuację nieprzewidzianą? No bo jeżeli wstawisz instrukcję warunkową i wyrzucisz wyjątek to jest to jak najbardziej "normalna", przewidziana sytuacja, co nie?
Cytat
Oprócz tego, co napisałeś czy nie jest tak, że wyjątki stosuje się wtedy, jeśli można przywrócić normalny stan aplikacji sprzed wystąpienia problemu (tj. po obsłużeniu błędu)?
Rzadko kiedy taka sytuacja ma miejsce. Z reguły wystąpienie błędu kończy się wymogiem jakiejś reakcji ze strony użytkownika i ewentualnym wznowieniu, a raczej ponownym uruchomieniu, danej akcji.
Cytat
Czy funkcja w php czytająca plik rzuci wyjątek czy zwróci false? Znowu wracamy do kwestii indywidualnej każdego z nas - tj. czy używać wyjątków do sterowania logiką aplikacji czy tylko w sytuacjach faktycznie wyjątkowych, gdzie zostawiamy wolne pole do obsługi napotkanego problemu?
Powinna bezsprzecznie wyrzucić wyjątek, co więcej powinien istnieć wymóg jawnej obsługi lub oddelegowania takiego wyjątku. Zwrócenie
false jest paskudną i wyjątkowo podatną na błędy praktyką. Cały sens istnienia wyjątków to właśnie wyeliminowanie takiego zjawiska (o czym pisałem post wcześniej).
PS. Nie ma czegoś takiego jak "dane pochodzące od użytkownika traktowane w inny sposób". Dane od użytkownika to nic innego jak zewnętrzny zasób, którego format czy poprawność nigdy nie jest pewna.
darko
31.10.2011, 18:21:25
Cytat(Crozin @ 31.10.2011, 16:17:59 )

@darko: A masz jakiś pomysł jak zareagować na sytuację nieprzewidzianą? No bo jeżeli wstawisz instrukcję warunkową i wyrzucisz wyjątek to jest to jak najbardziej "normalna", przewidziana sytuacja, co nie?
Dokładnie, dlatego najczęściej obejmuję blokiem try {} catch {} kod, który nie jest mojego autorstwa i nie mogę przewidzieć, jak się zachowa, jak dostanie niepoprawne dane. Sprawdzam wtedy czy i jakie wyjątki wyrzuca i staram się obsłużyć wszelkie możliwe przypadki.
Cytat(Crozin @ 31.10.2011, 16:17:59 )

Rzadko kiedy taka sytuacja ma miejsce. Z reguły wystąpienie błędu kończy się wymogiem jakiejś reakcji ze strony użytkownika i ewentualnym wznowieniu, a raczej ponownym uruchomieniu, danej akcji.
Ok, ale jeśli nie ma możliwości wykonania żadnej akcji i z góry to wiadomo, to wyjątek nie ma racji bytu w takim miejscu. Bo niby po co? Chyba, że dalsze działanie aplikacji może wiele napsuć. To już jest wyjątkowa sytuacja

W przeciwnym razie wystarczyłby zwykły komunikat będący efektem sprawdzenia (if - else). Natomiast inaczej sprawa wygląda, jeśli możemy "olać" pewien niedobór danych (czy niespełnienie kryterium), ale nie musimy i tutaj należy zostawić pole dla programisty, który będzie korzystał z naszego kodu - dać mu możliwość zadecydowania, co w takiej sytuacji zrobić? Może dla niego, w jego użyciu naszego kodu nie będzie to niezbędne? Staram się uchwycić faktyczne sytuacje, kiedy wyjątki są niezbędne.
Cytat(Crozin @ 31.10.2011, 16:17:59 )

Powinna bezsprzecznie wyrzucić wyjątek, co więcej powinien istnieć wymóg jawnej obsługi lub oddelegowania takiego wyjątku. Zwrócenie false jest paskudną i wyjątkowo podatną na błędy praktyką. Cały sens istnienia wyjątków to właśnie wyeliminowanie takiego zjawiska (o czym pisałem post wcześniej).
A jednak różnie bywa: file zwraca false, fopen również przy czym "If the open fails, an error of level E_WARNING is generated. You may use @ to suppress this warning." (- czy to jest eleganckie rozwiązanie? Nie.), file_get_contents - j.w., SplFileInfo::openFile generuje RuntimeException - ok.
Cytat(Crozin @ 31.10.2011, 16:17:59 )

PS. Nie ma czegoś takiego jak "dane pochodzące od użytkownika traktowane w inny sposób". Dane od użytkownika to nic innego jak zewnętrzny zasób, którego format czy poprawność nigdy nie jest pewna.
A czy nie jest tak, że niezależnie od tego, co przyjdzie od użytkownika, programista spodziewa się określonych danych w pewnym formacie o danej maksymalnej długości i typie? Czy to nie jest sytuacja przewidywalna? Według mnie jest i nie jest w żaden sposób wyjątkowa. Zamiast upychać wszędzie rozmaite podhierarchie wyjątków można pewne rzeczy wymusić, albo - po przeprowadzeniu walidacji - zwrócić komunikat(y) błędu/błędów i czekać na poprawienie danych przez użytkownika. Czy walidatory wyrzucają wyjątki? Nie. Dalej nie mam przekonania czy powinniśmy stosować wyjątki dla sytuacji przewidywalnych, dla których znamy z góry wymagane kryteria (przecież często sami je narzucamy) i oczekujemy określonego rezultatu czy też lepiej używać instrukcji warunkowych i wymuszać pewien stan rzeczy?
PS. kiedyś przyszło mi pracować z kodem, gdzie w każdym niepewnym miejscu autor po prostu zatrzymywał działanie skryptu poprzez die('coś tam'). Niestety nie mieliśmy zbyt dużo czasu, żeby zapoznać się z kodem i wyszedł z tego mega zonk. Z kolei z drugiej strony - zdarzyło mi się korzystać z biblioteki do obróbki grafiki (jakaś darmowa, nazwy nie pamiętam) - tu z kolei autor dla każdej bzdury rzucał wyjątkami na prawo i lewo, np. rozmiar obrazka był za duży lub z mały - throw new Exception('Obrazek ma niepoprawny rozmiar'); - i tyle. Ani słowa na temat czy rozmiar jest za mały czy za duży? Ogólnie chodzi o to, żeby korzystać z wyjątków z głową, stosując przy tym wcześniej dobrze przemyślaną hierarchię. Nie wystarczy po prostu korzystać z wyjątków. Powód każdego rzucanego wyjątku powinien być bardzo szybko "identyfikowalny", a komunikat jasny i czytelny. Pozostawiam indywidualnym preferencjom decyzję, kiedy i w jakich sytuacjach wykorzystywać wyjątki.
Crozin
31.10.2011, 20:46:54
Cytat
Dokładnie, dlatego najczęściej obejmuję blokiem try {} catch {} kod, który nie jest mojego autorstwa i nie mogę przewidzieć, jak się zachowa, jak dostanie niepoprawne dane.
PHP co prawda nie informuje na poziomie języka o możliwych wyjątkach, ale każda przyzwoita biblioteka robi to w dokumentacji. Co więcej taki blok jest bezwartościowy, jeżeli nie masz pojęcia jakie wyjątki mogą wystąpić. Zresztą pisałem o czymś zupełnie innym, bo to o czym Ty piszesz to reakcja na sytuację w pełni przewidzianą (w końcu rzucany jest jakiś wyjątek).
Cytat
Ok, ale jeśli nie ma możliwości wykonania żadnej akcji i z góry to wiadomo, to wyjątek nie ma racji bytu w takim miejscu. Bo niby po co?
By przerwać wykonywanie kodu, który nie ma prawa zakończyć swojego działania poprawnie. Co więcej zawsze jest szansa, że gdzieś wyżej, po drodze, jednak coś się nim zajmie.
Cytat
Chyba, że dalsze działanie aplikacji może wiele napsuć. To już jest wyjątkowa sytuacja
Dalsze działanie aplikacji po wystąpieniu błędu z definicji psuje coś.
Cytat
W przeciwnym razie wystarczyłby zwykły komunikat będący efektem sprawdzenia (if - else).
Cały sens istnienia wyjątków to pozbycie się owego bloku if - else, bo jego istnienie nie jest zagwarantowane. Jego wystąpienie jest podyktowane jedynie dobrymi chęciami programisty, których często brakuje. Wyjątki natomiast wymuszają (jak już kilkukrotnie pisałem, w PHP robią to słabo) wprowadzenie fragmentu kodu jakkolwiek związanego z obsługą błędu.
Cytat
A jednak różnie bywa: file zwraca false, fopen również przy czym "If the open fails, an error of level E_WARNING is generated. You may use @ to suppress this warning." (- czy to jest eleganckie rozwiązanie? Nie.), file_get_contents - j.w., SplFileInfo::openFile generuje RuntimeException - ok.
Biblioteka standardowa PHP powstała przed wprowadzeniem wyjątków do tego języka. Generalnie... cała nadaje się do przepisania, razem ze znakomitą większością rozszerzeń. Zauważ, że połowa wątków tutaj na forum jest wynikiem błędnej obsługi, lub jej całkowitego braku, błędów generowanych przez bibliotekę standardową.
Cytat
A czy nie jest tak, że niezależnie od tego, co przyjdzie od użytkownika, programista spodziewa się określonych danych w pewnym formacie o danej maksymalnej długości i typie? Czy to nie jest sytuacja przewidywalna? Według mnie jest i nie jest w żaden sposób wyjątkowa.
Idąc tym tokiem rozumowania: czy jeżeli odczytuję plik JPEG i ma on nieprawidłowy format to jest to sytuacja wyjątkowa czy nie? czy jeżeli serwer bazy danych nie odpowiada to jest to sytuacja wyjątkowa czy nie? Obie te sytuacje są w pełni przewidywalne, co więcej zawsze sprawdza się czy aby przypadkiem do nich nie doszło.
Napiszę jeszcze raz: pojawienie się błędu czy wyjątku jest skutkiem sytuacji przewidywalnej. W przypadku sytuacji nieprzewidywalnych cholera wie co się może stać. Wyjątki zmniejszają możliwość wystąpienia takiej sytuacji.
Ad. PS: Ale to chyba oczywiste, że wyjątek powinien sobą reprezentować jakieś informacje.
Orzeszekk
31.10.2011, 21:52:32
Cytat(darko @ 31.10.2011, 16:03:17 )

~Orzeszekk
To, że nie jest to sytuacja wyjątkowa, nie oznacza, że jest to sytuacja normalna. Poniekąd sam sobie zapracowałeś na to odstępstwo pozwalając wpisywać użytkownikowi cokolwiek w pole przeznaczone na datę. Ja wolę zapobiegać niż leczyć i nie muszę komplikować kodu stosując wyjątki tam, gdzie nie jest ich miejsce. Oczywiście nie mogę i nie chcę nikomu zabronić stosowania wyjątków do sterowania programem w normalnych sytuacjach, przewidzianych przez programistę poprzez odpowiednią walidację danych (po to piszesz walidację, żeby takie sytuacje przewidzieć i dopiero to, czego nie przewidziałeś lub nie mogłeś przewidzieć - obejmujesz w klamry try {(...) throw (...)} catch(...){}). Nie stosuję wyjątków do kontrolowania danych pochodzących od użytkownika, php oferuje tyle standardowych narzędzi, że w zupełności wystarczy:
- wymuszenie określonego typu
- i długości danych
- rzutowanie zmiennej do określonego typu
- ustawienie domyślnej wartości w przypadku danej spoza zakresu.
Jak chcesz wymusic na uzytkowniku wpisanie w pole tekstowe formatu w dacie RRRR-MM-DD a nie swojego imienia lub wulgaryzmu? chyba stojąc nad nim z bejzbolem?
No chyba ze HTML5 wprowadza input type="date" ?
Bo chyba nie nazywasz wymuszeniem na uzytkowniku napisanie javascriptu do twojej strony ktory blokuje przycisk submit jeżeli uzytkownik nie poda poprawnej daty, bo jesli ktos bedzie zlosliwy to wyłączy javascript, wyśle ci perlem czy mozillą firefox spreparowany formularz. I twój skrypt juz nie bedzie mial na to odpowiedzi, poniewaz zalozyles ze wymusiles na userze poprawną datę.
Twoj argument o poprawieniu danych jest w PHP bez sensu, poniewaz, widok wyswietlajacy formularz do wypelnienia i widok wyswietlajacy komunikat o poprawnym wykonaniu akcji/błędzie to są 2 różne uruchomienia skryptu. Ten skrypt (widok) ktory odbiera dane z formularza i na ich podstawie tworzy cos na stronie: news, nowe konto, nowe <tu wstaw cos> ma prawie zawsze tyle do zrobienia: odczytac dane z formularza, zapisac je i wyswietlic komunikat o powodzeniu lub błędzie.
A jesli chodzi o obcy kod nie ma lepszego spososbu na poinformowanie o błędzie niz odpowiednio spreparowany wyjątek. Wyjątek pozwala przemycic w kodzie sensowny komunikat na co nie pozwala funkcja rzucająca błędy lub return liczba.
darko
1.11.2011, 01:19:53
<PASS> oho ~thek coś pisze
To może ja nieco dodam od siebie... Pracowałem trochę z C++, trochę z Javą, a obecnie głównie z PHP. Jako że od C zaczynałem to mam podejście mocno zbieżne z tym co pisze darko. Wyjątki tylko dla sytuacji wyjątkowych. A czym one są? Otóż zachodzą one w momencie gdy poprawnie napisana aplikacja natrafia na sytuację, która od niej zupełnie nie zależy. Przykład? Utrata połączenia z bazą danych już po jego ustanowieniu. Wyjątkiem nie jest natomiast sytuacja powszechna jak pomyłka i z dużą dozą przewidywalna. Zapewne jednak każdy dopasowuje kryterium "wyjątkowości" do siebie.
Dla mnie jeśli userowi napisałem, że pole pomieścić może 15 znaków do których należą same litery polskiego alfabetu (przykładowo imię) to wpisanie tam dłuższego lub z cyframi oznacza, że albo się pomylił, albo jest debilem

Tak czy inaczej nie jest to sytuacja wyjątkowa i mogę zwyczajnie upomnieć usera oraz poprosić o poprawne dane raz jeszcze, nie dopuszczając do dalszej części aplikacji lub celowo ignorując błędne dane (jeśli mogę, gdy są nieobowiązkowe) i informując o fakcie, iż nie wezmą one udziału w dalszej fazie obróbki danych. Jeśli natomiast dane są prawidłowe, a mimo to nie mogę dalej pracować, to jest to już sytuacja wyjątkowa. Przykład? Plik istnieje, dane są ok, użytkownik ma prawo do pliku (wgrał go na serwer i jest powiązany z plikiem), ale... fizycznie są ustawione błędne prawa dostępu (ktoś skopał chmod kopiując pliki podczas przywracania backupu). Inny przykład? Użytkownik i aplikacja mają zezwolenie na wgrywanie określonego typu plików na serwer... ale ustawienia danego hostingu ten akurat format uznają za niebezpieczny. Czyli dochodzi do sytuacji, gdy wszelkie pozwolenia są ok, plik JEST na serwerze, ale ustawienia sprawiają, że odgórnie serwer nas i aplikację zlewa, nie dopuszczając do w pełni akceptowalnego typu danych. Sam miałem z takimi do czynienia.
Najłatwiej więc to widać w sytuacji dostępu do zewnętrznego zasobu. Nie każda niemożność jest wyjątkowa. Jeśli zasobu od początku nie ma to trudno mówić by był to wyjątek. Po prostu nie ma go od samego początku i aplikacja zostanie zatrzymana już na starcie obróbki z powiadomieniem, że: "sorry batory, ale dalej się nie ruszę, nawet ciągnięta". Przykład? Obróbka pliku. Skoro oczekujemy tylko txt z określonym formatowaniem to tylko taki akceptujemy i każde odstępstwo nie jest wyjątkiem, ale błędnym typem danych i musimy zatrzymać proces obróbki do czasu poprawienia danych. Jeśli natomiast plik jest poprawny, ale w wyniku obróbki została wyczerpana pamięć dostępna to jest to coś niezależnego od samej aplikacji, mimo jej oraz danych poprawności.
Nie podzielam opinii Orzeszkka co do tego, że wszystko co jest odstępstwem od zamierzonego działania jest jednocześnie sytuacją wyjątkową. Gdyby tak było, w kodzie nie byłoby ŻADNEGO if-else, a jedynie same try-catch. No bo skoro ciąg zdarzeniowy jest liniowy to nawet celowe rozgałęzienie kodu jest sytuacją wyjątkową, czyż nie? Jednak wiele z typowych sytuacji w procesie działania aplikacji, które kończą się błędami, wynika z ograniczonej liczby przewidywalnych łatwo pomyłek lub prób wpłynięcia na wynik poprzez preparowanie danych. Przytoczono przykład z datą... Skoro wyraźnie zaznaczam, że akceptuję tylko daty z podanego zakresu o określonym formacie to wszystko inne jest błędnymi danymi, ale w pełni wychwytywalnymi. Nie jest to nic specjalnego.
Crozin... Zasugerowałeś, że try-catch powinno eliminować struktury kontrolne, gdzie ich wystąpienie jest wątpliwe i masz rację. Problemem jest jednak sytuacja, gdy programiści zaczynają wyjątki traktować jako alternatywną formę struktur kontrolnych. A takie coś sugeruje Orzeszekk. Jeśli domyślnie obsługujemy coś w jednakowy sposób, to każde odstępstwo = wyjątek. Innymi słowy dochodzimy do sytuacji, gdzie zamiast kilku if(-elseif)-else mamy dokładnie tyle samo bloków try-catch, których cel istnienia jest identyczny, ale robią to w, rzekomo, ładniejszy i łatwiejszy do ogarnięcia sposób. W ten sposób dochodzimy do takich aplikacji, gdzie cały kod to pierdylion try-catchy rzucających jeszcze więcej wyjątków do obsłużenia tak pozagnieżdżanych, że czytelność i konserwacja tegoż cierpią strasznie. A czemu? Bo programiście uwidziało się stworzyć strukturę wyjątków taką że hej i teraz musi jakoś to poodbierać, a że wyjątki dziedziczą jakoś po sobie, to tylko jeden, od którego dziedziczą inne złapie wszystkie naraz. Zaś przy bardziej szczegółowym trzeba łapać bardziej wyspecjalizowanymi (a więc odpowiedzialnymi za "gałęzie" wyjątków), czyli niejako wracamy do if-else, tylko że zbudowanego na wyjątkach. Sens tego żaden.
darko
1.11.2011, 01:50:44
Post scriptum
Cytat(Orzeszekk @ 31.10.2011, 21:52:32 )

Jak chcesz wymusic na uzytkowniku wpisanie w pole tekstowe formatu w dacie RRRR-MM-DD a nie swojego imienia lub wulgaryzmu? chyba stojąc nad nim z bejzbolem?
Blokując pole w js, walidując poprawność formatu daty.
Cytat(Orzeszekk @ 31.10.2011, 21:52:32 )

No chyba ze HTML5 wprowadza input type="date" ?
WprowadzaCytat(Orzeszekk @ 31.10.2011, 21:52:32 )

Bo chyba nie nazywasz wymuszeniem na uzytkowniku napisanie javascriptu do twojej strony ktory blokuje przycisk submit jeżeli uzytkownik nie poda poprawnej daty, bo jesli ktos bedzie zlosliwy to wyłączy javascript, wyśle ci perlem czy mozillą firefox spreparowany formularz. I twój skrypt juz nie bedzie mial na to odpowiedzi, poniewaz zalozyles ze wymusiles na userze poprawną datę.
Jestem daleki od takich czynności w stosunku do Użytkowników moich "stron", a jeśli pomyślę chwilę to na nic nie zdadzą się takie "tricky things" wymienione przez Ciebie, zapominasz, że jako typ, któremu zależy na sprawdzeniu poprawności danych, sprawdzę nawet, jakiego koloru skarpetki miał koleś, który próbował wysłać do mnie jakiekolwiek dane.
Cytat(Orzeszekk @ 31.10.2011, 21:52:32 )

Twoj argument o poprawieniu danych jest w PHP bez sensu, poniewaz, widok wyswietlajacy formularz do wypelnienia i widok wyswietlajacy komunikat o poprawnym wykonaniu akcji/błędzie to są 2 różne uruchomienia skryptu. Ten skrypt (widok) ktory odbiera dane z formularza i na ich podstawie tworzy cos na stronie: news, nowe konto, nowe <tu wstaw cos> ma prawie zawsze tyle do zrobienia: odczytac dane z formularza, zapisac je i wyswietlic komunikat o powodzeniu lub błędzie.
Czy dwa różne uruchomienia skryptu uzasadniają bezsens moich wypowiedzi? Jeżeli tak, chętnie wysłucham jakiegokolwiek argumentu. Widok nie może odebrać danych z formularza, tym bardziej nie może niczego tworzyć. Jest tylko sługą wyświetlającym w zadanej przeze mnie formie, to co chcę i w jaki sposób chcę.
Cytat(Orzeszekk @ 31.10.2011, 21:52:32 )

A jesli chodzi o obcy kod nie ma lepszego spososbu na poinformowanie o błędzie niz odpowiednio spreparowany wyjątek. Wyjątek pozwala przemycic w kodzie sensowny komunikat na co nie pozwala funkcja rzucająca błędy lub return liczba.
Dlaczego tak uważasz? A co w sytuacji, kiedy nie spodziewasz się rzucenia wyjątku lub, co gorsze jego treść jest zbyt ogólna (bardzo częsty błąd) lub niezrozumiała, a już najgorsze, co może być - myląca?
@Crozin: sytuacja z jpg i jego formatem jest trochę rozmyta. Jeśli bowiem masz na myśli jakieś proste sprawdzenie typu rozszerzenia czy mime bez faktycznego sprawdzenia zawartości pliku jakimś narzędziem mogącym zweryfikować informacje nagłówkowe pliku i stwierdzić, że mamy faktycznie do czynienia z poprawnym jpg, to fakt. można przemycić dowolny plik do obróbki i tutaj żadne ifowanie nie pomoże oraz wyjątek JEST na miejscu. Ale jeśli ktoś używa wyjątków by sprawdzić czy mu user podesłał jpg czy png to już z deczka jest to nadużywanie tego narzędzia.
I tak. Wyjątek sam w sobie zwraca nie tylko komunikat, ale informację czego dotyczy już po samej klasie jaką jest. Co innego bowiem Image_type_Exception('Not available'), a co innego Image_type_Exception('Licence restrictions'), ale już zupełnie inna bajka to Image_size_Exception('Input size too large to process'), gdzie już sam typ nas informuje z jaką kategorią wyjątku mamy do czynienia, ale komunikat może to uściślić.
@Orzeszekk: walidacja to nie jest coś co robi się "bo tak powinno się robić", a tym bardziej NIE zostawia się jej jedynie po stronie użytkownika, ale obowiązkowo robi na serwerze. Po stronie usera to jedynie "dodatek", by nie wysyłać tak często błędnych danych.
I nie masz racji do końca z widokiem formularza. W moich skryptach za wyświetlanie strony z błędami oraz samego formularza odpowiada TEN SAM widok, ale w zależności od przekazanych mu danych wyświetla je odpowiednio sformatowane. Wszystko bowiem w nim zależy od przekazanych mu struktur danych. Za każdym razem ma pełen komplet danych, ale za każdym razem one mogą być inne jednocześnie.
Poza tym co mi po komunikacie jako wyjątku? Równie dobrze mogę wysłać stringa lub tablicę stringów i sprawdzać czy jest pusta czy nie

Siła wyjątku leży już w samym fakcie, że nie samym komunikatem daje on nam informacje. Mogę bowiem jak wspomniałem wyżej mogę łapać choćby klasę wyjątku Image_Exception oraz Image_processing_Exception i już na dzień dobry wiem, że jedna jest mocno ogólna, a druga szczegółowa i nie wszystko tam trafi oraz
zależy mi na wyłapaniu ewentualnym tego, a nie innego typu wyjątku, gdyż spowodować on może wywalenie się aplikacji, zaś pozostałe są mniej "awaryjnogenne". Przy czym kompletnie nie wiem co może się stać, ale zależy mi by temu zapobiec/przeciwdziałać w jakiś sposób. A sam wyjątek rzucam właśnie wtedy gdy coś się wywalić może i nie jestem w stanie przewidzieć czemu oraz jako komunikat zapewne zrzut stosu załączę, by wyłapać co poszło i gdzie nie tak, by to zdebugować.
I znowu darko wspomniał jedną rzecz, o której PHPowcy zwyczajnie nie mają dużego pojęcia, bo za mało mają do czynienia z "owyjątkowionymi" bibliotekami... Normą jest bowiem wśród naszej braci łapanie w taki sposób
catch( Exception $message ) {...}
i gdy nagle łapiemy coś czego nie powinno być to jest mega zonk dla większości, bo "skąd i dlaczego?". A zwłaszcza gdyby sypnęła by wyjątkiem biblioteka standardowa, której to wyjątków zapewne większość by nie znała. A jest to rzecz normalna w takiej choćby Javie, gdzie wyjątki się sypią jak igły z choinki na trzech króli, przy byle pierdółce, na pół ekranu
batman
1.11.2011, 02:43:37
Pozwolę sobie wtrącić się to tej jakże niezwykle interesującej dyskusji na temat walidacji formularzy. Przyjmując założenie, iż aplikacje PHP realizowane są w modelu trójwarstwowym (powszechnie nazywanym MVC), walidacja danych powinna odbywać się na poziomie modelu. W takim przypadku, model musi rzucić wyjątek, by poinformować źródło danych o niepoprawnych danych wejściowych. Z perspektywy modelu, odebranie danej typu bool, gdy oczekiwana była data, jest sytuacją wyjątkową i dlatego pojawia się wyjątek. To, że dla programisty nie jest to "wyjątkowe", nie oznacza, że takie nie jest w kontekście modelu/klasy/aplikacji/itp.
Crozin
1.11.2011, 02:59:56
Cytat
Przykład? Plik istnieje, dane są ok, użytkownik ma prawo do pliku (wgrał go na serwer i jest powiązany z plikiem), ale... fizycznie są ustawione błędne prawa dostępu (ktoś skopał chmod kopiując pliki podczas przywracania backupu). Inny przykład? Użytkownik i aplikacja mają zezwolenie na wgrywanie określonego typu plików na serwer... ale ustawienia danego hostingu ten akurat format uznają za niebezpieczny. Czyli dochodzi do sytuacji, gdy wszelkie pozwolenia są ok, plik JEST na serwerze, ale ustawienia sprawiają, że odgórnie serwer nas i aplikację zlewa, nie dopuszczając do w pełni akceptowalnego typu danych
Dobra tylko co biblioteka do IO ma do omawianego tutaj przypadku? Bo to ona będzie odpowiedzialna za powstanie wyjątku. Przecież to nie ma kompletnie żadnego związku z odbieraniem danych od użytkownika, jako zew. zasobu.
Cytat
Najłatwiej więc to widać w sytuacji dostępu do zewnętrznego zasobu. Nie każda niemożność jest wyjątkowa. Jeśli zasobu od początku nie ma to trudno mówić by był to wyjątek. Po prostu nie ma go od samego początku i aplikacja zostanie zatrzymana już na starcie obróbki z powiadomieniem, że: "sorry batory, ale dalej się nie ruszę, nawet ciągnięta".
No czyli już na start... wyrzuci wyjątek, racja? Ja widzę jedynie dwa rozwiązania:
$abc = new Zasób($def);
if ($abc->czyWystąpiłBład()) {
bląd();
}
// lub
try {
$abc = new Zasób($def);
} catch (...)
błąd();
}
Ogromną podatność na błędy tego pierwszego już omówiłem.
Cytat
Przykład? Obróbka pliku. Skoro oczekujemy tylko txt z określonym formatowaniem to tylko taki akceptujemy i każde odstępstwo nie jest wyjątkiem, ale błędnym typem danych i musimy zatrzymać proces obróbki do czasu poprawienia danych.
No i sytuacja dokładnie taka jak wcześniej. Albo normalnie rzucamy wyjątkiem, albo jesteśmy zdani na łaskę programisty, który być może obsłuży błąd.
Cytat
Nie podzielam opinii Orzeszkka co do tego, że wszystko co jest odstępstwem od zamierzonego działania jest jednocześnie sytuacją wyjątkową. Gdyby tak było, w kodzie nie byłoby ŻADNEGO if-else, a jedynie same try-catch.
Bzdura. Wyjątki są od obsługi błędów, nie sterowaniem przepływem aplikacji. Już pomijając w ogóle fakt, że niemal każda instrukcja
throw jest połączona z if-em.
Cytat
Crozin... Zasugerowałeś, że try-catch powinno eliminować struktury kontrolne [...]
Jak już napisałem, bzdura. Nigdzie nie napisałem, że try-catch ma zastępować struktury kontrolne jako takie.
Cytat
@Crozin: sytuacja z jpg i jego formatem jest trochę rozmyta. Jeśli bowiem masz na myśli jakieś proste sprawdzenie typu rozszerzenia czy mime bez faktycznego sprawdzenia zawartości pliku jakimś narzędziem mogącym zweryfikować informacje nagłówkowe pliku i stwierdzić, że mamy faktycznie do czynienia z poprawnym jpg, to fakt. można przemycić dowolny plik do obróbki i tutaj żadne ifowanie nie pomoże oraz wyjątek JEST na miejscu. Ale jeśli ktoś używa wyjątków by sprawdzić czy mu user podesłał jpg czy png to już z deczka jest to nadużywanie tego narzędzia.
A czym konkretnie różni się błąd typu "powinieneś przesłać obraz (png, jpeg, gif)" od "przesłany plik jpeg jest uszkodzony"? Jakie jest kryterium dopuszczalności?
----------------------
Na koniec może jeszcze podsumuję:
1. Wyjątki służą do obsługi błędów.
2. Wyjątki wyrzca się gdy dany kod nie może zakończyć pracy pomyślnie. Tak więc mając jakąś metodę typu isValid() i wywalimy wyjątku gdy coś jest niepoprawne.
3. Wyjątki i tzw. struktury kontrolne mogą ze sobą bez problemu współgrać.
Cytat
A zwłaszcza gdyby sypnęła by wyjątkiem biblioteka standardowa, której to wyjątków zapewne większość by nie znała. A jest to rzecz normalna w takiej choćby Javie, gdzie wyjątki się sypią jak igły z choinki na trzech króli, przy byle pierdółce, na pół ekranu
Między innymi dlatego kod przeciętnego "początkującego" Java'owca jest dwie, czy trzy klasy ponad ekwiwalent PHP-owca. Można sobie zweryfikować przeglądając chociażby StackOverflowa.

EDIT:
Cytat
[...] Przyjmując założenie, iż aplikacje PHP realizowane są w modelu trójwarstwowym (powszechnie nazywanym MVC) [...]
MVC to szczególny przypadek architektury trójwarstwowej, czy ogólnie, wielowarstwowej.
Tak, wiem - czepiam się.
Czym dla mnie się różnią? Wyjątek i błąd to dla mnie nieco inne pojęcia. Wyjątek jest właściwie "podzbiorem" błędów, które nie są przez programistę przewidziane lub przewidywalne. W tej sytuacji więc, gdy mamy kontrolę danych dostarczonych przez usera wyjątki powinny być łapane dla całego obiektu gdyby coś jednak nie wyszło, ale błędy przewidywalne tylko komunikowane i odsługiwane przez programistę bez stosowania tego mechanizmu. Nie zaś, że rzucamy sobie wyjątek gdy user wprowadza nie pasujące do wzorca dane. To już jest bowiem kontrola przepływu danych i tutaj if-else w zupełności wystarcza.
Co do przykładu z zasobem to kwestia jest związana z sytuacją w jakiej to następuje. Jeśli aplikacja bazuje na połączeniu z zasobem i tym samym jest on integralną częścią, to jest to błąd i aplikacja powinna poinformować o tym fakcie gdy próbuje nawiązać połączenie i nie potrafi. Jeśli jednak aplikacja wie, że taki zasób jest i połączenie z nim ma, a w pewnym momencie nagle je traci to jest to już sytuacja wyjątkowa. W pierwszym bowiem wypadku już od samego początku wiemy, że zasób jest niedostępny i nie możemy z nim pracować. W drugim zasób jest i nagle znika. Pierwsze jest normą, gdyż możesz przewidzieć dokładnie wystąpienie błędu i jego miejsce. Tego nie można nazwać wyjątkiem. Ale jak przewidzisz wystąpienie drugiej sytuacji, która może mieć miejsce dokładnie w dowolnym momencie począwszy od momentu nawiązania połączenia do czasu jego zakończenia? Nie da się wprost powiedzieć: "To nastąpi w 5 sekund od nawiązania połączenia.", ale w wyniku debugu możemy określić przyczyny lub okoliczności wystąpienia, a tym samym możemy wyeliminować jej zajście i sprawić, że przestaje być wyjątkowa
Stwierdzasz, że albo rzucamy wyjątek albo zdajemy się na programistę... Czyli jako programista mogę mogę nie przejmować się błędem i jego obsługą tylko rzucam wyjątek i niech martwi się o to ten, który ów kod dołącza do aplikacji? Popatrz może dokładniej na kody Javowców i innych programistów. Tam jest wiele struktur kontrolnych, które powstają w momencie wykrycia nieprawidłowości poprzez wyjątek, a same wyjątki służą tylko wyłapywaniu nieprzewidzianych sytuacji, a nie by sterować.
To z czym się nie zgadzam w tym co napisałeś to fakt czego nie napisałeś. Dla mnie pełniejsza wersja to: "Wyjątki są od obsługi błędów, których miejsca i czasu wystąpienia nie potrafimy określić w chwili tworzenia aplikacji".
Przykład z różnicą między błędami jest prosty i zależy od... złożoności aplikacji. Czemu? Jeśli nie mamy w kodzie możliwości sprawdzenia poprawności danych to sprawdzenie czy plik jest uszkodzony jest dla nas niewychwytywalne. W takim wypadku gdy podczas pracy natrafimy na uszkodzony fragment zachodzi sytuacja wyjątkowa. Jeśli jednak kod sprawdzić potrafi możliwość wystąpienia uszkodzenia, to olanie tego przez programistę jest jego błędem i powinno to być wychwycone na etapie testowania oraz poprawione.
Dlatego Twoje 3 punkty (właściwie to 2 pierwsze, bo trzeci jest jak najbardziej prawidłowy) nieco skoryguję:
1. Wyjątki służą do obsługi błędów, które nie są przez programistę przewidziane lub przewidywalne. Poznając okoliczności zaistnienia, wyjątek staje się błędem zwykłym i zdolnym do wyeliminowania w 99% wypadków. Pozostały 1% jest zależny od środowiska uruchomieniowego i wpływu procesów zewnętrznych na samą aplikację lub powiązane z nią zasoby. Tym samym jest nieprzewidywalny z samej swojej natury i w zasadzie nigdy nie można go wyeliminować.
2. Wyjątki wyrzuca się gdy dany kod nie może zakończyć pracy pomyślnie ze względu na czynniki, które są poza zasięgiem i przewidywaniami specyfikacji. Tak więc mając jakąś metodę typu isValid(), którą jesteśmy w stanie wykryć istnienie błędu, wyjątki są techniką zbędną. Wywalimy wyjątek gdy coś jest niepoprawne, choć z przebiegu całości procesu nie da się wywnioskować chwili jego zaistnienia i powinno się dostać prawidłowe wyniki, co jednak nie zachodzi lub dochodzimy do sytuacji nietypowej dla aplikacji.
3. Wyjątki i tzw. struktury kontrolne mogą ze sobą bez problemu współgrać.
Orzeszekk
1.11.2011, 14:26:25
Crozin jako chyba jedyna osoba z dyskutujących zachował tutaj zdrowy rozsądek i nie odpłynął w akademicką mniemanologię, i podpisuje się pod jego postem 2ma rękami i nogami, i nie mam nic więcej do dodania.
thek, mylisz po prostu pojęcie błędu i wyjątku. Wyjątek jest po prostu wygodną, dostosowaną do paradygmatów obiektowych reprezentacją informacji o błędzie. Ten jak to ty mowisz, błąd to po prostu reprezentacja błędu występująca w językach strukturalnych jak np C czy turbo pascal.
W nowszych językach programowania, pełni obiektowych jak np Java czy C#, nie ma kompletnie czegos takiego jak błąd, są tylko wyjątki.
Najwyrazniej masz thek naleciałosci PHP-owe, rozwarstwienie na błędy i wyjątki w PHP bierze się stąd że PHP 5 jest wstecznie kompatybilny ze starymi wersjami, a stare wersje jak np PHP 3 opierały się na C, gdzie nie ma wyjątków są tylko blędy. Osobiście polecam dopisać sobie errorHandler zamieniający każdy rzucony błąd na ErrorException i php przestaje być smiesznie rozwarstwiony w tej kwestii.
Wartosc semantyczna "blędu" i "wyjątku" jest taka sama. To po prostu informacja o tym ze cos idzie nie tak podana w roznym opakowaniu.
Uwaga batmana o tym ze dane sa walidowane zazwyczaj po stronie modelu rowniez jest słuszna, w moich aplikacjach się to równiez odbywa w ten sposob, wyjątek jest w tej sytuacji najwygodniejszym sposobem na przekazanie informacji o błędzie do innej warstwy.
A co do przykładu z dwoma formami zgłaszania błędów, to są one lekko mówiąc nieporównywalne. Czemu? Ponieważ bazują na dwóch różnych formach dających ten sam efekt. Tyle że w pierwszym wypadku błąd wykrywamy poprzez flagi obiektu samego, a w drugim bazujemy na tym, że inicjalizacja obiektu już na dzień dobry rzuca wyjątki w przypadku błędu. Innymi słowy pierwszy wariant zakłada, że tworzenie obiektu zasobu przebiega bez obsługi wyjątków, czyli tak jak jest choćby w php, gdzie brak powodzenia operacji jest sygnalizowany nullem czy false, gdyż biblioteka standardowa nie jest do wyjątków przystosowana. Drugi wariant ma miejsce choćby w innych językach, które od początku obsługę wyjątków mają bazowo zaimplementowane a sama klasa exception jest jakąś pochodną klasy object.
Orzeszekk
1.11.2011, 14:42:15
Są porównywalne, mozesz kompletnie zastąpić wyjątek błędem, możesz w ogole nie uzywac wyjątku tylko uzyc wartosci zwracanej przez metodę, wszystko zalezy od tego jak to zakodujesz, tak jak instrukcje IF mozna zrealizowac za pomocą skoków GOTO, tak samo rzucenie i obsluge wyjatku mozna zaimplementowac za pomocą odpowiednio skonstruowanych if-else oraz return (roznica jest tylko w wygodzie, na korzysc wyjątkow) wiec nie wiem jaka mialaby byc semantyczna roznica.
Po zrobieniu errorHandlera ktory rzuca wyjątek ErrorException o komunikacie takim jak komunikat bledu, z twojej strony wyglada to tak ze np. funkcja fread rzuca wyjatek gdy odczytuje pusty plik, ty ja obejmujesz w bloki try- catch i wszystko dziala tak jak w normalnym pelni obiektowym jezyku programowania.
A wcale to nie dziala tak jak mowisz ze sobie sprawdzasz flagi i reagujesz lub nie, bo w momencie rzucenia fatal error wykonanie programu sie zatrzymuje.
Crozin
1.11.2011, 16:17:28
@thek: Taka osobista uwaga. Staraj się jednak pisać zwięźlej, bo w chwili obecnej czytanie i ustosunkowywanie się do Twoich postów jest dosyć męczące.
Nie, wyjątki nie służą do obsługi jakiś bardzo rzadkich sytuacji. Wyjątki służą do obsługi wszystkich błędów. Służą do obsługi wszystkich błędów, ponieważ wymuszają (po raz n-ty muszę zwrócić uwagę na to, że w PHP spieprzyli sprawę nie wprowadzając tego wymuszenia na poziomie języka) obsługę wszelkich możliwych błędów lub w ostateczności wywalą cały program, który na skutek nieobsłużonego błędu może zachować się w sposób niewiadomy.
I to jest podstawowy powód dla którego wyjątki używa się do obsługi wszystkich błędów. Bo jak mówisz, że sprawdzenie czy zasób istnieje przed jego otwarciem to "zwykła sytuacja do wychwycenia":
if (!resource_exists(...)) {
error(...);
}
open_resource(...)
To powiedz mi, co w przypadku gdy jakiś niedbały programista zapomni o tym początkowym IF-ie? Albo zachowanie całej aplikacji będzie kompletnie nieprzewidywalne, albo w open_resource() bezsensownie zdublujesz taki warunek w celu wyrzucenia błędu.
Wariant z wyjątkiem:
try {
open_resource(...);
} catch (...) {
}
Co się stanie jak jakiś niedbały programista zapomnij o bloku try - catch (w takim PHP jest to niestety możliwe)? Wywali całą aplikację, posypią się jakieś błędy do konsoli, ale cholera aplikacja przerwie swoje działanie, dzięki czemu nie dojdzie do jakiś nieprzewidzianych zachowań.
A żeby jeszcze dobitniej pokazać dlaczego pierwsze podejście jest złe:
$url = '....';
if (!is_valid_url($url)) {
error();
}
if (!host_can_be_resolved($url)) {
error();
}
$res = open_resource($url);
if ($res == -1) {
error('timeout');
}
while (($c = read_resource($res)) != -1) {
doSth($c);
}
close_resource($res);
}
// vs:
try {
$url = '...';
$res = open_resource($url);
while (($c = read_resource($res)) != -1) {
doSth($c);
}
close_resource($res); // w PHP nie ma bloków finally, więc jedynie coś takiego
} catch (InvalidUrlException $iue) {
} catch (IOException $ioe) {
}
// bloków catch mogłoby być pewnie między 1 a 5, w zależności od potrzeb
W drugim:
- przejrzystość kodu
- znacznie mniejsza podatność na błędy (mimo sporych ułomności ze strony języka)
@Orzeszek: Nie widzę problemu by wyjątki były wewnętrznym sposobem na implementację obsługi błędów. Zauważ bowiem, że jak napisałem, wyjątek jest podzbiorem błędów, których wystąpienie jest problematyczne lub niemożliwe do wychwycenia. Możemy się jednak nimi posłużyć by sytuacja stała się przewidywalna.
Wyjątek jest pewną reprezentacją błędu z racji tego, iż jest jego podzbiorem. Czy więc jest różnica w tym, że zwrócę obiekt klasy Object z komunikatem czy obiekt klasy Exception dziedziczący po Object z dokładnie tym samym komunikatem? To już nieistotna forma reprezentacji. A tak właśnie wygląda to w językach, które nazywasz obiektowymi. Inne opakowanie na dokładnie to samo. I dokładnie to samo stwierdzasz dalej pisząc, że " To po prostu informacja o tym ze cos idzie nie tak podana w roznym opakowaniu." i tym samym zwrócenie null, false, komunikatu, czy obiektu określonej klasy to tylko nieistotne opakowanie. Ja bowiem piszę nie o tym czy obiekt zwracany jest nullem, intem czy obiektem klasy ale logiką tego co jest błędem, a co sytuacją wyjątkową i do czego mechanizm wyjątków powinien być stosowany tak naprawdę. By podać jakiś przykład bardziej "ludzki" z walidacją... Skoro mogę wykryć błąd poprawności danych poprzez choćby użycie wyrażenia regularnego, to mogę to zrobić w dowolny sposób, niekoniecznie od razu sięgając do wyjątków, by zasygnalizować to aplikacji. Jest to owszem forma wygodna, ale zaczyna się niebezpiecznie zbliżać do kontroli przepływu, a nie po to ten mechanizm wymyślono. Tutaj w zupełności wystarczy zwykły IF. Co gorsze, wyjątki w momencie zaistnienia wyskakują z normalnego przebiegu by znaleźć najbliższy pasujący blok catch. Myślisz, że pisanie Java to od razu "ach i och"? Mało to ja widziałem kodów gdzie było
try{
// różne operacje;
} catch ( Exception zmienna ) {
//kompletnie nic
}
//dalsze operacje;
a całość byle tylko wyjątek złapać i ukryć dla postronnych. Brzydki hack, ale wbrew pozorom często stosowany, nie tylko wśród początkujących. Czym to się różni od @ w PHP? Niczym. Jedyna różnica to fakt, że w PHP nie ma ujednolicenia co jest błędem, a co wyjątkiem. Zaś w takiej Javie każdy błąd = wyjątek. Co moim zdaniem jest zbyt dużym uogólnieniem, byle tylko ułatwić pewne rzeczy w czasie programowania. Tyle że kosztem tego jest to, iż nieraz by coś było można normalnie obsłużyć, trzeba wykonać choćby kilka rzutowań po drodze.
Co do pisania handlerów to akurat swój kod pisać potrafię na tyle, że nie potrzebuję małpek czy error handlerów zamieniających error na exception, to raz. A dwa, że error handler którego jedynym celem jest zamiana komunikatu na obiekt klasy Exception to dla mnie bezsens. Nic mi on nadal bowiem mówić nie będzie poza samym komunikatem. Nie po to są wyjątki i błędy by sobie jedne drugimi zastępować, skoro mają ciutkę inny zakres kompetencji.
Poza tym trudno powiedzieć o naleciałościach PHP-owych, skoro poznałem go kilka lat po tym, gdy już pisałem w C++ czy Javie, a na forum narzekam na PHP i jego idiotyzm czy braki w porównaniu do innych języków, głównie C++
Crozin
1.11.2011, 17:15:41
catch (SomeException se) {
}
Jest różnica między świadomym zignorowaniem wystąpienia błędu, a brakiem jakiejkolwiek obsługi błędu.
Nie wiem ile jeszcze razy będę musiał powtarzać. Wyjątki to
wymuszenie obsługi błędu w przeciwieństwie do zwracania false itp. Taki był cel ich powstania - cała reszta to tylko dodatki. I wyjątki są pełnoprawną strukturą kontroli przepływu, bo nie da się obsługiwać błędów (niezależnie jak są one zrealizowane) bez zmiany przepływu aplikacji.
Nie wiem też @thek coś się tak uparł na jakieś "spostrzeżenie" jakbym sugerował, że wyjątki mają być zamiennikiem dla bloków if - else. Przecież to bzdura.
batman
1.11.2011, 17:44:03
Cytat(thek @ 1.11.2011, 16:22:40 )

Mało to ja widziałem kodów gdzie było
try{
// różne operacje;
} catch ( Exception zmienna ) {
//kompletnie nic
}
//dalsze operacje;
a całość byle tylko wyjątek złapać i ukryć dla postronnych. Brzydki hack, ale wbrew pozorom często stosowany, nie tylko wśród początkujących. Czym to się różni od @ w PHP? Niczym.
I tu się mylisz. Sam to stosuję jako metodę na uniknięcie kilku(nastu/dziesięciu) if-ów coś tam sprawdzających. Weźmy na przykład odpowiedź jakiegoś serwera zwracana w postaci XML. Odpowiedzi może być kilkanaście i każda z nich zawiera specyficzne węzły. Musiałbym napisać kilkanaście razy obsługę odpowiedzi, gdzie dzięki wyjątkom mam tylko jedną. Po prostu parsuję kod XML zakładając, że oczekiwany przeze mnie węzeł w nim się znajduje. Jeśli go nie ma (sytuacja wyjątkowa - w końcu spodziewałem się tego węzła), klasa parsująca rzuca mi wyjątek, że próbuję operować na nieistniejącym węźle. Ja ten wyjątek przechwytuję i ignoruję.
@Crozin: to o czym piszesz to ułomność języka, który pozwala na pisanie bez jakiejkolwiek kontroli nad czymkolwiek, zrzucając wszystko na interpreter. Zwróćmy uwagę, że taka Java jest także językiem interpretowanym (przez JVM), ale jest prekompilowana do wersji przez JVM zrozumiałej. I wyjątki jako takie są w dużej mierze na etapie prekompilacji wyłapywane. Co nie zmienia faktu, że można kod napisać także w niej "po PHP-owemu", gdzie będzie cacy jeśli zrobimy jak chciał programista, ale jeden "byk" i wywali nam całą aplikację. Nie kłócę się też ze stwierdzeniem, że wyjątki to wymuszenie obsługi. To co po raz n-ty powtarzam to stosowanie tego mechanizmu jako remedium na wszystko co nieraz przeradza się w kuriozum. A co do "spostrzeżenia" to nie sugeruję, iż Ty uważasz za zamiennik to, ale że część programistów tak ten mechanizm stosuje i jest to moim zdaniem złe. Co do zmiany przepływu to wiesz dobrze jak działają wyjątki. One nie powodują zmiany przepływu, ale "wyskoczenie" z normalnego przepływu do najbliższego pasującego bloku catch. Nigdy jednak nie wiesz czy będzie to po 1, 5 czy 15 instrukcji wewnątrz bloku. Gdyby to do czegoś porównać, to chyba najprędzej do użycia goto, które także powoduje przejście do określonego miejsca w kodzie (etykiety), a które byłoby równoważne z blokiem catch.
@oboje: no właśnie... Świadomie ignorujemy. Obejmujemy blokiem try wszystkie operacje, gdyż wiemy jakiego typu wyjątek dostaniemy i tym samym usuwa się go z widoku. Jednocześnie jeśli w owym (owych) XML dostaniemy wyjątek tej samej klasy, ale tyczący czegoś innego, nawet się o tym nie dowiemy. W efekcie takie podejście ma sens identyczny ze stosowaniem @ przy operacjach w PHP. Można nawet nie wiedzieć, że coś działa nieprawidłowo, gdyż zamiast obsłużyć błąd, ignorujemy go dla naszej wygody lub "kompaktowości" kodu. Ja wiem, że to jest fajne i przyjemne rozwiązanie, ale podobnie jak @ powoduje problemy z debugiem aplikacji. W wersji batmana z owymi xml-ami tracę bowiem znacznie bardziej kontrolę nad tym co otrzymuję z serwerów, niż gdybym miał zrobić te ileś if-ów. Więcej pracy dla mnie, ale teżi kontrola nad całością większa i nie wyleję dziecka z kąpielą.
Poza tym zwróćmy uwagę na jeden fakt... Zazwyczaj nie mamy jednej klasy wyjątku, ale całą ich hierarchię. Kod Crozina jest mocno uproszczony, gdyż przecież nie walimy kodu całej aplikacji w try i na końcu tylko bloczki catch uzupełniamy. Zazwyczaj bloki try-catch obejmują jedynie te fragmenty, które podejrzewamy o możliwe zaistnienie problemu określonego typu lub typów.
batman
2.11.2011, 08:10:50
Cytat
Jednocześnie jeśli w owym (owych) XML dostaniemy wyjątek tej samej klasy, ale tyczący czegoś innego, nawet się o tym nie dowiemy.
Patrzysz na to przez pryzmat PHP, w którym do wszystkiego używa się jednej klasy Exception. W moim przykładzie ignoruje się tylko wyjątek typu NieMaTakiegoWezlaException. Sam napisałeś, że jest hierarchia wyjątków i jeśli będziemy z niej korzystać, to takie praktyki są o wiele lepsze niż ręczne klepanie warunków sprawdzających. Co więcej, jeśli zmieni się struktura XML, musisz przepisać warunki, ponieważ nie będą one obejmować wprowadzonych zmian.
Właśnie dlatego napisałem, nie "wyjatek", ale "wyjątek tej samej klasy", co wskazuje, że nie myślę tutaj o ograniczeniu do jednej jedynie klasy. To czego w Twoim przykładzie się obawiam to fakt, iż coś jeszcze może być nie tak z węzłem i złapie sie pod ów specyficzny wyjątek, o czym się nie dowiesz, gdyż wyciszasz to. Ja przykładowo znam strukturę i wolę wyłuskać dane mnie interesujące za pomocą Xpath oraz obsłużyć ręcznie niż palnąć wyciszenie wyjątku gdyby nie znalazło interesującej mnie informacji. Bowiem w ten sposób mogę nawet nie dowiedzieć się, że zaszła jakaś drobna zmiana w strukturze xml. Wiem, że jest to może podejście masochistyczne lekko, ale wyjątki stosuję raczej tylko tam gdzie wiem, że coś może się wywalić, ale nie mam na to bezpośredniego wpływu i kontroli kiedy oraz z jakiego powodu. Gdy w końcu błąd zreprodukuję, zawężam lub reorganizuję tak, by nie używać tego mechanizmu jako remedium. Wiem, że jest przydatny, ale staram ograniczać jego użycie do minimum. Uważam, że jak we wszystkim, należy stosować z głową daną technikę/rozwiązanie, bo potem mamy sytuację jak z magią w php, która wciskana jest wszędzie, niekoniecznie tam gdzie jest konieczna czy przydatna, choć ułatwia wiele rzeczy niewątpliwie.
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.