2012-05-09 12 views
33

Czy jest możliwe wykonanie zatrzymania PHP po powiadomieniu/ostrzeżeniu na całym świecie?Zatrzymanie wykonywania skryptu po powiadomieniu/ostrzeżeniu

Prowadzimy serwer deweloperski z wieloma witrynami, ale chcemy zmusić naszych programistów do naprawiania tych ostrzeżeń/zawiadomień (lub poprosić o pomoc co najmniej) zamiast ignorować i kontynuować.

Odpowiedz

47

Tak, jest to możliwe. To pytanie dotyczy bardziej ogólnego problemu obsługi błędów w PHP. Należy zdefiniować i zarejestrować niestandardową procedurę obsługi błędów za pomocą set_error_handlerdocs, aby dostosować obsługę błędów PHP.

IMHO najlepiej jest rzucić wyjątek na dowolny błąd PHP i użyć bloków try/catch do sterowania przepływem programu, ale opinie różnią się w tym punkcie.

Aby osiągnąć PO stwierdził cel można zrobić coś takiego:

function errHandle($errNo, $errStr, $errFile, $errLine) { 
    $msg = "$errStr in $errFile on line $errLine"; 
    if ($errNo == E_NOTICE || $errNo == E_WARNING) { 
     throw new ErrorException($msg, $errNo); 
    } else { 
     echo $msg; 
    } 
} 

set_error_handler('errHandle'); 

Powyższy kod wygeneruje ErrorException żadnej chwili E_NOTICE lub E_WARNING jest podniesiona, skutecznie kończąc wyjście skryptu (jeśli wyjątek nie jest złapany). Zgłaszanie wyjątków w przypadku błędów PHP najlepiej jest połączyć z równoległą strategią obsługi wyjątków (set_exception_handler), aby z gracją zakończyć w środowiskach produkcyjnych.

Należy zauważyć, że powyższy przykład nie będzie zgodny z operatorem tłumienia błędów @. Jeśli jest to dla Ciebie ważne, wystarczy dodać czek z funkcją error_reporting() jak wykazano tutaj:

function errHandle($errNo, $errStr, $errFile, $errLine) { 
    if (error_reporting() == 0) { 
     // @ suppression used, don't worry about it 
     return; 
    } 
    // handle error here 
} 
+0

I procedurę obsługi błędów można zdefiniować i zarejestrować za pomocą ustawienia 'auto_prepend_file'. – goat

+0

Dobre rzeczy, auto_popend_file to :-) .. zobaczmy, jak Magento lubi tę przeglądarkę swojej własnej obsługi wyjątków. – Michael

+0

Co jest warte, zdecydowanie odradzam użycie 'auto_prepend_file'. – rdlowrey

-4

Można włączyć error_reporting do E_ALL w pliku konfiguracyjnym PHP z serwerem.

W PHP 5 dostępny jest nowy poziom błędu E_STRICT. Ponieważ E_STRICT nie jest zawarty w E_ALL, musisz jawnie włączyć ten poziom błędu. Włączenie E_STRICT podczas programowania ma pewne zalety. Wiadomości typu STRICT pomagają w korzystaniu z najnowszej i najlepiej zasugerowanej metody kodowania, na przykład ostrzegają przed użyciem przestarzałych funkcji.

referencyjny: PHP Configuration Manual

następujące ustawienia poprowadzi cię do wyjścia wszystkie błędy w skrypcie. Należy pamiętać, że będą one musiały być uwzględnione na początku wszystkich plików skryptów.

+1

W twojej odpowiedzi brakuje części pytania dotyczącej "zatrzymania realizacji". Ustawienie raportowania błędów wpłynie tylko na wynik (na ekranie lub logu), ale tylko błędy lub fatały zatrzymają skrypt - ostrzeżenia i powiadomienia nie będą. – Sven

6

Możesz to skonfigurować globalnie w swoim php.ini file­Docs.

