質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

5回答

6936閲覧

PHPの例外処理について

gsuisk

総合スコア72

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

1グッド

4クリップ

投稿2017/09/01 14:17

例外処理のcatch()の()の部分はどのような意味なのでしょうか?

例えば、

PHP

1try{ 2 $obj = new SplFileObject($file, "rb"); 3}catch(Exception $e){ 4 echo $e->getMessage(); 5 exit(); 6}

catch(Exception $e)の部分の「Exception」は定義済みのクラスのことですよね?

$eはExceptionクラスのインスタンス(オブジェクト)という意味でしょうか?

$e->getMessage() はインスタンスである$eのgetMessagemeメソッドを使用しているということですよね?

$e = new Exception();

catchの()はこのような意味なのでしょうか?

初歩的なことですみませんが、ご回答いただきたいです。

aaaaaaaa👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

catchブロックは、tryブロック内でException(例外)が発生した場合に、Exception の種類ごとに、それを受け取って処理を行います。

例えば

PHP

1try{ 2 3 //throw new ErrorException("error"); // 1 4 //throw new InvalidArgumentException("invalid argument"); // 2 5 //throw new Exception("general"); // 3 6 //throw new PDOException("pdo"); // 4 7 8} catch(ErrorException $e){ 9 echo $e->getMessage(); 10 exit(); 11} catch(InvalidArgumentException $e){ 12 echo $e->getMessage(); 13 exit(); 14} catch(Exception $e){ 15 echo $e->getMessage(); 16 exit(); 17}

のようなコードがあるとして、

1をコメントアウトして活かし、ErrorExceptionをthrowすると1番目のcatchブロックでそれがキャッチされ、$eとして先程 new したErrorException(例外)のインスタンスが引数として渡されます。
ですから、

PHP

1echo $e->getMessage();

の部分で、errorという文字が表示されます。

2を活かすとInvalidArgumentExceptionがthrowされるので2番目のcatchブロックでキャッチされて、invalid argument が表示されます。

3も同様で3番目のcatchブロックでキャッチされ general が表示されます。

4をコメントアウトすると new された PDOException のインスタンスが throw されますが、これ用の catch ブロックが存在しません。

ですが、PDOException は RuntimeException クラスを継承し、さらに RuntimeException クラスは Exception クラスを継承しているため、結果的に 3番目の catch ブロックでキャッチされ、やはり、pdo が表示されます。

このように、catch ブロックは try ブロック内で throw された Exception 毎にキャッチを行い、その際に new されたインスタンスを引数として取ります。

ですから、不正な実行結果の際に Exception(例外)を throw する関数等を try ブロック内に書いた場合、エラー処理が非常に簡単に行えるようになるわけです。

尚、全ての例外の基底クラス Exception クラスでは
http://php.net/manual/ja/class.exception.php

PHP

1/* プロパティ */ 2protected string $message ; 3protected int $code ; 4protected string $file ; 5protected int $line ;

となっていて、そのコンストラクタは
http://php.net/manual/ja/exception.construct.php

なため、

PHP

1$e = new SomeException("hogehage");

のように new すると、第一引数の文字列が、そのインスタンスに対する

PHP

1$e->getMessage();

という getMessage() メンバメソッドで取得できるというわけです。

投稿2017/09/01 15:28

編集2017/09/01 15:44
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/09/01 16:03

で、ずっと謎だったのが、 $obj = new SplFileObject($file, "rb"); なんですけど、PHPマニュアル見てみても、 SplFileObject のコンストラクタが Exception 投げる事は無いような… どういうことでしょ? このコード…
退会済みユーザー

退会済みユーザー

2017/09/02 00:03

ありがとうございます。僕の読み落としですね。該当箇所見つけました。
gsuisk

2017/09/02 10:52

ありがとうございます。例外クラスはExceptionだけではないのですね。 catchの引数として渡すものは「例外クラスそのもの」ではなく、「インスタンス」なのでしょうか? それとも、 tryブロックでクラスを投げて、catchブロックでクラスをキャッチしてそこでインスタンス化($e生成) 細かくてすみませんが、どちらが正しいでしょうか?
gsuisk

2017/09/02 11:02

スローされるオブジェクトは、Exception クラスあるいは Exception のサブクラスのインスタンスでなければなりません。 それ以外のオブジェクトをスローしようとすると PHP の Fatal Error が発生します。 こうあるのですが、Exception のサブクラスのインスタンスとはInvalidArgumentExceptionのような、Exception以外の定義済みクラスのことでしょうか?
退会済みユーザー

退会済みユーザー

2017/09/02 12:12 編集

> catchの引数として渡すものは「例外クラスそのもの」ではなく、「インスタンス」なのでしょうか? try{}catch(){} に限らず、如何なる場合でもクラスは投げられないですし変数を保持できません。 静的なメソッドのコールなどはできますけどね。 明示的にせよ、暗黙的にせよ、try{}ブロック内でクラスのインスタンスが生成されて、それが投げ(throw)られ、catchされます。 たとえば SplFileObject クラスのコンストラクタではTomak さんが補足してくれた通り、filename に示されたファイルがオープンできなかった場合について、PHPが内部的に RuntimeException クラスについて、発生した例外の内容などをそのメンバ変数として格納してインスタンスを生成し、投げ(throw)ます。 $obj = new SplFileObject($file, "rb"); ← ここですね。
退会済みユーザー

退会済みユーザー

2017/09/02 12:11 編集

> こうあるのですが、Exception のサブクラスのインスタンスとはInvalidArgumentExceptionのような、Exception以外の定義済みクラスのことでしょうか? 定義済みであろうがなかろうが、Exception クラスを基底として継承している派生クラス全てです。 例えば InvalidArgumentException は PHP マニュアルを見ると、 InvalidArgumentException extends LogicException{} となっていて、LogicException を継承(extends)しています。 http://php.net/manual/ja/class.invalidargumentexception.php そして LogicException は LogicException extends Exception {} とあり、Exception を継承(extends)しています。 http://php.net/manual/ja/class.logicexception.php
退会済みユーザー

退会済みユーザー

2017/09/02 12:03 編集

ですから、Exception クラスを継承してさえ居れば、あなたが独自の例外を作成し、それをあなたのアプリケーション開発に役立てる事ができます。 例えばこれは、僕が作っているアプリケーションで使っている、バリデーションエラーが発生した場合に throw するクラスです。 ValidationErrorException.php ----------------------------------------------------------------------------------------------- <?php /**  * バリデーションエラーが発生したときにthrowされるExceptioin  */ class ValidationErrorException extends Exception {   public function __construct($message, $code = 0, Exception $previous = null)   {     parent::__construct($message, $code, $previous);   } } ----------------------------------------------------------------------------------------------- このファイルを require しておけば、 throw new ValidationErrorException("名前はひらがなで記入してください"); のようにして throw し、これを catch する事で、簡単にエラーハンドリングが出来るようになるわけです。 しかしこのサイト、いい加減コメントの方でも<code/>使えるようになって欲しいですね…
gsuisk

2017/09/03 05:42

インスタンスが投げられているのですね。 luckerさんの例であげられている ValidationErrorExceptionクラスでは、なぜコンストラクタ内に親クラス(Exceptionクラス)のコンストラクタが実行されているのでしょうか? いまいち ValidationErrorExceptionクラス内での処理の意味がわかりません。 何度もすみません...ご回答いただけると幸いです。
退会済みユーザー

退会済みユーザー

2017/09/03 09:25 編集

あー、ええと、これは単純に“同じコードを何度も書かないため”というのが適切かと思うんですが、 parent はまぁ「親クラス」ということなので、この場合 Exception クラスの事を指している事はわかると思います。 だから、この ValidationErrorException クラスのコンストラクタに渡されてきた引数についての処理を全部、その親クラスである Exception のコンストラクタにかかれてあるコードに丸投げしてるんです。 そうすれば、例えば引数の $message について、ValidationErrorException クラスのコンストラクタ内に $this->message = $message; とか、いちいち書かなくていいでしょ? そもそも、そうやって各サブクラスが勝手なことすると、Exception としての整合性が取れなくなって getMessage() メンバメソッドとかが意味をなさなくなっちゃう可能性がありますし。 そういうわけで、社会における仕事と同じであり、ただの報連相であって、上司に正確に報告を行っているわけです。
退会済みユーザー

退会済みユーザー

2017/09/03 09:02

なお、このへんは “多分” なので間違ってたら申し訳ないですが、 もう一つ、下の方に別に起こした回答が Exception の __construct() のソースコードっぽいです。 コメント欄には<code/>ブロック使えないので新規に起こしました。 parent に全部投げとくと、この辺のことを全部やってくれてるはずですよ。
退会済みユーザー

退会済みユーザー

2017/09/03 09:28

なお、 parent::__construct($message, $code, $previous); は静的な関数コールですので、親クラスである Exception のインスタンスに対して関数呼び出しをしているわけではなく、インスタンスを生成せず、Exception クラスにあるコードをそのまま実行しているだけです。 で、その実行結果は ValidationErrorException クラスのインスタンスのメンバ変数として保存されています。
gsuisk

2017/09/03 11:24

親クラスのコンストラクタに任せられるものは任せるということですね。 親切に教えていただきありがとうございました!
MasahikoHirata

2017/09/04 15:42

的確な回答と思います。評価させて頂きます。
guest

0

catch(Exception $e)の部分の「Exception」は定義済みのクラスのことですよね?

$eはExceptionクラスのインスタンス(オブジェクト)という意味でしょうか?

PHP内部の定義済みのクラスのことで、定義済みの例外は他にもあります。PHP7ではError $eというのもあります。

もともと、PHPには「try~catch 例外処理」はありませんでした。

導入された際に例外の$eだけ特殊な扱いで型宣言しなくてはならない仕様で導入されました。
これがException $eです。

普通、オブジェクト指向言語では変数の型宣言をしなくてはなりません。ストリング(オブジェクト)型の変数$strの場合は、String $strという具合です。PHPは型を自動判断しましょうというコンセプトなので通常は型を書かず、例外の時だけException $eと書かなければいけません。

PHPマニュアルの型宣言について(タイプヒンティング)に型宣言できる型一覧が記載されてます。
例えばArray $arrayなどというように型を定義して変数宣言できます。こうすることで、配列以外の型を代入することはできなくなり、より厳密にプログラムを作成することができるようになります。

php

1// 型宣言(タイプヒンティング) 2function something (array $param = array()) { 3 ... 4}; 5 6something(array(1,2,3)); // OK 7something(1) // NG

$e->getMessage() はインスタンスである$eのgetMessagemeメソッドを使用しているということですよね?$e = new Exception();

正確にはtry{throw new \Exception();}catch(\Exception $e){}ですが、感覚的にはあってます。

投稿2017/09/01 15:28

編集2017/09/01 18:49
Tomak

総合スコア1652

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gsuisk

2017/09/02 10:22

ありがとうございます。 「catch()の引数である$eは、Exceptionクラスのインスタンスでなければならない。」 ということを意味するために、引数の左にクラス名を記述している(タイプヒンティング)ということですよね?
Tomak

2017/09/03 07:39

はいそうです。 Exceptionクラスがインスタンス化されるタイミングは例外が発生したタイミングでPHP内部で勝手に生成して「$e」変数の中に格納します。 例外を「手動発生させる = throw new Exception(...)」で、この他にはランタイムエラーなど自動的にPHPが発生する例外もあります。 >$eは、Exceptionクラスのインスタンスでなければならない。 これは、正確な表現ですが、正確すぎる表現でもあります。 例えば、山田太郎さんを「人間のDNAを持った山田太郎さんです」と言っているようなかんじです。間違いじゃないですが、普通は「$eはException型です」または「$eはExceptionオブジェクトです」で通じます。 つまり$eという変数にクラスは代入できないわけで、中身にオブジェクトが格納されている時点でインスタンス化は終了しているわけです。 >引数の左にクラス名を記述している(タイプヒンティング) タイプヒンティングは、名称が古い呼ばれ方のようです。 今現在は「type declaration(タイプ デクラレーション)」といいます。 意味は「type(型)declaration(宣言)= 型宣言」といいます。 -- http://php.net/manual/ja/functions.arguments.php#functions.arguments.type-declaration 余談ですがアメリカの「独立宣言」は「Declaration of Independence(デクラレーション オブ インディペンデンス)」と言われています。 ■例外処理が何で必要? 何かの処理における例外クラスを作っておけばエラー処理を共通化したり簡単に拡張できるようになります。 ※自作する例外クラスはExceptionクラスを継承していなければなりません。 例外の仕組みがない場合(昔のPHPでは)「if ... else エラー処理」のようにするしかなく、エラー機能が拡張できない、再利用が難しいなどの問題点がありました。
退会済みユーザー

退会済みユーザー

2017/09/03 09:45 編集

雑談させてもらうと、仕事で PHP に関わる場合、 > 例外の仕組みがない場合(昔のPHPでは)「if ... else エラー処理」のようにするしかなく、 > エラー機能が拡張できない、再利用が難しいなどの問題点がありました。 本当に、こういう問題を全部 if 文で解決してある産廃コードが山のように有って、見た瞬間に逃げ出したくなる事がしょっちゅうです。PHP 5.1.0 or later なんですけどね。 大体そういうのを書く人は「Exception を使うと処理が複雑になる」とか寝言を言うのですが、 Exception をまともに使えない奴を現場に入れるのだけは、本当に止めてほしいものです。『お前の下等な脳味噌の confused なんて知らねぇよ』と、思ってる事しか出来ないんですよね、社会生活においては。 まぁ、職業プログラマはもう止めたので、二度と関わる事はないと思いますけどね…
Tomak

2017/09/03 10:39

すみません、食べてたピーナッツが飛び出してしまいました(笑)
退会済みユーザー

退会済みユーザー

2017/09/03 10:41

笑い事じゃないのは Tomak さんも良くわかってらっしゃるはずです、ええ。
gsuisk

2017/09/03 11:27

通常クラスをインスタンス化するときは、インスタンスを作成して変数に代入する処理を一行でやっているが、 例外処理ではインスタンスを作成する処理とインスタンスを変数に代入する処理を2つにわけているようなイメージですね。 ありがとうございました!
guest

0

基本はマニュアル

$eはtryでスローされたインスタンスですね

PHP

1try{ 2 throw new Exception('ゼロによる除算。'); 3}catch(Exception $e){ 4 var_dump($e); 5}

投稿2017/09/01 14:34

yambejp

総合スコア114572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

https://github.com/php/php-src/blob/master/Zend/zend_exceptions.c

C

1/* {{{ proto Exception|Error::__construct(string message, int code [, Throwable previous]) 2 Exception constructor */ 3ZEND_METHOD(exception, __construct) 4{ 5 zend_string *message = NULL; 6 zend_long code = 0; 7 zval tmp, *object, *previous = NULL; 8 zend_class_entry *base_ce; 9 int argc = ZEND_NUM_ARGS(); 10 11 object = getThis(); 12 base_ce = i_get_exception_base(object); 13 14 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc, "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) { 15 zend_class_entry *ce; 16 17 if (Z_TYPE(EX(This)) == IS_OBJECT) { 18 ce = Z_OBJCE(EX(This)); 19 } else if (Z_CE(EX(This))) { 20 ce = Z_CE(EX(This)); 21 } else { 22 ce = base_ce; 23 } 24 zend_throw_error(NULL, "Wrong parameters for %s([string $message [, long $code [, Throwable $previous = NULL]]])", ZSTR_VAL(ce->name)); 25 return; 26 } 27 28 if (message) { 29 ZVAL_STR(&tmp, message); 30 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); 31 } 32 33 if (code) { 34 ZVAL_LONG(&tmp, code); 35 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); 36 } 37 38 if (previous) { 39 zend_update_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); 40 } 41} 42/* }}} */ 43

投稿2017/09/03 09:03

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

マニュアルを見ていただければ、大体はわかると思います。

PHP

1try { 2 throw new Exception("エラーがあります。"); 3} catch(Exception $e) { 4 echo $e->getMessage(); 5}

上記のように、例外に引っかかった時にcatch(Exception $e)"エラーがあります。"という引数が送られて、
$e->getMessage()で、その引数の文字列を呼び出していると考えればいいと思います。

間違っていたりしたら、申し訳ありません。

投稿2017/09/01 16:10

alone.mk2

総合スコア58

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問