PHP: wyjątki czy błędy?


116

Może brakuje mi tego gdzieś w podręczniku PHP, ale jaka dokładnie jest różnica między błędem a wyjątkiem? Jedyną różnicą, jaką widzę, jest to, że błędy i wyjątki są obsługiwane inaczej. Ale co powoduje wyjątek, a co powoduje błąd?

Odpowiedzi:


87

Wyjątki są wyrzucane - są one przeznaczone do złapany. Błędy są zazwyczaj nie do naprawienia. Powiedzmy na przykład - masz blok kodu, który wstawi wiersz do bazy danych. Możliwe, że to wywołanie się nie powiedzie (zduplikowany identyfikator) - będziesz chciał mieć „Błąd”, który w tym przypadku jest „Wyjątkiem”. Kiedy wstawiasz te wiersze, możesz zrobić coś takiego

try {
  $row->insert();
  $inserted = true;
} catch (Exception $e) {
  echo "There was an error inserting the row - ".$e->getMessage();
  $inserted = false;
}

echo "Some more stuff";

Wykonywanie programu będzie kontynuowane - ponieważ „złapałeś” wyjątek. Wyjątek zostanie potraktowany jako błąd, chyba że zostanie przechwycony. Pozwoli ci to kontynuować wykonywanie programu również po jego niepowodzeniu.


