Skocz do zawartości

Zarchiwizowany

Ten temat jest archiwizowany i nie można dodawać nowych odpowiedzi.

dj.drezyna

[php] Obsługa błędów (niepowielanie kodu)

Polecane posty

Mam problem raczej łatwy ale ostatnio pojawiała się konieczność jego rozwiązania, a ja sobie z tym nie radzę.

Otóż mam jakiś warunek do spełnienia, a ponieważ jest on używany wielokrotnie umieszczam go w metodzie:

private function czyJest($elmn) {
if (in_array($elmn,array('a','b','c'))) {
return true;
}
return false;
}

Dalej piszę:

public function wezDane() {
if ($this->czyJest('f')) {
// jak jest robie to i to
}
else {
return 'Nie masz uprawnień do wykonania tej operacji';
}
}

No i pojawia się problem co zrobić by tekst i całą instrukcję else{} nie powtarzać przy każdym wywołaniu metody czyJest() tylko żeby ten sam błąd w przypadku zwrócenia false był wyświetlony w danym miejscu, czyli gdzie wykona się metodę czyJest().

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

trudno odpowiedzieć jednoznacznie, wszystko zależy od twojego pozostałego kodu kodu.

 

Możesz zrobić np. tak

class exception_access extends Exception{}
class mojaKlasa
{
 private function czyJest($elmn) {     
  if (in_array($elmn,array('a','b','c'))) {         return true;      }        
  throw new exception_access('Nie masz uprawnień do wykonania tej operacji',1);  
}   

 public function wezDane() {
    $this->czyJest('f');      // jak jest robie to i to 
 }


}


/////<html> .....
try
{
  $klasa = new mojaKlasa();
  $klasa->wezDane();

}
catch(exception_access $ac)
{
  echo $ac->getMessage();
}
///</html>

 

ale to tylko jedna z wielu możliwości

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

No też jakoś tak myślałem o wykorzystaniu Klasy Exception ale nie za bardzo widziałem, jak dokładnie to zrobić bo szczerze nie dobrze ale jednak - mało korzystam z obsługi błędów, raczej stosuję flagi. Ale rozwiązanie jest fajne.

 

Tylko jedno nie daje mi spokoju. Bo są inne rozwiązania jak powiadasz, więc o chociaż jakiś skrót bym prosił, co pozwoli chociaż wygoglować.

 

Dziękuję bardzo za odpowiedź

 

PS: A to

 to tak można wewnątrz klasy pisać znaczniki?

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

PS: A to

 to tak można wewnątrz klasy pisać znaczniki?

 

Nie można ale nasze forum uznało że tak będzie lepiej :D

 

Co do innych rozwiązań,

możesz próbować np. zwracania kodów błędów lub wywoływania specjalnych funkcji.

Ale wersja z wyjątkami jest zdecydowanie najbardziej nowoczesna i wygodna

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Dzięki Sazian! Tyle razy mi już pomogłeś i tym razem też super rozwiązanie zapodałeś. Dziękuję bardzo. Fajnie działa i dokładnie oto chodziło!

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Warto też wyjaśnić pewną sprawę, która mi się nasunęła. Otóż co w sytuacji gdy będą dwa wrunki np:

private function czyJest($id) {
if (in_array($id,array(1,2,3,4,5,6,7,8,9,0))) {
return true;
}
throw new Exception('Nie ma id!');
}

private function czyZawiera($id) {
if (in_array($id,array('a','b','c'))) {
return true;
}
throw new Exception('Nie ma elementu!');
}

// i dalej...

if (($this->czyJest($id)) or ($this->czyZawiera($elmn))) {
//coś tam robię sobie...
}

I teraz pytanie. Co się stanie jeżeli pierwsze zwróci true, a drugie false. If się wykona ale zostanie rzucony Błąd i co dalej???

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Jak to co ?

 

To ty znasz swój program i to ty decydujesz co się stanie. Ogólnie zasada jest taka że jak się wyrzucił wyjątek to nie ważne co się stało wcześniej anulujesz operacje i zwracasz komunikat.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