Można to zrobić poprzez określenie pliku, który jest dołączony przez wszystkich procesów PHP z auto_prepend_file directive­Docs:

auto_prepend_file "/full/path/to/a/prepend-file.php" 

Robi to w tobie globalny plik php.ini zapewni, że kod wewnątrz pliku poprzedzić będzie zawsze sprawdzony. Można go używać następnie zarejestrować globalnej obsługi błędów, które będą turn all errors into exceptions­Docs:

<?php 
function exception_error_handler($errno, $errstr, $errfile, $errline) { 
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline); 
} 
set_error_handler("exception_error_handler"); 

Ten mały skrypt włączyć wszystkie błędy/ostrzeżenia/zawiadomień itp do w ErrorException.

Połączyć go z error_reporting ini directive­Docs, wartości są opisane w pliku php.ini.

Wyrzucanie wyjątku jest bardzo surową rzeczą. Twoi programiści będą musieli radzić sobie z ostrzeżeniami i błędami, w przeciwnym razie kod nie będzie działał.

Prawdopodobnie jest to za dużo dla programistów i nie jest akceptowane społecznie w firmie. Zamiast tego można również rejestrować wszystkie błędy i dodawać je na końcu wyjścia (lub u góry, aby było lepiej widoczne), korzystając z buforowania wyjściowego.

Inną alternatywą jest rejestrowanie błędów i ostrzeżeń w pliku dziennika, a następnie monitorowanie tego pliku za pomocą innego procesu i agregowanie informacji. Możesz stworzyć tablicę wyników, która wyświetli liczbę ostrzeżeń na aplikację i sprawi, że będzie ona widoczna w biurze, aby wszyscy widzieli, jak dobrze zespół wykonuje swoją grę lub coś w tym stylu.

Próbuję powiedzieć: obok problemu technicznego, jest to problem społeczny, z którym trzeba się wykazać kreatywnością i faktycznie rozwiązać problem ze swoimi programistami. Musisz wyjaśnić, dlaczego ważne jest poprawianie ostrzeżeń i błędów oraz w jaki sposób ich kodowanie i umiejętności na tym skorzystają.

+1

Dla zapisu nie korzystam z 'auto_prepend_file'. Myślę, że kod powinien jasno określać, co się dzieje. Nie chcę, aby dyrektywa php.ini powodowała magiczne zachowanie, którego nie widzę w rzeczywistym kodzie źródłowym. IMHO to * dużo * lepiej wykonać proste wywołanie 'require'. Co stanie się za miesiąc, gdy spojrzysz na fragment kodu i stracisz zdrowie psychiczne, ponieważ nie ma sensu, dlaczego coś się dzieje? Co się stanie, jeśli nowy programista dołączy do zespołu? Nie mieliby pojęcia, że ​​dyrektywa php.ini automatycznie zawiera kod. – rdlowrey

+0

Co dalej, jeśli każde wykonanie php nie powinno obsługiwać błędów w ten sam sposób? 'auto_popend_file' i' auto_append_file' niepotrzebnie blokują cię w określone zachowania i widzę je jako jedną z "złych części" PHP. Tylko moje dwa centy :) – rdlowrey

+0

@rdlowrey: 'auto_popend_file' ma słabe strony, ale łatwo jest dać szansę na start. Osobiście uwielbiam znacznie bardziej centralne logowanie i podpinanie logów za pomocą skryptów powłoki, na przykład powiadamianie o błędach na pulpicie, takich jak: https://github.com/ktomk/Miscellaneous/tree/master/notify-phperrors – hakre

5

Od PHP 5.3.0:

set_error_handler(
    function(int $nSeverity, string $strMessage, string $strFilePath, int $nLineNumber){ 
     if(error_reporting()!==0) // Not error suppression operator @ 
      throw new \ErrorException($strMessage, /*nExceptionCode*/ 0, $nSeverity, $strFilePath, $nLineNumber); 
    }, 
    /*E_ALL*/ -1 
); 
3

