E_NOTICE - wyświetlać czy nie?
Zainspirowany ostatnimi wypowiedziami początkujących (i nie tylko) programistów php, postanowiłem skrobnąć małe co nie co na temat błędów E_NOTICE. Niektórzy mogą mi zarzucić, że E_NOTICE to nie błąd, lecz ja słowo "błąd" użyłem celowo i z pełną świadomością. Zapewne bardziej fachowo należałoby napisać "komunikaty" E_NOTICE, aczkolwiek słowo komunikat to przecież komunikat więc można olać, a błąd to już coś poważniejszego, więc może by warto na niego zwrócić uwagę. Także by nie usypiać uwagi początkujących programistów (jak i niestestety tych już uważających się za niepoczątkujących) będę używał słowa "błąd".
No ale zapewne zapytacie do czego tak w ogóle zmierzam. Już wyjaśniam: dosyć często spotykam się ze stwierdzeniem, że E_NOTICE to tylko komunikat, który można totalnie olać a najlepiej wyłączyć jego wyświetlanie (taki komunikat to tylko pierdułka, która powoduje masę śmieci na ekranie). Otóż nie moi drodzy, jesteście w błędzie wszyscy ci, którzy tak właśnie myślicie. Ta "pierdułka" może Wam zaoszczędzić kilku godzin w poszukiwaniu błędów.
Najczęstrzą przyczyną występowania błędów E_NOTICE jest niezadklarowany jakiś indeks w tablicy albo niezadeklarowana zmienna. Przykład:
//tutaj kod formularza
//....
if ($_POST['submit']){
//jeśli wyslalismy formularz to cos tam robimy
//....
// tutaj coś robimy, np. wysyłamy dane z formularza do bazy
}
Taki kod, w przypadku gdy wejdziemy na stronę z formularzem, ale jeszcze formularza nie wysłaliśmy, wygeneruje nam E_NOTICE undefined index submit...... W tym akurat przypadku, E_NOTICE faktycznie jest zwykłym komunikatem, który informuje nas, że odwołujemy się do indeksu submit w tabeli $_POST, którego nie ma. A nie ma, bo nie wysłaliśmy jeszcze formularza. Tak czy siak warunek nie jest spełniony, a o to chodzi. Gdy formularz wyślemy, indeks będzie, warunek będzie spełniony i zostanie wykonane wszystko co ma być wykonane po wysłaniu formularza. Jaki więc wniosek wyciąga początkujący programista? E_NOTICE tu tylko bruździ więc przestanę go wyświetlać i po sprawie.
Wszystko fajnie pięknie, programista więc wyłączył E_NOTICE, nie robią one bałaganu na stronie, skrypt działa jak ta lala. No ale nasz początkujący programista pisze dalej. Rozpatrzmy kolejną sytuację:
//tutaj kod formularza
//formularz ten zawiera między innymi pole o nazwie np. length
//<input type="text" name="length" />
//....
if ($_POST['submit']){
//jeśli wyslalismy formularz to cos tam robimy
//....
// tutaj coś robimy, np. wysyłamy dane z formularza do bazy
$length = $_POST['lenth']; //tę wartość programista wklada do bazy
}
W kodzie powyżej nasz dzielny programista pobiera wartości z formularza i wkłada je do bazy. Biedak ma jednak problem, bo jednej wartości nie może uzyskać. Chodzi oczywiście o wartość pola length - przy pobieraniu wartości tego pola popełnił literówkę. Siedzi więc bidulka i włosy z głowy wyrywa co jest nie tak. Patrzy na kod z lewej, z prawej, z góry - nic. Wkońcu zrozpaczony po "dwóch dniach" szukania błędu (to też jest dobre, jak ludzie lubią pisać na forum ile to godzin/dni spędzili na szukaniu błędu, a w rzeczywistości widać, że raczej zajmowali się czym innym) leci na forum i wali tekst: "Skrypt jest poprawny, ale nie wkłada mi wartości z formularza. Co jest nie tak? Pomóżcie, siedzę nad tym dwa dni". Oczywiście problem by był do zdiagnozowania w dwie minuty a nie w "dwa dni", gdyby nasz "chowacz noticów" jednak nie ukrywał błędów E_NOTICE a je wyświetlał. Gdyby tak zrobił, dostałby od razu komunikat undefined index lenth... i prawdopodobnie (piszę prawdopodobnie bo zdarzają się też "ślepcy") ujrzał by banalną literówkę, którą uczynił.
No dobrze, ale jak koleś włączy te E_NOTICE to nadal będzie dostawał ten zbędny komunikat, z pierwszego kodu. Co z nim uczynić? Odpowiedź jest banalnie prosta: zrobić tak, by ten komunikat się nie wyświetlał. I nie moi mili, nie chodzi mi tu o zastosowanie małpy (@), która wycisza komunikaty błędów. Chodzi mi o poprawne pisanie kodu. Jeśli więc chcemy sprawdzić, czy istnieje jakiś indeks, użyjmy do tego isset lub !empty
if (isset($_POST['submit'])){
}
if (!empty($_POST['submit'])){
}
To co użyjecie i jak, zależy w dużej mierze już od tego co chcecie osiągnąć. Nie będę tu się rozpisywał na temat metod, bo miejsca w bazie na ten artykuł mi zabraknie
Rozpatrzmy jeszcze jedną sytuację na koniec: nasz bohater jednak stwierdził, że na razie będzie lał na E_NOTICE - za "dużo" babrania w "ładne" pisanie. Tak więc pisze sobie swój własny system, ignoruje wszelkie błędy E_NOTICE, bo ich nie wyświetla. Tak sobie pisze przez kilka miesięcy. Natrafił jednak na problem/błąd, z którym nie mógł sobie poradzić. Z racji, że już trochę zmądrzał stwierdził, iż skorzysta jednak z E_NOTICE - może one pomogą mu w rozwiązaniu aktualnego problemu. Zadowolony, iż wpadł na tak genialny pomysł, włącza wyświetlanie wszystkich błędów - a tu ZONK. Z racji, że przez tyle czasu ignorował E_NOTICE, teraz nagle na ekranie pojawia mu się ich kilkadziesiąt - na ekranie ma normalnie czarno od błędów. Rzecz jasna, że przy takiej ilości "komunikatów" nie jest w stanie wychwycić tego, które może mu pomóc przy jego obecnym problemie...
No ale zapytacie: Czy na pewno zawsze trzeba pisać tak, by błąd się nie pojawiał? Czy naprawdę nie można go wyciszyć przy użyciu np. @? Odpowiedź: w bardzo ale to naprawdę w bardzo wyjątkwych sytuacjach można. Ale zapomnijcie o tych "wyjątkach" i nigdy nie używajcie @. Swego czasu w Zend Framework natrafiłem na kod, który używał @ do ewidentnego wyciszenia błędu rzucanego przez funkcję operującą na pliku. Kolesie z ZF użyli tego, gdyż było to szybsze niż wykonanie dodatkowej funkcji sprawdzającej stan pliku. Oczywiście błąd się generował, ale był wyciszany przez @ i nie był wyświetlany. Ja jednak użyłem własnej obsługi błędów i wyświetlałem nawet wyciszane błędy - w wyniku czego logi z błędami mi puchły - trochę napsioczyłem wówczas na kolesi z ZF
Na koniec chcę Wam przedstawić kod:
<?php
$end1 = microtime(true);
error_reporting(E_ALL ^ E_NOTICE);
ini_set('display_errors','1');
$start1 = microtime(true);
for ($i=0;$i < 10000;$i++){
if ($_POST['zm']){
//rob cos
}
}
$end1 = microtime(true);
echo 'Z wylaczeniem E_NOTICE: '.($end1 - $start1);
$end1 = microtime(true);
error_reporting(E_ALL);
ini_set('display_errors','1');
$start1 = microtime(true);
for ($i=0;$i < 10000;$i++){
if (isset($_POST['zm'])){
//rob cos
}
}
$end1 = microtime(true);
echo '<br />Z wlaczeniem E_NOTICE i ich niegenerowaniem: '.($end1 - $start1);
?>
Kod ten porównuje sytuację, gdy nie wyświetlamy błędów E_NOTICE, ale mamy taki kod, który je generuje. Drugą sytuacją jest gdy wyświetlamy wszystko jak popadnie, ale tak piszemy, by E_NOTICE nie były generowane. O to wyniki:
Z wylaczeniem E_NOTICE: 0.0129368305206
Z wlaczeniem E_NOTICE i ich niegenerowaniem: 0.00205683708191
0.0129368305206
0.00205683708191
Jak widać ładniejsze pisanie, mimo iż może jest dłuższe w kodzie (dłuższe "aż" o pare znaków) to jednak zdecydowanie szybciej się wykonuje - może ten argument Was przekona
Podsumowanie
W wielkim skrócie: zawsze, ale to zawsze analizujcie E_NOTICE, które dostajecie w wyniku działania skryptu. Nie wyciszajcie ich ani nie ignorujcie - te "komunikaty" naprawdę mogą Wam pomóc. Nawet jeśli teraz tego nie widzicie - w przyszłości wspomnicie moje słowa. A jak włączyć wyświetlanie wszystkich błędów? Tutaj macie napisane. Oczywiście takie wyświetlanie będziecie mieć na początku waszej przygody z php. Z czasem zapewne zaczniecie używać jakiegoś własnego systemu logowania błędów, np. przy użyciu set_error_handler().