No tak ale mi chodzi oto, że przecież to jest operator or czyli jeżeli jedno jest true a drugie false to przecież ,,//coś tam sobie robię'' się wykona, a to że drugi warunek jest false rzuci się błąd i co teraz? Bo jeżeli jeden z tych warunków jest dobry powinno się wszystko wykonać okej tymczasem zostaje rzucony błąd. I co nie rzucać go? To co się stanie z tak fajnie rozwiązaną sprawą w tym temacie o niepowtarzaniu komunikatu ciągle wypisując go w klauzuli else?

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

nawet nie musisz robić if'a

jeśli wystąpi wyjątek to kod zostanie przerwany i przejdzie do catch

 

czyli

try
{
echo 'a';
throw new exception('wiadomość');
echo 'b';
}
catch(exception $e)
{
echo 'c';
}


wyświetli „ac”

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

No okej, czyli jestem w pkt. wyjścia, bo jak uzyskać efekt taki by nie powtarzać komunikatów warunkowych takich jak pierwszym poście? Bo z jednym działa na wyjątkach bardzo dobrze natomiast jaki sposób zastosować przy warunkach opartych na or gdzie jeden spełniony warunek umożliwia zakończenie pewnych działań i niepożądane jest wyrzucenie błędu, bo jedno jest prawdziwe i nie trzeba błędu zgłaszać a jednocześnie nie chciałbym w else kolejny raz pisać że tego nie znaleziono i że tamten nie zawiera a tamten nie jest (Post 6).

 

Bo pisząc ten temat miałem nadzieję na rozwiązanie problemu powtarzających się komunikatów pisanych za każdym razem po niespełnieniu warunku(ów) Potem to jakoś przeszło na Exception ale przy łączeniu tychże błędów operatorem or coś się posypało. Teraz problem opisany jest jaśniej?

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Ok mam nadzieję że chodzi i o łatwiejszą wersje czyli wyświetlenie pierwszego błędu

function a($arg=0)
{
if($arg==1)
{
return true;
}
throw new Exception('aa');

}
function b($arg=0)
{
if($arg==1)
{
return true;
}

throw new Exception('bb');

}

try
{
if(a(0) || b(0))
{
echo 'ok';

}
}
catch(Exception $e)
{

var_dump($e->getMessage());
}

czyli de facto to co było.

Jeśli wystąpi błąd w funkcji a to wyświetli jej komunikat.

Jeśli funkcja a zakończy się powodzeniem ale b rzuci wyjątek to wyświetli jego komunikat.

Jeśli obie funkcje przejdą prawidłowo to wtedy wyświetli „ok”.

 

Problem pojawia się gdy chcesz wyświetlić oba komunikaty błędu.

 

Jedyne co przychodzi mi do głowy to:

1)funkcje nie rzucają wyjątku a tylko go zwracają

2)wynik działania funkcji w if'ie jest zapisywany do zmiennej

3)jeśli if jest niespełniony to wtedy tworzysz listę wyjątków, zapisując jeden w drugim i rzucamy pierwszy.

Czyli jeśli zostały zwrócone wyjątki ex1, ex2 i ex3 to w ex1 zapisujemy ex2, w ex2 zapisujemy ex3 i rzucamy ex1(zawiera w sobie wszystkie wyjątki)

4)w sekcji catch odczytujesz komunikaty z rzuconego wyjątku oraz z wyjątków „zagnieżdżonych”

 

