Jak poprawnie używać bloków logicznych if
| Robert | komentarze | Programowanie - Teoria
Instrukcja warunkowa if to element języków programowania który służy do warunkowania poszczególnych operacji w zależności od stanu programu. Wyróżniamy ogólnie dwa stany: TRUE oraz FALSE czyli kolejno prawda i fałsz. Nie będę się zagłębiać w szczegóły jeśli chodzi o Algebrę Boole'a i sposoby budowania takich instrukcji warunkowych za pomocą operatorów. Dziś spróbuję rzucić światło na temat instrukcji warunkowych z trochę innej strony.
Klasycznie w wielu poradnikach programowania oraz różnego rodzaju rozwiązaniach ze StackOverflow możemy znaleźć takie propozycje rozwiązania problemów:
const jakasFunkcja = () => {
if (warunek1) {
instukcja1();
if (warunek2) {
if (warunek3) {
instrukcja3();
}
}
else {
instrukcja2();
}
}
}
Powyższy przykład technicznie jest poprawny, ale zwróć uwagę na problem, że jeśli kod zostanie jeszcze bardziej rozbudowany, to będzie trudniejszy w dalszej rozbudowie. Rozważmy proces logowania użytkownika na dwóch skrajnych przykładach przy częściowym pominięciu Right Ways programowania.
function loginUser ( $user, $password ) {
if ( !isLogged() ) {
//sprawdzamy, czy użytkownik jest już zalogowany
if ( !empty($user) && !empty($password) ) {
//sprawdzamy, czy zmienne wejściowe nie są puste
$userData = getUser( $user );
if ( $userData !== null ) {
//sprawdzamy czy użytkownik istnieje
if ( password_verify( $password, $userData[ '' ] ) )
{
//sprawdzamy czy hasło się zgadza
$sessResult = createSession( $user );
if ( $sessResult ) {
//jak sesja została stworzona poprawnie to zalogowany.
notifyAndRedir( '/','Zalogowano poprawnie' );
}
else {
notifyAndRedir( URL_BACK,'Wystąpił błąd podczas logowania' );
}
}
else {
notifyAndRedir( URL_BACK,'Użytkownik nie istnieje lub hasło nie jest poprawne' );
}
}
else {
notifyAndRedir( URL_BACK,'Użytkownik nie istnieje lub hasło nie jest poprawne' );
}
}
else {
notifyAndRedir( URL_BACK,'Jedno z pól nie zostało wypełnione' );
}
}
redirect('/');
Celowo pominąłem operacje podnoszące bezpieczeństwo aplikacji takie jak sprawdzanie zawartości zmiennych wejściowych. Mimo usilnych starań kod nie jest zbytnio czytelny i niewygodny do dalszych modyfikacji. Spójrzmy teraz na tą samą logikę z nieco innej perspektywy.
//funkcja logująca użytkownika na podstawie loginu oraz hasła
function loginUser ( $user, $password ) {
if ( isLogged() ) {
//sprawdzamy, czy użytkownik jest już zalogowany
redirect('/');
}
if ( empty($user) || empty($password) ) {
//sprawdzamy, czy zmienne wejściowe nie są puste
notifyAndRedir( URL_BACK,'Jedno z pól nie zostało wypełnione' );
}
$userData = getUser( $user );
if ( $userData === null || !password_verify( $password, $userData[ '' ] ) ) {
/* sprawdzamy czy użytkownik istnieje oraz czy hasło się zgadza
Wykorzystując kolejność sprawdzania warunków i wiedzę, że jeśli
$userData !== null to przejdzie do sprawdzenia password_verify
*/
notifyAndRedir( URL_BACK,'Użytkownik nie istnieje lub hasło nie jest poprawne' );
}
$sessResult = createSession( $user );
if ( !$sessResult ) {
//jak sesja została stworzona poprawnie to zalogowany.
notifyAndRedir( URL_BACK,'Wystąpił błąd podczas logowania' );
}
notifyAndRedir( '/','Zalogowano poprawnie' );
}
Powyższy kod jest zdecydowanie czytelniejszy i łatwiejszy do modyfikacji, ponadto jest krótszy. Warto zastanowić się nad tym, w jakim sposób budować instrukcje. Przy okazji wskazówka, warto podczas sprawdzania czy użytkownik istnieje oraz przy porównywaniu hasła pokazywać ten sam komunikat ("Użytkownik nie istnieje lub hasło nie zgadza się") ponieważ uodparnia to aplikację pod względem bezpieczeństwa, atakujący nie ma pewności czy zgadł już użytkownika, czy też nie i może przystąpić do odgadywania hasła.