29
Errors are generally unrecoverable<- właściwie to nie jest prawda. E_ERRORi E_PARSEto dwa najczęstsze błędy nienaprawialne (istnieje kilka innych), ale zdecydowana większość błędów będziesz widzieć w dev podlegają zwrotowi ( E_NOTICE, E_WARNINGet al). Niestety obsługa błędów PHP jest kompletnym bałaganem - wszelkiego rodzaju rzeczy niepotrzebnie powodują błędy (na przykład ogromna większość funkcji systemu plików). Generalnie wyjątki to „sposób OOP”, ale niestety niektóre natywne API OOP PHP używają błędów zamiast wyjątków :-(
DaveRandom

1
@DaveRandom E_NOTICE, E_WARNING nie są „błędami” z definicji, prawda? Zawsze myślałem, że to „komunikaty”, które PHP wyświetla, aby powiadomić programistę, że coś może być nie tak z napisanym przez niego kodem.
slhsen

2
@slhsen to naprawdę kiepska terminologia, wszystkie formy tych wiadomości przechodzą przez "system obsługi błędów" w PHP, semantycznie wszystkie te zdarzenia są "błędami", nawet jeśli semantycznie zauważenie / ostrzeżenie zdecydowanie nie jest tym samym, co " błąd ”w tym kontekście. Na szczęście nadchodzące PHP7 przynajmniej utorowało drogę do uporządkowania tego bałaganu poprzez przekształcenie większości z tych rzeczy w możliwe do złapania wyjątki (za pomocą nowego Throwableinterfejsu), dając znacznie bardziej wyrazisty i absolutny sposób na rozróżnienie i prawidłowe przekazanie obu rzeczy problemy i komunikaty doradcze
DaveRandom

Przypuszczam, że „wykonywanie programu będzie kontynuowane” zmieniło się? Ponieważ PHP mówi: „Gdy zostanie zgłoszony wyjątek, kod następujący po instrukcji nie zostanie wykonany” ( php.net/manual/en/language.exceptions.php )
Robert Sinclair

1
Myślę, że to, co oznaczał OP, dotyczyło raczej różnicy między potomkami ErrorVS a potomkami Exception.
XedinUnknown

55

Zwykle korzystam set_error_handlerz funkcji, która przyjmuje błąd i rzuca wyjątek, więc cokolwiek się stanie, będę miał tylko wyjątki do załatwienia. Nie więcej @file_get_contentspo prostu ładny i schludny try / catch.

W sytuacjach debugowania mam również program obsługi wyjątków, który wyprowadza stronę podobną do asp.net. Publikuję to w drodze, ale na żądanie opublikuję później przykładowe źródło.

edytować:

Dodawanie zgodnie z obietnicą, wyciąłem i wkleiłem część kodu, aby utworzyć próbkę. Mam zapisane poniżej do pliku na mojej stacji roboczej, można JUŻ NIE zobaczyć wyniki tutaj (ponieważ link jest uszkodzony).

<?php

define( 'DEBUG', true );

class ErrorOrWarningException extends Exception
{
    protected $_Context = null;
    public function getContext()
    {
        return $this->_Context;
    }
    public function setContext( $value )
    {
        $this->_Context = $value;
    }

    public function __construct( $code, $message, $file, $line, $context )
    {
        parent::__construct( $message, $code );

        $this->file = $file;
        $this->line = $line;
        $this->setContext( $context );
    }
}

/**
 * Inspire to write perfect code. everything is an exception, even minor warnings.
 **/
function error_to_exception( $code, $message, $file, $line, $context )
{
    throw new ErrorOrWarningException( $code, $message, $file, $line, $context );
}
set_error_handler( 'error_to_exception' );

function global_exception_handler( $ex )
{
    ob_start();
    dump_exception( $ex );
    $dump = ob_get_clean();
    // send email of dump to administrator?...

    // if we are in debug mode we are allowed to dump exceptions to the browser.
    if ( defined( 'DEBUG' ) && DEBUG == true )
    {
        echo $dump;
    }
    else // if we are in production we give our visitor a nice message without all the details.
    {
        echo file_get_contents( 'static/errors/fatalexception.html' );
    }
    exit;
}

function dump_exception( Exception $ex )
{
    $file = $ex->getFile();
    $line = $ex->getLine();

    if ( file_exists( $file ) )
    {
        $lines = file( $file );
    }

?><html>
    <head>
        <title><?= $ex->getMessage(); ?></title>
        <style type="text/css">
            body {
                width : 800px;
                margin : auto;
            }

            ul.code {
                border : inset 1px;
            }
            ul.code li {
                white-space: pre ;
                list-style-type : none;
                font-family : monospace;
            }
            ul.code li.line {
                color : red;
            }

            table.trace {
                width : 100%;
                border-collapse : collapse;
                border : solid 1px black;
            }
            table.thead tr {
                background : rgb(240,240,240);
            }
            table.trace tr.odd {
                background : white;
            }
            table.trace tr.even {
                background : rgb(250,250,250);
            }
            table.trace td {
                padding : 2px 4px 2px 4px;
            }
        </style>
    </head>
    <body>
        <h1>Uncaught <?= get_class( $ex ); ?></h1>
        <h2><?= $ex->getMessage(); ?></h2>
        <p>
            An uncaught <?= get_class( $ex ); ?> was thrown on line <?= $line; ?> of file <?= basename( $file ); ?> that prevented further execution of this request.
        </p>
        <h2>Where it happened:</h2>
        <? if ( isset($lines) ) : ?>
        <code><?= $file; ?></code>
        <ul class="code">
            <? for( $i = $line - 3; $i < $line + 3; $i ++ ) : ?>
                <? if ( $i > 0 && $i < count( $lines ) ) : ?>
                    <? if ( $i == $line-1 ) : ?>
                        <li class="line"><?= str_replace( "\n", "", $lines[$i] ); ?></li>
                    <? else : ?>
                        <li><?= str_replace( "\n", "", $lines[$i] ); ?></li>
                    <? endif; ?>
                <? endif; ?>
            <? endfor; ?>
        </ul>
        <? endif; ?>

        <? if ( is_array( $ex->getTrace() ) ) : ?>
        <h2>Stack trace:</h2>
            <table class="trace">
                <thead>
                    <tr>
                        <td>File</td>
                        <td>Line</td>
                        <td>Class</td>
                        <td>Function</td>
                        <td>Arguments</td>
                    </tr>
                </thead>
                <tbody>
                <? foreach ( $ex->getTrace() as $i => $trace ) : ?>
                    <tr class="<?= $i % 2 == 0 ? 'even' : 'odd'; ?>">
                        <td><?= isset($trace[ 'file' ]) ? basename($trace[ 'file' ]) : ''; ?></td>
                        <td><?= isset($trace[ 'line' ]) ? $trace[ 'line' ] : ''; ?></td>
                        <td><?= isset($trace[ 'class' ]) ? $trace[ 'class' ] : ''; ?></td>
                        <td><?= isset($trace[ 'function' ]) ? $trace[ 'function' ] : ''; ?></td>
                        <td>
                            <? if( isset($trace[ 'args' ]) ) : ?>
                                <? foreach ( $trace[ 'args' ] as $i => $arg ) : ?>
                                    <span title="<?= var_export( $arg, true ); ?>"><?= gettype( $arg ); ?></span>
                                    <?= $i < count( $trace['args'] ) -1 ? ',' : ''; ?> 
                                <? endforeach; ?>
                            <? else : ?>
                            NULL
                            <? endif; ?>
                        </td>
                    </tr>
                <? endforeach;?>
                </tbody>
            </table>
        <? else : ?>
            <pre><?= $ex->getTraceAsString(); ?></pre>
        <? endif; ?>
    </body>
</html><? // back in php
}
set_exception_handler( 'global_exception_handler' );

class X
{
    function __construct()
    {
        trigger_error( 'Whoops!', E_USER_NOTICE );      
    }
}

$x = new X();

throw new Exception( 'Execution will never get here' );

?>

To byłoby pomocne. Pomoże mi wszystko, co ułatwi mi pracę z PHP. :-)
Jason Baker

