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

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

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

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

Q&A

解決済

1回答

1425閲覧

PDOでtry_catchを利用した場合の例外のエラーメッセージを見る方法

pegy

総合スコア243

PHP

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

0グッド

0クリップ

投稿2021/06/30 01:54

編集2021/06/30 01:55

下記のようなコードで二重try-catchで例外を外側のcatchでthrowすることを想定しております。

  1. サブクラスpdo_queryにおいて、発生した例外を親クラスのcatchにthrowしたいのですが、throw $e;// 外側のTryブロックに対してスロー こちらで投げたいのですが、こちらの方法がわからずにご質問させていただきました。

2.この挙動をに確認するために、例えばmain.phpをわざと存在しないカラムから取得するような$sql = "SELECT nill_column FROM test_table";のように変えた上で、親クラスの$e->getMessage()をコメントアウトなどしてみたのですが、このコードが存在してもしなくてもブラウザ上はWarning: PDO::query(): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'aa' in 'field list' in /Applications/MAMP/htdocs/textile/dist/51_class.php on line 38と出力されます。
??$e->getMessage()がないのにエラーメッセージが出力されてしまっているので、throwではなく何に基づいて出力されているメッセージなのか、ひいては上記の#1についてもどのように挙動を確認すればいいのか混乱しております。

このブラウザに出力されるエラーメッセージは例外の$e->getMessage()によるものでなければどこから出力されているのでしょうか?また、$e->getMessage()を正しく出力させるためにはどのようにしたら良いのでしょうか?

php

1//class.php 2<?php 3class pdo_connect 4{ 5 protected $DB_NAME='test'; 6 protected $HOST='localhost:8889'; 7 protected $UTF='utf8'; 8 protected $USER='root'; 9 protected $PASS='root'; 10 11 public function pdo(){ 12 $dsn="mysql:dbname=".$this->DB_NAME.";host=".$this->HOST.";charset=".$this->UTF; 13 $user=$this->USER; 14 $pass=$this->PASS; 15 try{ 16 $pdo=new PDO($dsn,$user,$pass, 17 array( 18 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 19 PDO::ATTR_EMULATE_PREPARES => false, 20 ) 21 ); 22 }catch(Exception $e){ 23 header('Content-Type: text/plain; charset=UTF-8', true, 500); 24 exit($e->getMessage()); 25 } 26 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); 27 return $pdo; 28 } 29} 30 31class pdo_query extends pdo_connect 32{ 33 public function select(string $sql){ 34 $pdo_q=$this->pdo(); 35 $pdo_q->beginTransaction(); 36 try{ 37 $stmt=$pdo_q->query($sql);//select * from table where 38 $items=$stmt->fetchAll(PDO::FETCH_ASSOC); 39 $pdo_q->commit(); 40 return $items; 41 }catch (PDOException $e){ 42 $pdo_q->rollBack(); 43 throw $e;// 外側のTryブロックに対してスロー こちら 44 } 45 } 46} 47

main.php

1require_once("class.php"); 2 3$pdo = new pdo_query(); 4$sql = "SELECT * FROM test_table"; 5$result = $pdo->select($sql); 6predump($result);

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

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

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

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

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

guest

回答1

0

ベストアンサー

サブクラスpdo_queryにおいて、発生した例外を親クラスのcatchにthrowしたいのですが、throw $e;// 外側のTryブロックに対してスロー こちらで投げたいのですが、こちらの方法がわからずにご質問させていただきました。

恐らく、クラスとメソッド、継承関係とオブジェクトについて色々誤解していると思います。
今回のケースでは、

PHP

1$pdo = new pdo_query(); 2$sql = "SELECT * FROM test_table"; 3$result = $pdo->select($sql); 4

PHP

1try{ 2 $pdo = new pdo_query(); 3 $sql = "SELECT * FROM test_table"; 4 $result = $pdo->select($sql); 5}catch(Exceptoin $e){ 6 echo $e->getMessage(); 7} 8

という感じにして、pdo_queryのオブジェクトを使用する側で最終的なcatchをする必要があります。

Warning: PDO::query(): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'aa' in 'field list' in /Applications/MAMP/htdocs/textile/dist/51_class.php on line 38と出力されます。


$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
があるせいです。

投稿2021/06/30 02:10

編集2021/06/30 02:12
tanat

総合スコア18711

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

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

pegy

2021/06/30 03:48