class myException extends Exception
{
protected $before=null; //wyjątek zagnieżdżony
/***
standardowe getery i setery
znaczek & wymusza użycie referencji po powinno zaoszczędzić RAM i CPU
***/
public function setBeforeException(myException &$before)
{
$this->before=$before;
}
public function getBeforeException()
{
return $this->before;
}

}
function a($arg=0)
{
if($arg==1)
{
return true;
}
return new myException('aa');

}
function b($arg=0)
{
if($arg==1)
{
return true;
}

return new myException('bb');

}
/*** funkcja zapisuje wyjątek jeden w drugim, wyjątki podajemy jako kolejne argumenty ***/
function cascadeException()
{
$first=null; //pierwszy wyjątek, ten będzie rzucany
$last=null; //ostatnio użyty wyjątek, do tego dodajemy kolejne
$args=func_get_args(); //pobranie argumentów
if(count($args)>0)
{
foreach($args as $a)
{
if($a instanceof myException)
{
if($first==null)
{
$first=$a;
$last=$first;
}
else
{
$last->setBeforeException($a);
$last=$a;
}

}

}
if($first!=null)
{
throw $first;
}
}

}
try
{
if(($a=a(0))===true || ($b=b(0))===true )
{
echo 'ok';
}
else
{
cascadeException($a,$b); //jeśli wystąpił błąd to zapisz kolejne wyjątki jeden w drugim
}

}
catch(Exception $e)
{
$err=array(); //tablica wiadomości
$err[]=$e->getMessage(); //wiadomość pierwszego rzuconego wyjątku
$tmp=$e; //zmienna pomocnicza
while(($tmp=$tmp->getBeforeException())!==null) //pobierz kolejne wyjątki
{
$err[]=$tmp->getMessage(); //dopisz wiadomość
}
var_dump($err);
}

 

mam nadzieję że wiesz o co chodzi ;)

i pamiętaj o bardzo ważnej zależności jeśli łączysz warunkiem lub w if'ie

jeśli zrobisz if(true || cokolwiek)

to cokolwiek niezostanie sprawdzone, a jeśli jest funkcją to niezostanie wykonana

 

ps.

gdyby forum znowu coś popsuło to tu wklejam drugi kod http://wklejto.pl/136255

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Szczerze mówiąc to przekombinowaliście :P Jeżeli mamy dwa warunki

  • Jeżeli gruszka jest marchewką
  • Jeżeli gruszka jest gruszką

To nie możemy z obu zwracać wyjątków (no możemy ale to nam utrudni sprawę). Prościej jest żeby te funkcje nadal zwracały true / false (Bo albo coś naprawdę pasuje albo nie). A komunikat no cóż nigdy nie jest tak że zwraca się jeden komunikat w kilku miejscach. A nawet jeżeli tak to trzeba go po prostu napisać i nie kombinować. Jednym słowem autor tematu próbuje na silę dopasować puzzel tam gdzie go być nie powinno. Ale oczywiście może kombinować np tak.

 

http://wklejto.pl/txt136269

 

Ale czy aby na pewno wyjątki służą do wyświetlania informacji użytkownikom ? Wydaje mi się że one są do informowania programu o różnych nie pożądanych błędach, a sama treść wyjątku powinna być zapisywana w logach tegoż programu gdy on sam będzie się starał w dalszym ciągu zadziałać prawidłowo / zwrócić odpowiedni komunikat o nie możności wykonania czynności.

 

Podsumują.

 

Do czego służą wyjątki

  • Do informowania programu o pewnych błędach powodujących nie możliwość dalszego wykonania (np nie odpowiadająca baza danych)
  • Do tworzenia logów aplikacji z miejsc krytycznych

 

Do czego NIE SŁUŻĄ WYJĄTKI

  • Do upiększania na sile kodu

 

Co do odpowiedzi. To autor tematu niech spróbuje rozrysować sobie to co chce zrobić i zastanowi się nad swoim kodem czy aby na pewno jest dobrze napisany / przemyślany bo jeżeli w kilku miejscach musi pisać ten sam warunek + ten sam komunikat to mi brakuje jakiegoś kawałka aplikacji według zasady DRY

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

@Sazian

 

Łatwiejsza wersja jest łatwiejsza ale tu jest operator or więc nie powinien pojawiać się błąd, jeżeli drugi warunek się nie spełni podczas, gdy choć jeden jest prawdziwy. Dlatego rozwiązanie dalej przedstawione to jest to!

 