Niezły kod, dzięki. Nie rozumiem jednak, skąd pochodzi klasa X i jaki jest jej cel?
Alec

wszystko poniżej "set_exception_handler ('global_exception_handler');" to tylko demo, nie będziesz go potrzebować, służy tylko do pokazania, co by się stało w normalnej sytuacji błędu bez wyjątku.
Kris

Standardowy PHP definiuje wyjątek ErrorException specjalnie do wyrzucenia z ogólnego modułu obsługi błędów. Czy pozwolisz mi edytować i aktualizować Twój post?
Tiberiu-Ionuț Stan,

@ Tiberiu-IonuțStan: jasne, ale przykład roboczy nie będzie zsynchronizowany. Również w dzisiejszych czasach pewnie bym wskazać ludziom github.com/theredhead/red.web/blob/master/src/lib/bootstrap.php z private-void.com zamiast.
Kris

21

Odpowiedź zasługuje na rozmowę o słoniu w pokoju

Błędy to stary sposób obsługi warunków błędu w czasie wykonywania. Zwykle kod wywołuje coś podobnego set_error_handlerprzed wykonaniem jakiegoś kodu. Podążanie za tradycją asemblera przerywa. Oto jak wyglądałby kod w języku BASIC.

on error :divide_error

print 1/0
print "this won't print"

:divide_error

if errcode = X
   print "divide by zero error"

Trudno było się upewnić, set_error_handlerże zostanie wywołana z odpowiednią wartością. Co gorsza, można by wywołać oddzielną procedurę, która zmieni procedurę obsługi błędów. Ponadto wiele razy połączenia były przeplatane set_error_handlerpołączeniami i programami obsługi. Kod szybko wymknął się spod kontroli. Obsługa wyjątków przyszła na ratunek poprzez sformalizowanie składni i semantyki tego, co naprawdę robi dobry kod.

try {
   print 1/0;
   print "this won't print";
} catch (DivideByZeroException $e) {
   print "divide by zero error";
}

Brak oddzielnej funkcji lub ryzyka wywołania niewłaściwego programu obsługi błędów. Gwarantujemy, że kod będzie teraz znajdował się w tym samym miejscu. Dodatkowo otrzymujemy lepsze komunikaty o błędach.

PHP miał tylko obsługę błędów, podczas gdy wiele innych języków już ewoluowało do preferowanego modelu obsługi wyjątków. Ostatecznie twórcy PHP zaimplementowali obsługę wyjątków. Ale prawdopodobnie obsługują stary kod, zachowali obsługę błędów i zapewnili sposób, aby obsługa błędów wyglądała jak obsługa wyjątków. Poza tym nie ma gwarancji, że jakiś kod nie zresetuje procedury obsługi błędów, co było dokładnie tym, do czego miała zapewnić obsługa wyjątków.

Ostatnia odpowiedź

Błędy, które zostały zakodowane przed wdrożeniem obsługi wyjątków, są prawdopodobnie nadal błędami. Nowe błędy są prawdopodobnie wyjątkami. Ale nie ma projektu ani logiki, do której są błędy i które są wyjątkami. Opiera się tylko na tym, co było dostępne w momencie kodowania, i preferencjach programisty, który to koduje.


3
To jest prawdziwy powód współistnienia wyjątków i błędów. Jeśli został zaprojektowany od zera, php powinien zawierać tylko jedną lub drugą.
Tomas Zubiri