コメントをいただきありがとうございます。 setAttribute()の設定については、理解できました。不勉強で申し訳ございません。 さて、try-catchなのですが、クラスではなく、実行時にcatchすべきということなのですが、どこでエラーがthrowされているのか識別されるために二重構造でtry-catchしたい場合もあると思いますが、(https://qiita.com/mpyw/items/b00b72c5c95aac573b71のトランザクション処理をご参照)これを定義したクラスではなくご指摘の方法を適用すると例外を捕捉しづらくなると考え、それぞれ接続の親クラスとqueryの子クラスでtry-catchを設定したのですが、考え方自体不適切でしょうか?
tanat

2021/06/30 03:56

親クラスと子クラス、メソッド同士の関係性、及びオブジェクトとクラスの関係に何か思い込みや思い違いがあるように思います。 DBの関係しないシンプルな親子クラスを作ってみて、挙動を把握することをおすすめします。 > どこでエラーがthrowされているのか識別されるために二重構造でtry-catchしたい場合もあると思いますが、 そうしたいのであれば、select()内ですれば良いことです。 質問のケースでは、別メソッドであるpdo_connect()をselect()の一部(もしくは逆)の様に扱えるという大きな誤解が根底にあるように見受けられます
tanat

2021/06/30 05:15 編集

あとは、例外の発生箇所を知りたいだけなら getTraceAsString() を使うのが良いです (詳細はPHPマニュアルのExceptionクラスのページを参照のこと)
pegy

2021/06/30 05:10

コメントありがとうございます。 おっしゃる通り、以下のような簡易なコードで挙動を試してみました。(クラスにする意味もなければ親子の役割にも意味がありません、単に挙動を確認するためのコードです)
pegy

2021/06/30 05:13 編集

class super_class { public $hantei = 0; public function type(string $operation){ try { // if( $operation !== "division" ){ // throw new Exception("割り算じゃないですね"); // } if ($operation == "division") { $this->hantei = 1; } } catch (\Exception $e) { return $e->getMessage(); } } } class sub_class extends super_class{ public function __construct() { $this->hantei; } public function calc(int $a,int $b){ if($this->hantei==1){ try{ if( $b == 0 ){ throw new Exception("0では割れません"); } return $a/$b; } catch (\Exception $e) { return $e->getMessage(); } }else{ return "割り算じゃないですね"; } } } $test = new sub_class(); $test ->type("division2"); var_dump($test->hantei); var_dump($test -> calc(5,2));
pegy

2021/06/30 05:16

else{ return "割り算じゃないですね"; } の部分を親クラスのExceptionオブジェクトに入れるという発想が、自体がおそらく親子クラスの考え方を間違っているということなのかと思います。 なんとなく承継するということは、あたかもサブクラスに親クラスのコードが存在しているかのように扱える(requireしているようなイメージ)と思っていたので、親のExceptionオブジェクトのプロパティにアクセスすれば良いのかな?というくらいに思っておりました。。
pegy

2021/06/30 05:20

コメント欄、コードブロックできないので、インデントもなく本当にみづらくて申し訳ないです。stack overflowのようにコメント欄もコードブロックできればいいのですが、本文に追記しても文脈を追いづらくなるので、いつも悩ましいです。。
tanat

2021/06/30 05:29

> の部分を親クラスのExceptionオブジェクトに入れるという発想が、自体がおそらく親子クラスの考え方を間違っているということなのかと思います。 うーん、何というか、親子関係もそうなのですが オブジェクト内のメソッド同士の関係についての誤解の方が大きい様に思います。 class xxxx{ public function a(){ } public function b(){ } } とした場合、a()とb()は全く別物です。 なのに親子関係にしたとたんb()がa()に含まれる様な挙動をすることはありません。 例えば、 コメントに書かれている子クラスは、親クラスを継承せずに書くと以下の様になります。 calc()がtype()の中にいきなり取り込まれるような挙動はしませんが、そのような挙動を期待されている様に見受けられます。 class sub_class { public $hantei = 0; public function type(string $operation){ try { // if( $operation !== "division" ){ // throw new Exception("割り算じゃないですね"); // } if ($operation == "division") { $this->hantei = 1; } } catch (\Exception $e) { return $e->getMessage(); } } public function __construct() { $this->hantei; } public function calc(int $a,int $b){ if($this->hantei==1){ try{ if( $b == 0 ){ throw new Exception("0では割れません"); } return $a/$b; } catch (\Exception $e) { return $e->getMessage(); } }else{ return "割り算じゃないですね"; } } }
tanat

2021/06/30 05:29

コメント欄でマークダウンを使えないのは本当に面倒臭いですよね
m.ts10806

2021/06/30 05:29

横からすみませんが、本文に状況追記で良いかと思います。解決してないのであれば「回答を受けた結果」として追記されたほうがあとから見た人にも伝わります。
pegy

2021/06/30 05:44

>m.ts10806様 ありがとうございます。コメントが複数に及んだ場合、どのコメントに対して示したコードなのかという「関係性」がトレースしづらくなるのかとも危惧していたのですが、次回より、仰っていただいた方法を試してみます。 例えば、コメントにはコードについては本文、#XXX様_001を参照などとしてとして、本文には、<コメントを受けてのコード追記>などして、関係と文脈を明確化して利用してみようと思います。
pegy

2021/06/30 05:51 編集

>tanat様 コメントありがとうございます。親子や承継に関わらず、それぞれのメソッドは基本的に個別独立した存在ということですね。そこで、例えばなのですが、aのメソッドとbのメソッドについて、なんらかの関係(例えば、一方の結果を用いてもう一方のメソッドが変化する場合、以下のような取り扱いをすることは一般的なことなのでしょうか? class xxxx{ public function a(){ } public function b(){ $ result = $this-> a(); result == 1 ?? return "string":0; } *勘弁的に記載してしまいましたが、class xxxxのインスタンス内で、function a()の結果をなんらかの形で保持していることを前提にして、他のメソッドでそれを利用しているというイメージです。
tanat

2021/06/30 06:10

> 一方の結果を用いてもう一方のメソッドが変化する場合、以下のような取り扱いをすることは一般的なことなのでしょうか? そうですね。 それは一般的な方法です。 クラスやオブジェクトの使い方について学習するのは中々難しい(適切な教材を探すのが難しい)のですが、 まずは https://www.php.net/manual/ja/language.oop5.basic.php と派生するページのサンプルを一通り読む&試してみると理解が進み、サンプルも探しやすくなると思います。
pegy

2021/06/30 17:48

返信遅くなり申し訳ございません、やっと通常の仕事から解放されました。。 ありがとうございます、未だにPHPのDocumentationはとっつきづらいのですが、踏ん張って、勉強してみます。よろしくお願い申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問