Jeśli jesteś w środowisku programistycznym, można rozważyć zainstalowanie modułu Xdebug i ustawić xdebug.halt_level=E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE gdzieś w PHP ini plików. Programista może zresetować xdebug.halt_level, ale mamy ten sam problem z odpowiedzią opartą na set_error_handler, ponieważ możemy przywrócić program obsługi do jego pierwotnej wartości.

+0

Ja osobiście wolę takie podejście. Dla nas to podejście jest najlepsze pod względem skalowalności. Środowiska nieprodukcyjne (rozwój, test, etap itp.) Działają na pojedynczych maszynach/instancjach. Produkcja jest zrównoważona w wielu dziedzinach. Idea posiadania plików aut/preloadowanych daje tylko dodatkowy obszar na problemy. Dzięki takiemu podejściu wszystkie środowiska są takie same, z wyjątkiem tego, że zatrzymują się w zasadzie na niczym, co drastycznie eliminuje to, co kończy się na Produkcji. – conrad10781

0

Inne rozwiązania implementują niestandardową procedurę obsługi błędów, która zastępuje domyślny mechanizm rejestrowania błędów. Oznacza to, że po ustawieniu niestandardowej procedury obsługi błędów, powiadomienie/ostrzeżenie nie jest już drukowane w sposób domyślny, dlatego zmieniamy więcej niż "zatrzymaj wykonywanie skryptu po powiadomieniu/ostrzeżeniu".

Potrzebowałem jednak sposobu na wydrukowanie wiadomości - w moim przypadku w PHP CLI - ponieważ dane wyjściowe są następnie analizowane przez inny program. Więc nie chciałem drukować wiadomości w postaci w jakiś sposób, ale w ten sam sposób, w jaki zwykle robi to PHP. I Po prostu chciał zatrzymać proces PHP CLI z kodem wyjścia != 0 tuż po ostrzeżeniu/ostrzeżenie zostało wydrukowane, i zrobić nie zmieniać niczego innego.

Niestety, nie istnieje domyślny sposób wyjścia ze skryptu bez zmiany całego błędu obsługi. Tak więc musiałem ponownie zaimplementować domyślną procedurę obsługi błędów (która jest zaimplementowana w języku C) w PHP.

W tym celu przyjrzałem się domyślnemu mechanizmowi drukowania błędów w kodzie źródłowym PHP i przesortowałem odpowiednie fragmenty z C do PHP, aby uzyskać następującą procedurę obsługi błędów, którą chcę się z wami podzielić w przypadku, gdy potrzebujesz czegoś podobnego:

set_error_handler(
    function($errNo, $errStr, $errFile, $errLine) { 
     $error_type_str = 'Error'; 
     // Source of the switch logic: default error handler in PHP's main.c 
     switch ($errNo) { 
      case E_ERROR: 
      case E_CORE_ERROR: 
      case E_COMPILE_ERROR: 
      case E_USER_ERROR: 
       $error_type_str = "Fatal error"; 
       break; 
      case E_RECOVERABLE_ERROR: 
       $error_type_str = "Recoverable fatal error"; 
       break; 
      case E_WARNING: 
      case E_CORE_WARNING: 
      case E_COMPILE_WARNING: 
      case E_USER_WARNING: 
       $error_type_str = "Warning"; 
       break; 
      case E_PARSE: 
       $error_type_str = "Parse error"; 
       break; 
      case E_NOTICE: 
      case E_USER_NOTICE: 
       $error_type_str = "Notice"; 
       break; 
      case E_STRICT: 
       $error_type_str = "Strict Standards"; 
       break; 
      case E_DEPRECATED: 
      case E_USER_DEPRECATED: 
       $error_type_str = "Deprecated"; 
       break; 
      default: 
       $error_type_str = "Unknown error"; 
       break; 
     } 
     fwrite(STDERR, "PHP $error_type_str: $errStr in $errFile on line $errLine\n"); 
     exit(1); 
    }, 
    E_ALL 
); 
Powiązane problemy