1
Moim zdaniem jest to najlepsza odpowiedź, ponieważ jest najbardziej szczegółowa i wyjaśniająca.
Robert Kusznier

8

Jedną rzeczą do dodania jest obsługa wyjątków i błędów. Dla twórców aplikacji, zarówno błędy, jak i wyjątki to „złe rzeczy”, które chcesz zarejestrować, aby dowiedzieć się o problemach, które ma Twoja aplikacja - aby klienci mieli lepsze wrażenia w dłuższej perspektywie.

Dlatego warto napisać procedurę obsługi błędów, która robi to samo, co w przypadku wyjątków.


Dziękujemy za udostępnienie linku!
Mike Moore

@Alex Weinstein: link jest uszkodzony
Marco Demaio

7

Jak stwierdzono w innych odpowiedziach, ustawienie obsługi błędów na rzucający wyjątek jest najlepszym sposobem obsługi błędów w PHP. Używam nieco prostszej konfiguracji:

set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
        if (error_reporting()) {
                throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
        }
});

Proszę zwrócić uwagę na error_reporting()czek, który należy zachować@ operator pracować. Ponadto nie ma potrzeby definiowania niestandardowego wyjątku, PHP ma do tego jedną fajną klasę.

Ogromną zaletą rzucania wyjątków jest to, że wyjątek ma skojarzony z nim ślad stosu, więc łatwo jest znaleźć problem.


5

Re: "ale jaka dokładnie jest różnica między błędem a wyjątkiem?"

Istnieje wiele dobrych odpowiedzi na temat różnic. Dodam tylko coś, o czym jeszcze nie mówiono - wydajność. W szczególności dotyczy to różnicy między zgłaszaniem / obsługą wyjątków a obsługą kodu powrotu (powodzenie lub błąd). Zwykle w php oznacza to powrót falselub null, ale mogą być bardziej szczegółowe, na przykład przy przesyłaniu plików: http://php.net/manual/en/features.file-upload.errors.php Możesz nawet zwrócić obiekt wyjątku !

Wykonałem kilka testów wydajnościowych w różnych językach / systemach. Ogólnie rzecz biorąc, obsługa wyjątków jest około 10 000 razy wolniejsza niż sprawdzanie kodu powrotu błędu.

Tak więc, jeśli absolutnie, pozytywnie musi zakończyć wykonywanie, zanim jeszcze się zaczęło - cóż, nie masz szczęścia, ponieważ podróże w czasie nie istnieją. Bez podróży w czasie kody zwrotne są najszybszą dostępną opcją.

Edytować:

PHP jest wysoce zoptymalizowany pod kątem obsługi wyjątków. Testy w świecie rzeczywistym pokazują, że rzucanie wyjątku jest tylko 2-10x wolniejsze niż zwracanie wartości.


3
Jasne, ale liczba cykli utraconych podczas rzucania wyjątków jest więcej niż rekompensowana przez dodatkowe moce opisowe, które otrzymujesz dzięki wyjątkom. Możesz zgłaszać określone typy wyjątków, a nawet dodawać dane do wyjątku, aby zawierały kody błędów. Poważnie wątpię również w twoje roszczenie o 10000 *. Nawet jeśli masz rację co do różnicy czasu, czas spędzony na wykonywaniu zwrotu i jeśli w porównaniu z nowym Wykonaniem, rzutem, złapaniem w dowolnym scenariuszu ze świata rzeczywistego jest prawdopodobnie tak malutki w porównaniu z wykonywanym kodem, że jest to zdecydowanie przedwczesna optymalizacja. Rzucaj wyjątki, są przyjemniejsze w 90% przypadków.
gnarf

1
1. 10,000x jest dokładny - z pewnymi odchyleniami w zależności od języka i opcji kompilatora. 2. Nie musisz zwracać wartości null / false. Możesz zwrócić numer - maksymalnie MAX_ULONG kodów powrotu bezpośrednio w tym miejscu. Możesz alternatywnie zwrócić ciąg niepowodzenia i po prostu sprawdzić ciąg znaków sukcesu, int lub null. 3. W rzeczywistych scenariuszach liczy się każdy cykl zegara. Facebook ma codziennie 552 miliony aktywnych użytkowników. Zakładając, że wyjątki są tylko 2x, a sprawdzenie użytkownika / przepustki zajmuje 0,001s, co oznacza oszczędność 153 godzin czasu przetwarzania każdego dnia. Przy 10.000 razy oszczędza 175 lat. Tylko do sprawdzania prób logowania - każdego dnia.
evan,