A o tych warunkach to w php jest odwrotnie do js, gdzie to kompilator jest leniwy i jeżeli są użyte tylko operatory or i jeżeli warunek pierwszy jest true to kompilator już nie sprawdza dalej, a jeśli to byłby funkcje, to by ich nie wykonał. A php jak mówisz robi dokładnie odwrotnie.

 

A jak to się dzieje, że wyjątki się zagnieżdżają w sobie. Dotyczy to może innych zmiennych, czy tylko ta klasa ma taką właściwość bo nie spotkałem się z czymś takim jeszcze. Mógłbyś wyjaśnić?

 

No i podsumowując dokładnie oto mi chodziło, bo w ten sposób możliwe jest wykrycie wszystkich błędów w jednym miejscu bez pisania po dziesiąty raz tego samego komunikatu. Dzięki wielkie aż mi wstyd, że tak podane pięknie na tacy ;)

 

 

 

@Stelma

 

Ani trochę nie przekombinowaliśmy, bo popatrz:

public function dodajProjekt($dane) {
if ($this->czyProjektAdm($dane['id'])) {
//dodajemy. . .
}
/*
else {
return 'Nie masz uprawnień do zmiany tego projektu!';
}//Niepotrzebny warunek po zastosowaniu uwag Saziana
*/
}

public function usunProjekt($id) {
if ($this->czyProjektAdm($id)) {
//usuwamy . . .
}
/*
else {
return 'Nie masz uprawnień do zmiany tego projektu!';
}//Niepotrzebny warunek po zastosowaniu uwag Saziana
*/
}

 

Mam nadzieję że teraz rozumiesz, że chodziło mi o stosowanie tego samego waruneku w różnych miejscach, poza tym zauważ, że są to metody publiczne do stosowania z ajaxem.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Może ja jestem dziwny ale czy to ajax czy też zwykłe wywołanie to ma tą samą drogę życia w moich projektach czyli:

  • Router
  • Kontroler
  • Akcja
  • Widok

Sprawdzanie danych odbywa się najczęściej w jakieś akcji która wykorzystuje najczęściej klasę Validate. Ta klasa nigdy ale to przenigdy nie zwraca wyjątku z prostej przyczyny. Ona ma mi powiedzieć czy coś pasuje mi do tego czego szukam czy też nie i w zależności od poprawności danych wyświetlany jest odpowiedni plik z widokiem. Co mi to daje ? A no to że nie muszę x razy mieć w kodzie komunikatów do użytkownika i nie muszę go zmieniać. Sam komunikat siedzi sobie w pliku widoku który to jest wyposażony w klasę tłumaczeń itp. A wyjątki ? A no je wykorzystuje do zażegnania tragicznym błęda aplikacji jak np brak połączeń / plików próba wywołania czegoś co nie istnieje itp.

 

No ale najważniejsze że problem rozwiązany :P tak tylko dorzuciłem trzy grosze żebyś się zastanowił nad tym czy aby napewno masz to dobrze zaprojektowane.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

 

A jak to się dzieje, że wyjątki się zagnieżdżają w sobie. Dotyczy to może innych zmiennych, czy tylko ta klasa ma taką właściwość bo nie spotkałem się z czymś takim jeszcze. Mógłbyś wyjaśnić?

 

 

po pierwsze chyba trochę przedobrzyłem :D

wersja poprawiona http://wklejto.pl/136344

Zamiast listy użyłem tablicy. Wiem że do zmiennej $list nie powinno być dostępu publicznego ale już nie chciało mi się robić geterów i seterów. Fajnym pomysłem może być też użycie iteratora http://php.net/manual/en/class.iterator.php

 

 

A jeśli chodzi o wyjaśnienie to prześledź klasę myException, a w wersji poprawionej ExceptionsList. To właśnie te klasy mają taką właściwość

Dosyć ciekawą konstrukcją jest również ten if – ciekawą jeśli wcześniej tego nie widziałeś

if(($a=a(0))===true || ($b=b(0))===true )

{

echo 'ok';

var_dump($a,$b);

}

