1
0
mirror of https://github.com/php/doc-pl.git synced 2026-03-25 23:52:07 +01:00
Files
archived-doc-pl/language/exceptions.xml
Maciej Sobaczewski 74a9ec438b Sync with EN
2025-05-14 03:58:20 +02:00

568 lines
16 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 402a72776804fbb74ec5c4cad72d4c7b6cdd5b2d Maintainer: sobak Status: ready -->
<!-- $Revision$ -->
<chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook">
<title>Wyjątki</title>
<para>
PHP posiada model obsługi wyjątków podobny do innych języków
programowania. W PHP wyjątek może zostać rzucony (&throw;) oraz złapany (&catch;).
Kod może zostać otoczony blokiem &try; aby skorzystać z łapania
potencjalnych wyjątków. Każdy z bloków &try; musi mieć przynajmniej jeden odpowiadający
blok &catch; lub &finally;.
</para>
<para>
Jeżeli zostanie rzucony wyjątek a jego obecny zasięg nie ma bloku &catch;
to wyjątek "przejdzie" wyżej w poszukiwaniu pasującego bloku &catch;. Wszystkie napotkane po drodze
bloki &finally; zostaną wykonane. Jeżeli zakres wywołania nie zawiera pasującego
bloku &catch; aż do osiągnięcia zasięgu globalnego, program zakończy
się błędem krytycznym, chyba że została ustawiona globalna funkcja obsługi wyjątków.
</para>
<para>
Rzucany obiekt musi być typu (&instanceof;) <interfacename>Throwable</interfacename>.
Próba rzucenia obiektu, który nie jest tego typu, będzie skutkować błędem krytycznym PHP.
</para>
<para>
Począwszy od PHP 8.0.0, słowo kluczowe &throw; jest wyrażeniem i może być użyte w konteście
dowolnego wyrażenia. We wcześniejszych wersjach było deklaracją i musiało znajdować się w swojej własnej linii.
</para>
<sect1 annotations="chunk:false" xml:id="language.exceptions.catch">
<title><literal>catch</literal></title>
<para>
Blok &catch; określa w jaki sposób odpowiedzieć na rzucony wyjątek. Blok
&catch; określa jeden lub więcej typów wyjątków, które może obsłużyć i
opcjonalnie określa zmienną, do której zostanie przypisany wyjątek (zmienna
była wymagana przed PHP 8.0.0). Pierwszy blok &catch;, do którego
pasuje rzucony wyjątek, będzie odpowiedzialny za jego obsługę.
</para>
<para>
Można użyć wielu bloków &catch; aby złapać różne klasy
wyjątków. Normalne wykonywanie (gdy w bloku &try; nie jest
rzucany żaden wyjątek) będzie kontynuowane po ostatnim bloku &catch;.
W blokach &catch; można rzucać inne wyjątki (używając &throw;) lub ponownie
rzucić ten sam wyjątek po wykonaniu jakiegoś kodu. Jeżeli tak się nie stanie,
wykonywanie będzie kontynuowane po bloku &catch;, który został wywołany.
</para>
<para>
Gdy rzucany jest wyjątek, kod następujący po wyrażeniu &throw; nie będzie
wykonany, a PHP spróbuje znaleźć pierwszy pasujący blok &catch;.
Jeżeli wyjątek nie zostanie złapany, zostanie zgłoszony krytyczny błąd PHP
z komunikatem "<literal>Uncaught Exception ...</literal>", chyba że
przy pomocy <function>set_exception_handler</function> została zdefiniowana
funkcja obsługi niezłapanych wyjątków.
</para>
<para>
Począwszy od PHP 7.1.0 blok &catch; może określać wiele wyjątków
używając znaku pipe (<literal>|</literal>). Jest to przydatne, gdy
różne wyjątki, z różnych hierarchii klas, są obsługiwane w ten sam
sposób.
</para>
<para>
Od PHP 8.0.0 nazwa zmiennej dla złapanego wyjątku jest opcjonalna.
Jeżeli nie zostanie określona, to blok &catch; wciąż zostanie wykonany, ale
nie będzie miał dostępu do rzuconego obiektu.
</para>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.finally">
<title><literal>finally</literal></title>
<para>
Można też określić blok &finally; po blokach &catch; lub
zamiast nich. Kod w bloku &finally; będzie wykonany zawsze
po blokach &try; lub &catch; (niezależnie czy zostań rzucony
wyjątek), a zanim zostanie wznowione normalne wykonywanie kodu.
</para>
<para>
Występuje szczególna interakcja między blokiem &finally; i wyrażeniem &return;.
Jeżeli w bloku &try; lub &catch; zostanie napotkane wyrażenie &return;,
to blok &finally; wciąż zostanie wykonany. Ponadto wyrażenie &return; jest
ewaluowane po jego napotkaniu, ale wynik zostanie zwrócony po wykonaniu bloku
&finally;. Co więcej, jeżeli blok &finally; także zawiera wyrażenie &return;,
to zostanie zwrócona wartość z bloku &finally;.
</para>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.exception-handler">
<title>Globalna funkcja obsługi wyjątków</title>
<para>
Jeżeli wyjątek będzie podróżował do zakresu globalnego, może zostać złapany
przez globalną funkcję obsługi wyjątków, jeśli została ona ustawiona. Funkcja
<function>set_exception_handler</function> może ustawić funkcję, która będzie
wykonana zamiast bloku &catch;, jeżeli nie został wywołany żaden
inny blok. Efekt jest więc zasadniczo taki, jak gdyby cały program
został ujęty w wielki blok &try;-&catch;, a ta funkcja była blokiem &catch;.
</para>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.notes">
&reftitle.notes;
<note>
<para>
Wewnętrzne funkcje PHP używają głównie
<link linkend="ini.error-reporting">raportowania błędów</link>, tylko nowoczesne
rozszerzenia <link linkend="language.oop5">zorientowane obiektowo</link>
używają wyjątków. Jednakże błędy mogą zostać łatwo "przetłumaczone" na
wyjątki używając klasy <link linkend="class.errorexception">ErrorException</link>
Ten sposób nie działa jednak z błędami krytycznymi (PHP fatal errors).
</para>
<example>
<title>Konwersja z raportowania błędów na wyjątki</title>
<programlisting role="php">
<![CDATA[
<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');
?>
]]>
</programlisting>
</example>
</note>
<tip>
<para>
<link linkend="intro.spl">Biblioteka standardowa PHP (SPL)</link> udostępnia
sporą ilość <link linkend="spl.exceptions">wbudowanych
wyjątków</link>.
</para>
</tip>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.examples">
&reftitle.examples;
<example>
<title>Rzucanie wyjątku</title>
<programlisting role="php">
<![CDATA[
<?php
function odwroc_liczbe($x) {
if (!$x) {
throw new Exception('Dzielenie przez zero.');
}
return 1/$x;
}
try {
echo odwroc_liczbe(5) . "\n";
echo odwroc_liczbe(0) . "\n";
} catch (Exception $e) {
echo 'Złapany wyjątek: ', $e->getMessage(), "\n";
}
// Kontynuuj wykonywanie
echo "Witaj, świecie!\n";
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
0.2
Złapany wyjątek: Dzielenie przez zero.
Witaj, świecie!
]]>
</screen>
</example>
<example>
<title>Obsługa wyjątków z blokiem &finally;</title>
<programlisting role="php">
<![CDATA[
<?php
function odwroc_liczbe($x) {
if (!$x) {
throw new Exception('Dzielenie przez zero.');
}
return 1/$x;
}
try {
echo odwroc_liczbe(5) . "\n";
} catch (Exception $e) {
echo 'Złapany wyjątek: ', $e->getMessage(), "\n";
} finally {
echo "Pierwszy blok finally.\n";
}
try {
echo odwroc_liczbe(0) . "\n";
} catch (Exception $e) {
echo 'Złapany wyjątek: ', $e->getMessage(), "\n";
} finally {
echo "Drugi blok finally.\n";
}
// Kontynuuj wykonywanie
echo "Witaj, świecie!\n";
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
0.2
Pierwszy blok finally.
Złapany wyjątek: Dzielenie przez zero.
Drugi blok finally.
Witaj, świecie!
]]>
</screen>
</example>
<example>
<title>Interakcja między blokiem &finally; i &return;</title>
<programlisting role="php">
<![CDATA[
<?php
function test() {
try {
throw new Exception('foo');
} catch (Exception $e) {
return 'catch';
} finally {
return 'finally';
}
}
echo test();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
finally
]]>
</screen>
</example>
<example>
<title>Zagnieżdżony wyjątek</title>
<programlisting role="php">
<![CDATA[
<?php
class MojWyjatek extends Exception { }
class Test {
public function testing() {
try {
try {
throw new MojWyjatek('foo!');
} catch (MojWyjatek $e) {
// rzuć ponownie
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
}
}
}
$foo = new Test;
$foo->testing();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(4) "foo!"
]]>
</screen>
</example>
<example>
<title>Obsługa kilku wyjątków w catch</title>
<programlisting role="php">
<![CDATA[
<?php
class MojWyjatek extends Exception { }
class MojInnyWyjatek extends Exception { }
class Test {
public function testing() {
try {
throw new MojWyjatek();
} catch (MojWyjatek | MojInnyWyjatek $e) {
var_dump(get_class($e));
}
}
}
$foo = new Test;
$foo->testing();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(11) "MojWyjatek"
]]>
</screen>
</example>
<example>
<title>Pomijanie zmiennej w catch</title>
<para>Dozwolone tylko w PHP 8.0.0 i późniejszych.</para>
<programlisting role="php">
<![CDATA[
<?php
class KonkretnyWyjatek extends Exception {}
function test() {
throw new KonkretnyWyjatek('Ups');
}
try {
test();
} catch (KonkretnyWyjatek) {
print "Został rzucony konkretny wyjątek, ale nie interesują nas szczegóły.";
}
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Został rzucony konkretny wyjątek, ale nie interesują nas szczegóły.
]]>
</screen>
</example>
<example>
<title>Throw jako wyrażenie</title>
<para>Dozwolone tylko w PHP 8.0.0 i późniejszych.</para>
<programlisting role="php">
<![CDATA[
<?php
function test() {
zrob_cos_ryzykownego() or throw new Exception('Nie zadziałało');
}
function zrob_cos_ryzykownego() {
return false; // Zasymuluj niepowodzenie
}
try {
test();
} catch (Exception $e) {
print $e->getMessage();
}
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Nie zadziałało
]]>
</screen>
</example>
</sect1>
<sect1 xml:id="language.exceptions.extending">
<title>Rozszerzanie wyjątków</title>
<para>
Użytkownik może zdefiniować własną klasę wyjątku poprzez rozszerzenie wbudowanej
klasy Exception. Metody i właściwości poniżej pokazują, co jest dostępne
w klasie potomnej, która dziedziczy po wbudowanej klasie Exception.
</para>
<example>
<title>Wbudowana klasa Exception</title>
<programlisting role="php">
<![CDATA[
<?php
class Exception implements Throwable
{
protected $message = 'Unknown exception'; // wiadomość wyjątku
private $string; // cache metody __toString
protected $code = 0; // kod wyjątku określony przez użytkownika
protected $file; // plik, w którym wystąpił wyjątek
protected $line; // linia, w której wystąpił wyjątek
private $trace; // backtrace
private $previous; // poprzedni wyjątek, jeżeli zostały one zagnieżdżone
public function __construct($message = '', $code = 0, ?Throwable $previous = null);
final private function __clone(); // uniemożliwia klonowanie wyjątków
final public function getMessage(); // wiadomość wyjątku
final public function getCode(); // kod wyjątku
final public function getFile(); // plik, w którym wystąpił wyjątek
final public function getLine(); // linia, w której wystąpił wyjątek
final public function getTrace(); // backtrace jako tablica
final public function getPrevious(); // poprzedni wyjątek
final public function getTraceAsString(); // ślad sformatowany jako ciąg znaków
// Nadpisywalne
public function __toString(); // sformatowany ciąg znaków do wyświetlenia
}
?>
]]>
</programlisting>
</example>
<para>
Jeżeli rozszerzana jest wbudowana klasa Exception i nadpisywany jest <link
linkend="language.oop5.decon">konstruktor</link>, to zdecydowanie zaleca się,
aby wywoływał on również <link
linkend="language.oop5.paamayim-nekudotayim">parent::__construct()</link>,
aby mieć pewność, że wszystkie dostępne dane zostały prawidłowo przypisane. Metoda <link
linkend="language.oop5.magic">__toString()</link> może zostać nadpisana, aby
określić własny format wyjścia, gdy obiekt jest prezentowany jako string.
</para>
<note>
<para>
Wyjątki nie mogą być klonowane. Próba <link
linkend="language.oop5.cloning">sklonowania</link> klasy Exception skończy się
błędem krytycznym <constant>E_ERROR</constant>.
</para>
</note>
<example>
<title>Rozszerzanie klasy Exception</title>
<programlisting role="php">
<![CDATA[
<?php
/**
* Definiujemy własną klasę wyjątku
*/
class MojWyjatek extends Exception
{
// Zredefiniuj konstruktor tak, aby wiadomość wyjątku była obowiązkowa
public function __construct($message, $code = 0, ?Throwable $previous = null) {
// jakiś kod
// upewnij się, że wszystko jest przypisane poprawnie
parent::__construct($message, $code, $previous);
}
// własna reprezentacja tekstowa obiektu
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "Własna funkcja dla tego typu wyjątku\n";
}
}
/**
* Tworzymy klasę, aby przetestować wyjątek
*/
class TestException
{
public $var;
const THROW_NONE = 0;
const THROW_CUSTOM = 1;
const THROW_DEFAULT = 2;
function __construct($avalue = self::THROW_NONE) {
switch ($avalue) {
case self::THROW_CUSTOM:
// rzuć własny wyjątek
throw new MojWyjatek('1 nie jest poprawnym parametrem', 5);
break;
case self::THROW_DEFAULT:
// rzuć domyślny wyjątek
throw new Exception('2 nie jest dozwolone jako parametr', 6);
break;
default:
// brak wyjątku, zostanie stworzony obiekt
$this->var = $avalue;
break;
}
}
}
// Przykład 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (MojWyjatek $e) { // Będzie złapany
echo "Złapałem nasz wyjątek\n", $e;
$e->customFunction();
} catch (Exception $e) { // Pominięto
echo "Złapałem domyślny wyjątek\n", $e;
}
// Kontynuuj wykonywanie
var_dump($o); // Null
echo "\n\n";
// Przykład 2
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (MojWyjatek $e) { // Typ się nie zgadza
echo "Złapałem nasz wyjątek\n", $e;
$e->customFunction();
} catch (Exception $e) { // Będzie złapany
echo "Złapałem domyślny wyjątek\n", $e;
}
// Kontynuuj wykonywanie
var_dump($o); // Null
echo "\n\n";
// Przykład 3
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (Exception $e) { // Będzie złapany
echo "Złapałem domyślny wyjątek\n", $e;
}
// Kontynuuj wykonywanie
var_dump($o); // Null
echo "\n\n";
// Przykład 4
try {
$o = new TestException();
} catch (Exception $e) { // Pomięto, brak wyjątku
echo "Złapałem domyślny wyjątek\n", $e;
}
// Kontynuuj wykonywanie
var_dump($o); // TestException
echo "\n\n";
?>
]]>
</programlisting>
</example>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->