@evan: FYI, tutaj przetestowali kod z wyjątkami i nie wydaje się, aby był wolniejszy: stackoverflow.com/a/445094/260080
Marco Demaio

@MarcoDemaio To pytanie dotyczy tylko bloku try / catch bez zgłaszania wyjątku. Lepszym testem byłoby zwrócenie wartości w noexcept () i zgłoszenie wyjątku w except (). Powinien również pojawić się w wielu funkcjach. stackoverflow.com/a/104375/505172 stwierdza, że ​​różnica w PHP jest w rzeczywistości 54x. Przeprowadziłem własny test w czasie rzeczywistym i wydaje się, że jest on 2-10x wolniejszy. To jest o wiele lepsze niż oczekiwano.
evan

@evan: Nie martwiłbym się wtedy, używam wyjątków tylko do śledzenia nieoczekiwanych / nieodwracalnych błędów, więc nawet jeśli byłoby to 100 razy wolniejsze, nie przejmowałbym się. Moje obawy dotyczyły spowolnienia kodu, po prostu dodając bloki try / catch.
Marco Demaio

4

Myślę, że odpowiedź, której szukasz, jest taka;

Błędy to standardowe rzeczy, do których jesteś przyzwyczajony, na przykład wywoływanie echa zmiennej $, która nie istnieje.
Wyjątki występują tylko od PHP 5 i występują w przypadku obiektów.

Aby było to proste:

Wyjątkami są błędy, które otrzymujesz podczas pracy z obiektami. Instrukcja try / catch pozwala jednak coś z nimi zrobić i jest używana podobnie jak instrukcja if / else. Spróbuj to zrobić, jeśli problem nie ma znaczenia, zrób to.

Jeśli nie „złapiesz” wyjątku, zamieni się on w standardowy błąd.

Błędy to podstawowe błędy php, które zwykle powodują zatrzymanie skryptu.

Try / catch jest często używane do nawiązywania połączeń z bazą danych, takich jak PDO, co jest w porządku, jeśli chcesz przekierować skrypt lub zrobić coś innego, jeśli połączenie nie działa. Ale jeśli chcesz po prostu wyświetlić komunikat o błędzie i zatrzymać skrypt, nie potrzebujesz tego, nieprzechwycony wyjątek zamienia się w błąd krytyczny. Możesz też użyć ustawienia obsługi błędów w całej witrynie.

Mam nadzieję, że to pomoże


3
Wyjątki mogą być równie dobrze używane z kodem proceduralnym w PHP.
Tiberiu-Ionuț Stan,

2

W PHP 7.1 i nowszych blok catch może określać wiele wyjątków za pomocą znaku potoku (|). Jest to przydatne, gdy różne wyjątki z różnych hierarchii klas są obsługiwane tak samo.

try {
  // do something
} catch (Error | Exception $e) {
  echo $e->getMessage();
}

1

Wyjątki są celowo generowane przez kod za pomocą rzutu, błędy ... nie tak bardzo.

Błędy pojawiają się w wyniku czegoś, co zwykle nie jest obsługiwane. (Błędy we / wy, błędy TCP / IP, błędy odniesienia zerowego)


1
To niekoniecznie jest prawdą. W wielu przypadkach sprawdzane są błędy, a kody zwrotne są celowo odsyłane w razie potrzeby. W rzeczywistości tak jest w przypadku każdego języka nie zorientowanego obiektowo. Wyjątki to także wyjątki od reguły. W obu przypadkach coś idzie nie tak, zostaje zauważone i należy się tym zająć. PHP przesyłania plików jest jednym z przykładów celowego obsługi błędów kodem powrotu - php.net/manual/en/features.file-upload.errors.php
Evan

1

Zamierzam przedstawić najbardziej niezwykłe omówienie kontroli błędów.