else

{

//throw new ExceptionsList($a,$b);

var_dump($a,$b);

}

 

zobacz co się stanie gdy wywołasz a(1) i b(0)

 

 

 

Może ja jestem dziwny ale czy to ajax czy też zwykłe wywołanie to ma tą samą drogę życia

 

Tu się zgadzam, w większości przypadków tak właśnie jest, czasami w AJAX'ie pomijam klasę widoku np. przez użycie json_encode lub pomijam warstwę widoku jeśli nie zależy mi na danych zwrotnych.

Ale w ogólnym przypadku tak.

 

Sprawdzanie danych odbywa się najczęściej w jakieś akcji która wykorzystuje najczęściej klasę Validate. Ta klasa nigdy ale to przenigdy nie zwraca wyjątku z prostej przyczyny. Ona ma mi powiedzieć czy coś pasuje mi do tego czego szukam czy też nie (….)

 

Tak, klasa walidująca powinna dawać w wyniku tylko true/false, ale klasa walidująca sprawdza czy wprowadzone dane są prawidłowe czyli np. czy adres URL jest prawidłowy ? Czy e-mail jest prawidłowy ? Czy to jest prawidłowa liczba zmiennoprzecinkowa ?

 

Ale zauważ że to co robi dj.drezyna to raczej system sprawdzania uprawnień a nie walidacja danych wejściowych.

 

 

A wyjątki ? A no je wykorzystuje do zażegnania tragicznym błęda aplikacji jak np brak połączeń / plików próba wywołania czegoś co nie istnieje itp.

 

A tu się do końca nie zgodzę :) wyjątki służą również do komunikacji wewnątrz aplikacji.

Przykładowo w systemie ACL przed wywołaniem akcji może zostać zgłoszony wyjątek braku uprawnień co spowoduje uruchomienie innej akcji.

Innym przykładem może być wyjątek żądania ponownego uruchomienia aplikacji ale na innym adresie URL(taka forma przekierowania)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

@up

 

@Ajax

Co do ajaxa zgadzam się w 100%. Np tablice lepiej przekazać jsonem do skryptu.

 

@Validate

Tak klasa walidująca posiada same metody statyczne służące do sprawdzenia poprawności danych. Adresem url zajmuje się router to on ma za zadanie przeparsować adres url na swoją własną formę (w końcu ktoś po mnie może chcieć zupełnie inny router).

 

@Wyjątki

Też się zgadzam bo o tym zapomniałem ;p

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Miałem na myśli walidacje, a nie parsowanie adresu URL

czyli np.

if(Valid::url($_POST['strona_www']))
{
echo 'Prawidłowy adres URL';
}
else
{
echo 'Błędny adres URL';
}

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

@Sazian

 

Tak sprawdzałem. Błędy wyświetlają się dopiero po tym jak cały if nie przejdzie, natomiast nie ma rzuconego błędu jeśli choć jeden jest prawdziwy i oto chodzi bo wtedy to wewnątrz ifa się wykona jak należy.

 

Tak jest to jest potrzebne do tego by weryfikować uprawnienia.

 

No i po trzecie to bardzo dziękuję za tak szeroko rozpostartą pomoc dla mnie! Dzięki wielkie, Zapraszam do Olsztyna :)

 

P.S. Problem rozwiązałem na swój sposób opierając się, że prawidłowy jest zapis:

if (($a = $this->jakasFunkcja($pram)) === true)

i na

else {
Uzytkowe::zbierzBledy($a); // Przez Saziana realizowana przez

/*
catch(ExceptionsList $e)
{
foreach($e->list as $v)
{
echo $v->getMessage().'<br />';
}
}
*/

}

Mi wystarczy jedynie komunikat zrzucony przez funkcję spr. upr. no a potem wyświetlenie komunikatów jeżeli wykonana zostanie instrukcja else{}

Te błędy i za każdym razem w catch() {} robić to jakoś nie ale za inspirację należą się WIELKIE i to WIELKIE podziękowania WAM!

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

×