mirror of
https://github.com/php/doc-pl.git
synced 2026-03-25 23:52:07 +01:00
568 lines
16 KiB
XML
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
|
|
-->
|