Wiele lat temu zbudowałem bardzo dobrą obsługę błędów w języku i chociaż niektóre nazwy się zmieniły, zasady przetwarzania błędów są dziś takie same. Miałem niestandardowy wielozadaniowy system operacyjny i musiałem móc odzyskać dane po błędach danych na wszystkich poziomach bez wycieków pamięci, wzrostu stosu lub awarii. Poniżej przedstawiam moje zrozumienie tego, jak muszą działać błędy i wyjątki i czym się różnią. Powiem tylko, że nie rozumiem, jak działają elementy wewnętrzne try catch, więc do pewnego stopnia zgaduję.

Pierwszą rzeczą, która dzieje się pod osłoną przetwarzania błędów, jest przeskakiwanie z jednego stanu programu do drugiego. Jak to się robi? Dojdę do tego.

Historycznie rzecz biorąc, błędy są starsze i prostsze, a wyjątki są nowsze, nieco bardziej złożone i wydajne. Błędy działają prawidłowo, dopóki nie trzeba ich rozwikłać, co jest równoznaczne z przekazaniem trudnego problemu przełożonemu.

Błędy mogą być liczbami, takimi jak numery błędów, a czasami z jednym lub większą liczbą skojarzonych ciągów. Na przykład, jeśli wystąpi błąd odczytu pliku, możesz być w stanie zgłosić, co to jest i prawdopodobnie nie powiedzie się. (Hay, to krok naprzód od zwykłego upadku, jak za dawnych czasów).

O wyjątkach nie mówi się często, że wyjątki to obiekty ułożone warstwowo na specjalnym stosie wyjątków. Jest jak stos zwrotny dla przepływu programu, ale przechowuje stan powrotu tylko dla prób i przechwyceń błędów. (Nazywałem je ePush i ePop, i? Przerwij był rzutem warunkowym, który będzie ePop i odzyskał do tego poziomu, podczas gdy Abort był pełną kostką lub wyjściem.)

Na dole stosu znajduje się informacja o początkowym obiekcie wywołującym, obiekcie, który wie o stanie, w którym została uruchomiona zewnętrzna próba, czyli często w momencie uruchomienia programu. Poza tym, kolejna warstwa na stosie, gdzie góra jest dziećmi, a dół to rodzice, jest obiektem wyjątku następnego wewnętrznego bloku try / catch.

Jeśli spróbujesz wewnątrz próby, umieszczasz wewnętrzną próbę na zewnętrznej próbie. Gdy wystąpi błąd w wewnętrznej try i albo wewnętrzny catch nie może go obsłużyć, albo błąd zostanie zgłoszony do zewnętrznej try, wówczas kontrola jest przekazywana do zewnętrznego bloku catch (obiekt), aby sprawdzić, czy może obsłużyć błąd, tj. twój przełożony.

Więc to, co naprawdę robi ten stos błędów, to możliwość oznaczania i przywracania przepływu programu i stanu systemu, innymi słowy, pozwala programowi nie zawiesić stosu zwrotnego i zepsuć rzeczy innym (dane), gdy coś pójdzie nie tak. W ten sposób zapisuje również stan wszystkich innych zasobów, takich jak pule alokacji pamięci, i może je wyczyścić po zakończeniu przechwytywania. Ogólnie rzecz biorąc, może to być bardzo skomplikowana sprawa i dlatego obsługa wyjątków jest często powolna. Ogólnie rzecz biorąc, do tych bloków wyjątków należy wprowadzić sporo stanu.

Tak więc blok try / catch ustawia stan, do którego można powrócić, jeśli wszystko inne zostanie pomieszane. To jest jak rodzic. Kiedy nasze życie się popsuje, możemy wrócić na kolana rodziców, a oni znowu wszystko będzie dobrze.

Mam nadzieję, że cię nie zawiodłem.


1

Możesz dodać ten komentarz

function doSomething()
{
   /** @noinspection PhpUnhandledExceptionInspection */
   throw new Exception();
}

0

Po zdefiniowaniu set_error_handler () procedura obsługi błędów jest podobna do procedury wyjątków. Zobacz kod poniżej:

 <?php
 function handleErrors( $e_code ) {
   echo "error code: " . $e_code . "<br>";
 }

 set_error_handler( "handleErrors" ); 

 trigger_error( "trigger a fatal error", E_USER_ERROR);
 echo "after error."; //it would run if set_error_handler is defined, otherwise, it wouldn't show
?>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.