mirror of
https://github.com/php/doc-ja.git
synced 2026-03-23 22:52:11 +01:00
* 表記揺れ修正: OOP の文脈で 上書き → オーバーライド に統一 Closes #26 * magic.xml, property-hooks.xml: 上書き に戻す(OOP継承以外の文脈) --------- Co-authored-by: KentarouTakeda <4785040+KentarouTakeda@users.noreply.github.com>
627 lines
19 KiB
XML
627 lines
19 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<!-- EN-Revision: c81a48e58fc530a74827316027fae74668d17a1d Maintainer: hirokawa Status: ready -->
|
|
<!-- CREDITS: takagi,mumumu -->
|
|
|
|
<chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook">
|
|
<title>例外(exceptions)</title>
|
|
<para>
|
|
PHP は、他のプログラミング言語に似た例外モデルを持っています。
|
|
PHP 内で例外がスローされ (&throw; され)、それが
|
|
捕捉され (&catch; され) ます。発生した例外を
|
|
捕捉するには、コードを &try; ブロックで囲みます。
|
|
各 &try; ブロックには、対応する &catch;
|
|
ブロックあるいは &finally; ブロックが存在する必要があります。
|
|
</para>
|
|
<para>
|
|
例外がスローされ、現在の関数スコープに &catch; ブロックがなかった場合、
|
|
その例外は、マッチする &catch;
|
|
ブロックが見つかるまで関数のコールスタックを "遡って" いきます。
|
|
その途中で見つかった全ての &finally; ブロックが実行されます。
|
|
グローバルスコープに遡るまで全てのコールスタックを探しても、
|
|
マッチする &catch; ブロックが見つからない場合は、
|
|
グローバルな例外ハンドラが設定されていない限り fatal error となり、
|
|
プログラムが終了します。
|
|
</para>
|
|
<para>
|
|
スローされるオブジェクトは、
|
|
<interfacename>Throwable</interfacename> のインスタンスでなければなりません。
|
|
それ以外のオブジェクトをスローしようとすると
|
|
PHP の fatal error が発生します。
|
|
</para>
|
|
<para>
|
|
PHP 8.0.0 以降では、&throw; キーワードは式として扱えるようになり、
|
|
様々なコンテクストで使えるようになりました。
|
|
これより前のバージョンでは、&throw; は文であり、
|
|
それが現れる行でだけでしか使えませんでした。
|
|
</para>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.catch">
|
|
<title><literal>catch</literal></title>
|
|
<para>
|
|
&catch; ブロックは、スローされた例外にどのように反応するかを定義します。
|
|
&catch; ブロックは、扱えるひとつ以上の例外またはエラー型を定義します。
|
|
そして、オプションで例外を代入できる変数も定義できます。
|
|
(PHP 8.0.0 より前のバージョンでは、この変数定義は必須でした)
|
|
スローされた例外またはエラーにマッチする最初の &catch;
|
|
ブロックが、そのオブジェクトを処理します。
|
|
</para>
|
|
<para>
|
|
さまざまな型の例外を捕捉するために
|
|
複数の &catch; ブロックを使用することができます。
|
|
通常の実行時 (&try; ブロック内で例外がスローされなかった
|
|
場合) は、&catch;
|
|
ブロック内は処理されず、それ以降から処理が続けられます。
|
|
&catch; ブロックの中から例外を &throw; する
|
|
(あるいは &throw; しなおす) こともできます。
|
|
&throw; し直さない場合、その &catch; ブロックの後から処理が続けられます。
|
|
</para>
|
|
<para>
|
|
例外がスローされた場合、その命令に続くコードは実行されず、
|
|
PHP は最初にマッチする &catch; ブロックを探します。
|
|
例外が捕捉されない場合、PHP は "<literal>Uncaught Exception ...</literal>"
|
|
というメッセージとともに
|
|
致命的なエラー(fatal error)を発生させます。
|
|
ただし、<function>set_exception_handler</function> でハンドラが
|
|
定義されている場合を除きます。
|
|
</para>
|
|
<para>
|
|
PHP 7.1.0 以降では、&catch; ブロック で 複数の例外を
|
|
パイプ文字 (<literal>|</literal>) を使って指定できるようになりました。
|
|
これは、異なるクラス階層からの例外を同時に扱う必要がある場合に有用です。
|
|
</para>
|
|
<para>
|
|
PHP 8.0.0 以降では、キャッチされた例外に対応する変数はオプションになりました。
|
|
指定されない場合、&catch; ブロックは実行されるものの、
|
|
スローされたオブジェクトへアクセスすることは出来ません。
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.finally">
|
|
<title><literal>finally</literal></title>
|
|
<para>
|
|
&catch; ブロックの後、または &catch; ブロックの代わりに、
|
|
&finally; ブロックも指定できます。
|
|
&finally; ブロックの中に書いたコードは、
|
|
&try; および &catch; ブロックの後で、
|
|
かつ通常のコードの実行が再開される前に常に実行されます。
|
|
例外がスローされたかどうかは関係ありません。
|
|
</para>
|
|
<para>
|
|
&finally; ブロックと &return; 文の間には注意すべき相互作用があります。
|
|
&return; 文が &try; や &catch; ブロックの内部に存在した場合でも、
|
|
&finally; ブロックは実行されます。
|
|
さらに、&return; 文は出現した時に評価されますが、
|
|
結果は &finally; ブロックが実行された後に返されます。
|
|
さらに、&finally; ブロックにも &return; 文が存在した場合は、
|
|
&finally; ブロックから値が返されます。
|
|
</para>
|
|
<para>
|
|
&try; ブロック内でスローされた例外と、
|
|
&finally; ブロック内でスローされた例外には、
|
|
もう一つ注意すべき相互作用があります。
|
|
これら両方のブロックから例外がスローされると、
|
|
&finally; ブロックからスローされた例外は伝播しますが、
|
|
&try; ブロック内でスローされた例外は前の例外として使われます。
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.exception-handler">
|
|
<title>グローバルな例外ハンドラ</title>
|
|
<para>
|
|
例外がグローバルスコープにまで遡った場合、
|
|
設定されていれば、グローバルな例外ハンドラがそれをキャッチすることができます。
|
|
他の &catch; ブロックが呼び出されなかった場合に、
|
|
&catch; の代わりに呼び出される関数を
|
|
<function>set_exception_handler</function> 関数で設定できます。
|
|
その効果は、プログラム全体を &try;-&catch; ブロックで囲むことと同じです。
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.notes">
|
|
&reftitle.notes;
|
|
|
|
<note>
|
|
<para>
|
|
PHP の内部関数の多くは
|
|
<link linkend="ini.error-reporting">エラー報告(error_reporting)</link>
|
|
を使っており、例外を使っているのは新しい
|
|
<link linkend="language.oop5">オブジェクト指向</link>
|
|
の拡張モジュールのみです。
|
|
しかし、<link linkend="class.errorexception">ErrorException</link>
|
|
を使えば簡単にエラーを例外に変換することができます。
|
|
この変換テクニックが使えるのは、致命的でないエラーに限ります。
|
|
</para>
|
|
<example>
|
|
<title>エラーを例外に変換する</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">Standard PHP Library (SPL)</link>
|
|
には <link linkend="spl.exceptions">組み込みの例外</link> が数多く用意されています。
|
|
</para>
|
|
</tip>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.examples">
|
|
&reftitle.examples;
|
|
|
|
<example>
|
|
<title>例外をスローする</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
function inverse($x) {
|
|
if (!$x) {
|
|
throw new Exception('ゼロによる除算。');
|
|
}
|
|
return 1/$x;
|
|
}
|
|
|
|
try {
|
|
echo inverse(5) . "\n";
|
|
echo inverse(0) . "\n";
|
|
} catch (Exception $e) {
|
|
echo '捕捉した例外: ', $e->getMessage(), "\n";
|
|
}
|
|
|
|
// 実行は継続される
|
|
echo "Hello World\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
0.2
|
|
捕捉した例外: ゼロによる除算。
|
|
Hello World
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>例外処理での &finally; ブロック</title>
|
|
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
function inverse($x) {
|
|
if (!$x) {
|
|
throw new Exception('ゼロによる除算。');
|
|
}
|
|
return 1/$x;
|
|
}
|
|
|
|
try {
|
|
echo inverse(5) . "\n";
|
|
} catch (Exception $e) {
|
|
echo '捕捉した例外: ', $e->getMessage(), "\n";
|
|
} finally {
|
|
echo "First finally.\n";
|
|
}
|
|
|
|
try {
|
|
echo inverse(0) . "\n";
|
|
} catch (Exception $e) {
|
|
echo '捕捉した例外: ', $e->getMessage(), "\n";
|
|
} finally {
|
|
echo "Second finally.\n";
|
|
}
|
|
|
|
// 実行は継続される
|
|
echo "Hello World\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
0.2
|
|
First finally.
|
|
捕捉した例外: ゼロによる除算。
|
|
Second finally.
|
|
Hello World
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>&finally; ブロックと &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>ネストした例外</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class MyException extends Exception { }
|
|
|
|
class Test {
|
|
public function testing() {
|
|
try {
|
|
try {
|
|
throw new MyException('foo!');
|
|
} catch (MyException $e) {
|
|
// 改めてスロー
|
|
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>複数の例外ハンドリングをひとつの catch で行う</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class MyException extends Exception { }
|
|
|
|
class MyOtherException extends Exception { }
|
|
|
|
class Test {
|
|
public function testing() {
|
|
try {
|
|
throw new MyException();
|
|
} catch (MyException | MyOtherException $e) {
|
|
var_dump(get_class($e));
|
|
}
|
|
}
|
|
}
|
|
|
|
$foo = new Test;
|
|
$foo->testing();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
string(11) "MyException"
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>キャッチする時に変数を省略する</title>
|
|
<para>PHP 8.0.0 以降でのみ許されます</para>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
function test() {
|
|
throw new SpecificException('Oopsie');
|
|
}
|
|
|
|
try {
|
|
test();
|
|
} catch (SpecificException) {
|
|
print "A SpecificException was thrown, but we don't care about the details.";
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
A SpecificException was thrown, but we don't care about the details.
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>throw を 式として扱う</title>
|
|
<para>PHP 8.0.0 以降でのみ許されます</para>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class SpecificException extends Exception {}
|
|
|
|
function test() {
|
|
do_something_risky() or throw new Exception('It did not work');
|
|
}
|
|
|
|
function do_something_risky() {
|
|
return false; // Simulate failure
|
|
}
|
|
|
|
try {
|
|
test();
|
|
} catch (Exception $e) {
|
|
print $e->getMessage();
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
It did not work
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>try と finally の内部からスローされる例外</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
try {
|
|
try {
|
|
throw new Exception(message: 'Third', previous: new Exception('Fourth'));
|
|
} finally {
|
|
throw new Exception(message: 'First', previous: new Exception('Second'));
|
|
}
|
|
} catch (Exception $e) {
|
|
var_dump(
|
|
$e->getMessage(),
|
|
$e->getPrevious()->getMessage(),
|
|
$e->getPrevious()->getPrevious()->getMessage(),
|
|
$e->getPrevious()->getPrevious()->getPrevious()->getMessage(),
|
|
);
|
|
}
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
string(5) "First"
|
|
string(6) "Second"
|
|
string(5) "Third"
|
|
string(6) "Fourth"
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.exceptions.extending">
|
|
<title>例外を拡張する</title>
|
|
<para>
|
|
組み込みの Exception クラスを拡張することで、例外クラスをユーザーが
|
|
定義することが可能です。以下のメンバーおよびプロパティは、
|
|
組み込みの Exception クラスから派生した子クラスの中でアクセス可能です。
|
|
</para>
|
|
<example>
|
|
<title>組み込みの例外クラス</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Exception implements Throwable
|
|
{
|
|
protected $message = 'Unknown exception'; // exception message
|
|
private $string; // __toString cache
|
|
protected $code = 0; // user defined exception code
|
|
protected $file; // source filename of exception
|
|
protected $line; // source line of exception
|
|
private $trace; // backtrace
|
|
private $previous; // previous exception if nested exception
|
|
|
|
public function __construct($message = '', $code = 0, ?Throwable $previous = null);
|
|
|
|
final private function __clone(); // Inhibits cloning of exceptions.
|
|
|
|
final public function getMessage(); // message of exception
|
|
final public function getCode(); // code of exception
|
|
final public function getFile(); // source filename
|
|
final public function getLine(); // source line
|
|
final public function getTrace(); // an array of the backtrace()
|
|
final public function getPrevious(); // previous exception
|
|
final public function getTraceAsString(); // formatted string of trace
|
|
|
|
// Overrideable
|
|
public function __toString(); // formatted string for display
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
クラスが、組み込みの Exception クラスを拡張し、
|
|
<link linkend="language.oop5.decon">コンストラクタ</link>を再定義した場合、
|
|
全ての利用可能なデータが正しく代入されることを保証するために
|
|
<link linkend="language.oop5.paamayim-nekudotayim">
|
|
parent::__construct()</link> もコールすることが強く推奨されます。
|
|
<link linkend="language.oop5.magic">__toString()</link> メソッドは、
|
|
オブジェクトが文字列として表された際に独自の出力を行うために
|
|
オーバーライドすることができます。
|
|
</para>
|
|
<note>
|
|
<para>
|
|
例外を複製することはできません。Exception を <link
|
|
linkend="language.oop5.cloning">clone</link> しようとすると
|
|
致命的な <constant>E_ERROR</constant> エラーが発生します。
|
|
</para>
|
|
</note>
|
|
<example>
|
|
<title>例外クラスを拡張する</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/**
|
|
* カスタム例外クラスを定義する
|
|
*/
|
|
class MyException extends Exception
|
|
{
|
|
// 例外を再定義し、メッセージをオプションではなくする
|
|
public function __construct($message, $code = 0, ?Throwable $previous = null) {
|
|
// なんらかのコード
|
|
|
|
// 全てを正しく確実に代入する
|
|
parent::__construct($message, $code, $previous);
|
|
}
|
|
|
|
// オブジェクトの文字列表現を独自に定義する
|
|
public function __toString() {
|
|
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
|
|
}
|
|
|
|
public function customFunction() {
|
|
echo "A custom function for this type of exception\n";
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 例外をテストするためのクラスを作成
|
|
*/
|
|
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:
|
|
// カスタム例外をスローする
|
|
throw new MyException('1 is an invalid parameter', 5);
|
|
break;
|
|
|
|
case self::THROW_DEFAULT:
|
|
// デフォルトの例外をスローする
|
|
throw new Exception('2 is not allowed as a parameter', 6);
|
|
break;
|
|
|
|
default:
|
|
// 例外が発生しなかった。オブジェクトが生成される
|
|
$this->var = $avalue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 例1
|
|
try {
|
|
$o = new TestException(TestException::THROW_CUSTOM);
|
|
} catch (MyException $e) { // ここでキャッチされる
|
|
echo "Caught my exception\n", $e;
|
|
$e->customFunction();
|
|
} catch (Exception $e) { // ここはスキップされる
|
|
echo "Caught Default Exception\n", $e;
|
|
}
|
|
|
|
// 実行を継続する
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
|
|
// 例2
|
|
try {
|
|
$o = new TestException(TestException::THROW_DEFAULT);
|
|
} catch (MyException $e) { // この型にはマッチしない
|
|
echo "Caught my exception\n", $e;
|
|
$e->customFunction();
|
|
} catch (Exception $e) { // ここでキャッチされる
|
|
echo "Caught Default Exception\n", $e;
|
|
}
|
|
|
|
// 実行を継続する
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
|
|
// 例3
|
|
try {
|
|
$o = new TestException(TestException::THROW_CUSTOM);
|
|
} catch (Exception $e) { // ここでキャッチされる
|
|
echo "Default Exception caught\n", $e;
|
|
}
|
|
|
|
// 実行を継続する
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
|
|
// 例4
|
|
try {
|
|
$o = new TestException();
|
|
} catch (Exception $e) { // スキップされる、例外は発生しない
|
|
echo "Default Exception caught\n", $e;
|
|
}
|
|
|
|
// 実行を継続する
|
|
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
|
|
-->
|