Piąta odsłona PHP została zaprezentowana światu w roku 2004. Zmiany wprowadzone do języka były wręcz rewolucyjne. Programowanie obiektowe w PHP przestało budzić uśmiech politowania, a szereg usprawnień i nowych funkcjonalności robił ogromne wrażenie. Mimo iż od premiery “obiektowego PHP” minęło ponad sześć lat, nadal niektóre – nawet te podstawowe – funkcjonalności pozostają niezrozumiałe i albo kurzą się w zaciszu manuala albo są wykorzystywane w sposób wołający o pomstę do nieba. Taki właśnie los spotkał wyjątki.
Zanim zaczniemy poznawać wyjątki dostępne w ramach SPL, warto wiedzieć po co w ogóle one powstały. Ich powstaniu przyświecał jeden cel – możliwość sterowania przepływem aplikacji w obliczu błędu. A po naszemu – nawet jeśli coś nie zadziała, aplikacja nie wyłoży się koncertowo, tylko będzie próbowała działać w ograniczonym zakresie.
Poza standardową klasą Exception, będącą nadrzędną klasą dla wyjątków, w PHP (a dokładniej w SPL) mamy dostępnych kolejnych trzynaście klas wyjątków. Każda z nich powstała w innym celu.
BadFunctionCallException
Wyjątek BadFunctionCallException powstał w celu zasygnalizowania niepopranego wywołania funkcji. Co należy przez to rozumieć? Najprościej będzie to wytłumaczyć na przykładzie.
try {
callMe();
} catch(BadFunctionCallException $e) {
echo $e;
}
function callMe()
{
$args = func_num_args();
if($args < 2) {
throw new BadFunctionCallException('Za mało argumentów');
}
}
BadFunctionCallException można również rzucać w przypadku braku niepoprawnej nazwy funkcji do wywołania.
BadMethodCallException
Obiektowy odpowiednik poprzedniej klasy.
try {
$foo = new Foo();
$foo->niesitniejacaMetoda();
} catch(BadMethodCallException $e) {
echo $e;
}
class Foo
{
public function __call($method, $args)
{
switch($method) {
case 'foo':
/* do magic */
break;
default:
throw new BadMethodCallException('Nie ma takiej metody');
}
}
}
DomainException
Najmniej zrozumiały i najmniej potrzebny (póki co) wyjątek dostępny w PHP. Wyjątek DomainException powinien zostać zgłoszony w momencie próby skorzystania z danych nienależących do bieżącej domeny. Jak na razie na temat tego wyjątku toczą się akademickie dyskusje, z których można dowiedzieć się, że np. obiekt Foo nie znajduje się w domenie dni tygodnia. W przypadku PHP nie spotkałem się jeszcze z praktycznym zastosowaniem tej klasy.
InvalidArgumentException
Wyjątek zgłaszany w momencie otrzymania niespodziewanego/niepoprawnego argumentu.
try {
$foo = new Foo();
$foo->bar('abc');
} catch(InvalidArgumentException $e) {
echo $e;
}
class Foo
{
public function bar($arg)
{
if(!is_numeric($arg)) {
throw new InvalidArgumentException('Niepoprawny argument');
}
}
}
LengthException
Ten typ wyjątku zgłaszany jest w przypadku odebrania danych o niepoprawnej długości. Niepoprawna długość danych oznacza tutaj nieprawidłowy rozmiar odebranego pliku, błędną ilość danych przesłanych ze strumienia, czy też nieoczekiwaną wielkość tablicy.
try {
$a = array(123, 234, 345);
// z jakiegos powodu tablica musi zawierać dwa elementy
if(count($a) != 2) {
throw new LengthException('Niepoprawna wielkość tablicy');
}
} catch(LengthException $e) {
echo $e;
}
LogicException
Kolejny klasa wyjątku, z której nie będziemy zbyt często korzystać. Zgłaszany jest w momencie, gdy wyrażenie logiczne oznacza fałsz.
try {
$expression = false;
if(!$expression) {
throw new LogicException('Nieprawda');
}
} catch(LogicException $e) {
echo $e;
}
OutOfBoundsException
Zgłoszenie niepoprawnego klucza, np. tablicy lub innej kolekcji.
try {
$a = array('a' => 1, 'b' => 2, 'c' => 3);
if(!array_key_exists('qwe', $a)) {
throw new OutOfBoundsException('Brak klucza');
}
} catch(OutOfBoundsException $e) {
echo $e;
}
OutOfRangeException
Jeden z najczęstszych błędów w aplikacjach – zadana wartość wykracza poza zdefiniowany zasięg.
try {
$startYear = 1950;
$endYear = 1970;
$input = 2000;
if($input < $startYear|| $input > $endYear) {
throw new OutOfRangeException('Poza zasięgiem');
}
} catch(OutOfRangeException $e) {
echo $e;
}
OverflowException
Wyjątek zgłaszany w momencie próby dodania elementu do zapełnionego pojemnika.
try {
$a = array();
addToArray($a, 123);
addToArray($a, 234);
addToArray($a, 345);
addToArray($a, 456); // spowoduje rzucenie wyjątku
} catch(OverflowException $e) {
echo $e;
}
function addToArray(&$a, $value)
{
$arrayMaxLength = 3;
if(count($a) + 1 > $arrayMaxLength) {
throw new OverflowException('Tablica się wylała');
}
$a[] = $value;
}
RangeException
Kolejny rzadko spotykany wyjątek, zgłaszany w przypadku zastosowania niepoprawnego zasięgu. Jest podobny do klasy OutOfRangeException, z tą różnicą, że dziedziczy nie po LogicException, a po RuntimeException.
RuntimeException
Wyjątek czasu wykonywania. Zgłoszenie tego typu wyjątku oznacza, że aplikacja wybrała się pod budynek Sejmu, podpaliła opony i zrobiła rozróbę. Innymi słowy aplikacja nie działa i na pewno nie posprząta po sobie. RuntimeException zgłaszany jest za każdym razem, gdy wystąpi zdarzenie uniemożliwiające poprawne działanie aplikacji (brak dostępu do źródła danych, brak zasobów do przetworzenia żądania, itp).
UnderflowException
UnderflowException jest odwrotnością OverflowException i oznacza, że próbowaliśmy pobrać element z kolekcji, która jest pusta.
try {
$a = array(123, 234, 345);
echo readFromArray($a);
echo readFromArray($a);
echo readFromArray($a);
echo readFromArray($a); // zglosi wyjątek
} catch(UnderflowException $e) {
echo $e;
}
function readFromArray(&$a)
{
if(count($a) == 0) {
throw new UnderflowException('Z pustego i Salomon nie naleje');
}
return array_shift($a);
}
UnexpectedValueException
Działa na takiej samej zasadzie jak InvalidArgumentException, z tą różnicą, że jest zgłaszany nie w przypadku niepoprawnych argumentów funkcji, a w każdej innej sytuacji, gdy spodziewaliśmy się innej wartości. Może to być np. nieoczekiwana wartość w parsowanym pliku Excel lub spreparowane ciasteczko.
Podsumowanie
Sterowanie przepływem aplikacji przy użyciu wyjątków wbrew pozorom do najprostszych nie należy. Bardzo często spotykałem na swojej drodze kwiatki w postaci walidacji formularzy lub innych mniej lub bardziej zabawnych zastosowań wyjątków. Dlatego też zanim rzucony zostanie wyjątek warto upewnić się, czy w tym konkretnym przypadku nie będzie lepiej zwrócić false, null lub wartości domyślnej.
Gdybyś tylko trochę lepiej opisał ten DomainException, bo „ni w ząb” nie znajduję dla niego żadnego zastosowania. ;]
Ja myślę, że DomainException ma bardzo proste zastosowanie. Załóżmy, że mamy powiedzmy encję Użytkownik z właściwościami firstName i lastName. Chcemy skonstruować obiekt tej encji, aby została zachowana jej poprawność w kontekście domeny problemu jaki modelujemy firstName i lastName nie mogą być puste. Więc, jeżeli przy konstrukcji takiego obiektu nie podamy parametrów firstName i lastName to można rzucić DomainException.
Mam tylko małą uwagę.
Popraw proszę arkusz styli dla druku, bo lubię czytać wydrukowane artykuły, a w obecnej sytuacji wygląda to marnie…
@Tomasz Kowalczyk
Domyślam się, że wyjątek DomainException doskonale sprawdzi się w DDD. Niestety nie mam z tym za wiele wspólnego, więc musiałby się wypowiedzieć ktoś, kto zna się na rzeczy (np sokzzuka).
@Bigismall
Jak znajdę chwilę, to pogrzebię w szablonie i zobaczę co da się z tym fantem zrobić.
Nie wiem… Może trochę przekombinowuję, ale problematyczny wyjątek można by powiązać z choćby wprowadzonymi w 5 przestrzeniami nazw. Jest to swego rodzaju domena.
Akurat omawiane klasy wyjątków pojawiły się w PHP „nieco” później, niż reszta obiektówki. Początkowo do dyspozycji była wyłącznie klasa Exception.
Kluczem do zrozumienia zastosowania części z omówionych tu klas jest zwrócenie uwagi, że one nawzajem dziedziczą po sobie. Przykładowo, LogicException jest klasą bazową dla LengthException oraz OutOfRangeException. W związku z tym jest też błąd w samym tekście dotyczący tego pierwszego. Zgodnie z dokumentacją LengthException oznacza, że długość jest nieprawidłowa, a nie że jakaś wartość ma nieprawidłową długość. Jeśli problem będzie dotyczyć wartości, powinniśmy rzucić coś pochodzącego od RuntimeException.
Zgodnie z dokumentacją LengthException oznacza, że długość jest nieprawidłowa
I dokładnie to samo napisałem. Posłużyłem się tylko bardzo uproszczonym przykładem. I jak już, to powinien zostać zgłoszony nie RuntimeException, a OutOfRangeException.
Napisałeś „Ten typ wyjątku zgłaszany jest w przypadku odebrania danych o niepoprawnej długości” – a tu nie chodzi o niewłaściwą długość odbieranych danych, tylko o niepoprawną wartość parametru „DŁUGOŚĆ”. Jeśli plik ma 1000 bajtów długości, a powinien mieć 2000, rzucasz coś pochodzącego od RuntimeException; jeśli do funkcji sprawdzającej długość pliku podasz np. wymaganą długość równą -2000, wtedy rzucasz LengthException, ponieważ „-2000″ nie jest poprawną wartością długości.
Niestety tu się mylisz. RuntimeException powinien być rzucany tylko i wyłącznie w momencie, gdy aplikacja padła i nie ma żadnego sposobu na odzyskanie przez nią sprawności. LengthException idealnie nadaje się do zgłoszenia informacji, że np. ze strumienia przyszła niepoprana ilość danych.
Chyba Ci się pomyliło z jakimś innym językiem. Dokumentacja jasno mówi: „Exception thrown if an error which can only be found on runtime occurs”. Nie ma tu nic o żadnych padach aplikacji, odzyskiwaniu sprawności itd. Błąd, który wynika np. z wprowadzenia niewłaściwych danych do aplikacji i nie ma nic wspólnego z tym, że jest nieprawidłowo napisana. Nieprawidłowa długość tekstu/pliku spełnia te wszystkie wymagania, jest więc błędem typu RuntimeException. Rany, przecież masz czarno na białym hierarchię klas w dokumentacji, zajrzyj sobie tam i tyle, bo to, co mówisz, nie trzyma się w ogóle kupy.
Jeśli LengthException oznacza, że wartość ma niewłaściwą długość, to powiedz mi w takim razie, dlaczego dziedziczy on po LogicException i dlaczego OutOfBoundsException, który także dotyczy wartości zewnętrznej, dziedziczy po RuntimeException?
OutOfBoundsException nie dotyczy wartości zewnętrznej. Wyjątek ten oznacza, że coś jest niedozwolone i w takiej formie jest nieakceptowane przez aplikację. Dlatego dziedziczy po RuntimeException. LengthException dziedziczy po LogicException z jednego prostego powodu – długość może się zgadać lub nie, czyli wyrażenie jest prawdą lub fałszem. Jeśli jest fałszem, to kwalifikuje się pod wyjątek logiczny.
To może jeszcze jedno małe pytanko – czy rzucenie wyjątku z SPL różni się czymkolwiek od rzucenia własnego wyjątku? Pytam, bo wydaje mi się, że nie ma takiej różnicy, ale zawsze mogę się mylić. ;]
Nie ma. Są to po prostu predefiniowane klasy wyjątków dziedziczące po Exception, których użycie jest opcjonalne i które równie dobrze mógłbyś sobie sam zdefiniować.
Batman -> LogicException nie oznacza, że wyrażenie logiczne jest fałszywe, tylko że zostało nieprawidłowo sformułowane. W dokumentacji jest jasno napisane: „Exception thrown if a logic expression is invalid„, a to nie ma nic wspólnego z wartością tego wyrażenia. Prawidłowe (valid) expression może przyjmować zarówno wartości prawdziwe, jak i fałszywe, zależnie od tego, co do nich podstawimy.
@Tomasz Kowalczyk
SPL został wprowadzony do PHP 5, jednak dopiero od wersji 5.3 nie można go wyłączyć, przez co zawsze jest dostępny. Z opisanych przeze mnie wyjątków możesz korzystać tak samo jak z klasy Exception, która jest bazową klasą dla wszystkich wyjątków.
@Zyx
Łapiesz mnie za słówka.
Nie łapię za słówka, tylko staram się, by się później przez tego typu wpisy totalny burdel nie zrobił. Wyobraź sobie sytuację, gdy będziesz chciał rozróżnić obsługę wyjątków na podstawie tego czy jest to błąd użytkownika (RuntimeException) czy źle ustawionego systemu/programisty (LogicException). Wiele Ci przyjdzie z tego, że masz takie klasy w SPL-u, kiedy każdy je sobie będzie rzucać, jak mu się podoba na zasadzie „a tam, dwa słowa różnicy nie robią”, tym bardziej że dokumentacja do tego jest nienajlepsza. Już lepiej wtedy będzie wyrzucić to w diabły i zrobić własną hierarchię.
Burdel w PHP już jest od dawna i naprawdę przeceniasz mój wkład w jego powstanie.
LogicException jest wykorzystywany również w przypadku próby uzyskania „stanów niemożliwych”.
Przykładowo jeżeli mamy w bazie 2 typy użytkowników bot i człowiek z czego człowiek posiada pola imię i nazwisko a bot nie. W przypadku próby ustawienia imienia można wywalić LogicException (Ponieważ nielogiczne jest aby bot posiadał imię bądź nazwisko). Oczywiście to przykład. Aczkolwiek chodzi o to, żeby logiczna operacja „Bot nie ma imienia” nie została zakłócona.
~Zyx masz może swoją pełna interpretacja SPLExceptions?
http://ralphschindler.com/2010/09/15/exception-best-practices-in-php-5-3
@batman: Sam burdelu w PHP nie zrobiłeś, ale nie ma powodu byś przyczyniał się do jego powiększania.
Z LogicException korzystamy wszędzie tam, gdzie próbujemy zrobić coś co się nie trzyma kupy. Przykładowo:
$app = new App();$app->start();
$app->start(); // wywala LogicException
$app->stop();
A w treści wyjątku coś w stylu „Nie można uruchomić już uruchomionej aplikacji”. Nie ma to nic wspólnego z wartością logiczną (true/false) jakiegoś wyrażenia. I tej wyjątek jest dosyć popularny.
Przykłady z OverflowException i UnderflowException byłby bardziej klarowne gdybyś wykorzystał w nich SplFixedArray (z wielkością równą 3).
RuntimeException (z reguły pod postacią bardziej wyspecjalizowanych obiektów) również jest bardzo popularny. Używany powinien być zawsze wtedy, gdy do jego powstania przyczyniły się okoliczności mogące powstać wyłącznie w trakcie działania aplikacji – czyli bardzo często.
I co jest niby dziwnego w rzucaniu wyjątkami w przypadku walidacji formularzy? Wyjątki powstały właśnie po to by funkcje nie zwracały false/-1/nulla czy pustego tekstu, a pełnowartościową informację o błędzie (tak, błędne dane wprowadzone przez użytkownika to błąd i trzeba na to odpowiednio zareagować) z która da się jakoś normalnie obchodzić. Wszędzie tam, gdzie możesz stwierdzić, że coś poszło nie tak powinieneś wyrzucić wyjątek.
@Crozin
W Twoim przykładzie powinien zostac rzucony wyjątek BadMethodCallException.
Walidowanie formularzy przy pomocy wyjątków jest najgorszym sposobem z możliwych. Błędy walidacji nie są sytuacją wyjątkową tylko jednym z możliwych scenariuszy.
BadMethodCallException jest podtypem LogicException, a to właśnie na niego chciałem zwrócić uwagę. I nie, nie powinno tam być BadMethodCallException, bo nie takie jest przeznaczenie tego obiektu. W palecie wyjątków SPL nie ma niczego co by ściślej określało tego typu sytuację niż LogicException i w niezbyt rozbudowanych przypadkach nada się on dobrze. Inaczej trzeba będzie napisać własną klasę lepiej oddającą typ błędu.
Co do formularzy… Jeżeli podanie błędnych danych nie jest sytuacją wyjątkową to co jest? Bo jak rozumiem w takim przypadku podanie błędnych danych do połączenia z bazą danych, podanie nazwy pliku który nie istnieje czy przekazanie metodzie obiektu w ogóle nie wiadomo jakiego typu (taka bardziej zaawansowana forma błędnych danych) nie powinno rzucać wyjątkiem bo przecież to normalne, że dany użytkownik bazy może mieć inne hasło, plik może nie istnieć itp.
Albo jeszcze inaczej. To jak nie wyjątkiem to czym zasygnalizujesz błąd?
Dla Twojego przykładu najlepiej pasuje BadMethodCallException. Niestety nie ma takiego wyjątku w PHP, który można podciągnąć pod tą sytuację i należy stosować wyjątek najbliżej oddający problem, a nie najogólniejszy.
Wracając do formularzy i wyjątków. Niepoprawne uzupełnienie formularza jest jednym ze scenariuszy. Nie mam tutaj nic „wyjątkowego”. Wyjątkiem może być brak komunikacji z serwerem bazy danych, pojawienie się niepoprawnych danych w strumieniu lub próba wywołania metody, która nie istnieje.
Pytasz jak zasygnalizuję błąd. Bardzo prosto. Funkcja/metoda isValid, która sprawdzi wszystkie niezbędne warunki do zaakceptowania formularza zwraca status true lub false. Na tej podstawie wiadomo, że dane są poprawne lub nie.
Nie, BadMethodCallException kompletnie nie pasuje bo samo wywołanie metody jest jak najbardziej w porządku. Ten wyjątek służy do poinformowania „próbujesz źle wywołać daną metodę”, a nie „tej metody nie powinieneś wywoływać w takim kontekście”. Manual w miarę jasno określa co oznacza ten wyjątek.
>Niepoprawne uzupełnienie formularza jest jednym ze scenariuszy. Nie mam tutaj nic „wyjątkowego”.
Wyjątki nie są od obsługi jakiś bliżej niezdefiniowanych sytuacji wyjątkowych. One są od tego by odpowiednio zareagować w przypadku gdy dany fragment kodu nie jest w stanie ukończyć swojej pracy w planowany sposób.
Proszę powiedz mi kiedy coś jest sytuacją wyjątkową, a kiedy nie ma w niej nic wyjątkowego. Napisałeś, że zerwanie połączenia z bazą danych zasługuje na wyjątek, ale… co jest w tym wyjątkowego (idąc Twoją logiką)? Przecież zaraz po wysłaniu zapytania PHP zaczyna odliczać czas, gdy minie 30 sekund (timeout) uznaje, że wystąpił błąd. Co w tym wyjątkowego? Przecież nawet sam jawnie ustalasz ile PHP ma czekać przed orzeczeniem błędu. Fakt, zdarza się to pewnie rzadziej niż podanie błędnych danych w formularzu, ale… wyjątki są zarezerwowane wyłącznie dla błędów, zdarzających się nie częściej niż 5 razy na godzinę?
Wyjątki miały w założeniu:
1. Uprościć kod. Ma on być napisany z założeniem, że wszystko przebiega pomyślnie – dopiero na końcu dodajemy obsługję błędów. Dzięki temu pozbywamy się dziesiątek IF-ów.
2. Przerwać wykonywanie danej akcji w momencie, gdy jej dalsze wykonywanie nie ma sensu lub byłoby po prostu niebezpieczne.
3. Wymusić (akurat w przypadku PHP z tym wymuszaniem jest dosyć słabo) obsługę błędów przez użytkownika.
Wykorzystanie dziesiątek isValid() (bo trzeba by to robić w kontekście całego formularza jak i po kolei dla każdego z jego elementów) niszczy wszystkie te szczytne cele.
Tak, BadMethodCallException pasuje najlepiej, ponieważ nie ma innej klasy wyjątku opisującej niepoprawne użycie metody.
I tutaj się mylisz, co pokazuje kolejne Twoje zdanie, czyli
Sytuacją wyjątkową jest sytuacja, której nie projektujesz jako przypadek użycia. Mając formularz przypadkiem użycia będzie uzupełnienie i wysłanie formularza. Do tego dochodzi ścieżka alternatywna, czyli niepoprawne uzupełnienie formularza. Sytuacją wyjątkową, której nie opisujesz w przypadku użycia jest np. brak łączności ze źródłem danych (i dlatego to jest wyjątkiem, a nie dlatego, że dzieje się to wyjątkowo rzadko).
Czym według Ciebie różni się zapis:
if(strlen($jakies_pole_z_formularza) < 10)
{
throw new Exception("Błąd");
}
od
if(strlen($jakies_pole_z_formularza) < 10)
{
$errors[] = "Błąd";
}
Według mnie skorzystanie z wyjątków jest tutaj co najmniej bez sensu. Jedyne co zyskasz, to dodatkowa komplikacja polegająca na dodaniu nowej warstwy do aplikacji i przy okazji dodatkowo skomplikujesz przepływ aplikacji.
BadMethodCallException nie opisuje błędnego użycia metody, a błędne wywołanie metody! I tak istnieje… LogicException – albo MySuperHiperLogicException.
Jak już napisałem, wyjątki nie służą obsłudze jakiś sytuacji krytycznych itp. Służą obsłudze wszelkich błędów. Błędne wypełnienie formularza jest… błędem, a nie alternatywnym przypadkiem użycia. Alternatywny przypadek użycia to np. kliknięcie „zapisz jako szkic” albo „anuluj” zamiast „zapisz”.
Na błąd spowodowany nieprawidłowym wypełnieniem formularza reagujemy. A reakcja ta polega na najbardziej prymitywnej formie poinformowania o niepowodzeniu oraz możliwości podjęcia kolejnej próby.
To, że to użytkownik podaje dane i fakt, że względnie często podaje je źle nie zmienia faktu, że jest to najzwyklejszy błąd, taki sam jak przykładowo wykonanie
$comment->setAuthor(new DateTime());(na dobrą sprawę formularz to nic innego jak nakładka umożliwiająca wykonanie właśnie takiego kodu).Mylisz się. Ja upraszczam działanie aplikacji, bo jasno rozdzielam wykonywanie akcji od obsługi błędów i minimalizuję ilość kodu niepotrzebnie zaśmiecającego akcję. Zwróć uwagę, że w drugim przypadku musiałbyś co chwila pisać albo
return, albo jakieśif (count($this->errors) == 0), bo metoda(y) sprawdzające przykładowo adres email przed rejestracją użytkownika powinny darować sobie sprawdzanie rekordów MX czy unikalności maila w momencie gdy na samym początku orzekły błędny format samego maila.Widzę, że nie dasz sobie wytłumaczyć po co są wyjątki i jak z nich korzystać. Pozwolę sobie odesłać Ciebie do kogoś, kto zna się na rzeczy – http://www.codinghorror.com/blog/2009/04/exception-driven-development.html.
Na koniec zastanów się dlaczego żaden poważny framework nie korzysta z wyjątków do walidacji danych lub innych standardowych funkcjonalności (przypadków użycia).
Może to przez to, że dochodzi już 7:00 i jeszcze się spać nie położyłem, ale w tym artykule nie widzę niczego co miałoby bezpośredni z tematem.
Ot, pierwszy z brzegu – Symfony korzysta.
Nie wiem w jakim Symfony sprawdzałeś, ale w ostatniej wersji walidacja odbywa się w metodzie isValid, która zwraca true lub false. Nie ma tutaj żadnych wyjątków. Może Ci się pomylić z walidacją danych po stronie modelu?
@batman A jaki masz argument za tym aby walidacja obiektu czasem nie zwracała wyjątku? Kumam istnienie isValid ale np przy próbie zapisu danych wywali wyjątek bo walidacja nie przechodzi. Toż to prawidłowe podejśce.
@wookieb
Należy oddzielić od siebie walidację danych formularza od walidacji danych trafiających do modelu. W przypadku formularza stosowanie wyjątków spowoduje sprawdzenie czy tylko pierwsze pole zawiera poprawne dane. Rzucenie wyjątku po sprawdzeniu wszystkich pól nie będzie niczym różnić od np.
if(count($errors) > 0) .... Poza tym przeniesiesz odpowiedzialność walidacji formularza gdzieś wyżej, co wprowadzi dodatkową warstwę do aplikacji.Z kolei walidacja danych trafiających do modelu, to już inna bajka. W tym przypadku rzucenie wyjątkiem jest jak najbardziej wskazane. Głównie dlatego, że model nie wie skąd trafiają do niego dane. Może to być na przykład SOAP, Flash, wiersz poleceń itd. Wyjątek jest jedynym sposobem, by powiadomić źródło o wystąpieniu problemu.
Formularz jest częścią modelu. A dokładniej rzecz biorąc interfejsem dla jakiegoś (zestawu) obiektu(ów) pozwalającym na wywołanie odpowiednich setterów w inny sposób. Po co mam dublować kod robiący to samo.
Kto Ci broni objąć blokiem
try-catchpojedyncze pole zamiast całego formularza?Nie przenoszę jej nigdzie wyżej ponieważ pozostaje ona tam gdzie jej miejsce – w modelu. Formularz jedynie pozwala w inny sposób zareagować na pojawienie się tych wyjątków.
Właśnie zaprzeczyłeś sam sobie.
No i Crozin myśli tak jak ja. W modelu powinna być pełna walidacja danych (dotyczących tylko modelu). A co formularz sobie z tym formularz to już nie problem modelu.
@Crozin
Nie zrozumieliśmy się od samego początku. Walidacja danych odbywająca się w modelu jak najbardziej powinna korzystać z wyjątków. Pisząc o walidacji formularza miałem na myśli sytuację znaną z np. ZF, w którym to formularz stanowi odrębny byt, niebędący częścią modelu.
Wychodzi Batmanie, że miałem rację z tymi wyjątkami. Pozgłaszałem wszystkie idiotyzmy wypisywane w dokumentacji, na które się powołujesz, jako błędy i błędy te zostały przyjęte, a następnie naprawione.
@Zyx
To świetnie. Przynajmniej tutaj będzie w PHP porządek. Ale nie oznacza, to że byłem w błędzie, tylko źródło, na które się powoływałem było niepoprawne. Niemniej zwracam honor.