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

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

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

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

Q&A

1回答

2981閲覧

phpで関数内の関数から、エラーをキャッチできませんか?

myako

総合スコア1

PHP

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

0グッド

0クリップ

投稿2020/06/10 12:00

編集2020/06/10 12:05

長くなってしまって申し訳ございませんが、PHPにお詳しい方のお目に留まりましたら幸いです。

以下3つの関数があり、➂の中で➀➁のエラー(getCodeとgetMessage)を取得することはできませんか?

###発生中の問題
➂のgetPreviousで以下メッセージがでて実行できないです。

PHP Fatal error: Uncaught Error: Call to a member function getPrevious() on null in /workspace/Main.php:13 Stack trace:

###コード

php

1<?php 2 3var_dump( myGet( 'one', ['name'=>'x'] ) ); 4 5// ➂右記を実行する「➀引数をバリデーションして、➁SQLから値を取得する」 6function myGet( $process, $args ){ 7 $result = null; 8 try { 9 $e = null; 10 11 // ➀のエラーをチェック 12 $name = myValid( $process, $args['name'] ); 13 $prev = $e->getPrevious(); 14 if ( $prev ) $e = e('myValid()でエラー', 0, $e); 15 16 // ➁のエラーをチェック 17 $row = myRow( $name ); 18 $prev = $e->myRow(); 19 if ( $prev ) $e = e('myRow()でエラー', 0, $e); 20 21 if ( $e ) { 22 throw $e; 23 }else{ 24 $result = $row; 25 } 26 } catch (Exception $e) { 27 $result = exception_to_array( __FUNCTION__, $e ); 28 } 29 30 return $result; 31} 32 33// ➀SQLから値を取得 34function myRow( $name ){ 35 $result = null; 36 try { 37 $e = null; 38 39 // 本来のコード 40 // $row = $dbh->query( "SELECT * FROM t_user WHERE naem=$name" ); 41 // 本来のコードによって以下$rowが取得されたと仮定 42 $row = ['ID'=>1, 'name'=>$name, 'age'=>20]; 43 $result = $row; 44 45 // この関数でエラーチェック 46 if ( empty($row) ) $e = e('レコードがない', 4, $e); 47 48 if ($e) { 49 throw $e; 50 } 51 } catch (Exception $e) { 52 $result = exception_to_array( __FUNCTION__, $e ); 53 } 54 55 return $result; 56} 57 58// ➁引数をバリデーション 59function myValid( $process, $name ){ 60 $result = null; 61 62 $ok = [ 63 'one'=>['a','b'], 64 'two'=>['x','y','z'] 65 ]; 66 67 try { 68 $e = null; 69 70 // この関数でエラーチェック 71 if ( ! isset($process) ) $e = e('processが空', 1, $e); 72 if ( ! isset($name) ) $e = e('nameが空', 2, $e); 73 if ( !$e ) { 74 if ( ! in_array( $name, $ok[$process], true ) ) { 75 $e = e('$nameが不正', 3, $e); 76 }else{ 77 $result = $name; 78 } 79 } 80 81 if ($e) { 82 throw $e; 83 } 84 } catch (Exception $e) { 85 $result = exception_to_array( __FUNCTION__, $e ); 86 } 87 88 return $result; 89} 90 91// エラーチェック用 92function e( $message, $code, $previous = null) { 93 return new Exception($message, $code, $previous); 94} 95function exception_to_array($func_name, Exception $e) { 96 do { 97 $errors[$func_name][$e->getCode()] = $e->getMessage(); 98 } while ($e = $e->getPrevious()); 99 return array_reverse($errors); 100}

###試したこと
上記全ての関数で、戻り値の$result$result['result']として、➂の中では$result['result'] === 'errror'というチェックをしましたが、これでも➀と➁の何が悪いか?(getCodeとgetMessage)を取得することができませんでした。

// ※変更1から// 変更8が上記との変更箇所です。

php

1<?php 2 3var_dump( myGet( 'one', ['name'=>'x'] ) ); 4 5// ➂右記を実行する「➀引数をバリデーションして、➁SQLから値を取得する」 6function myGet( $process, $args ){ 7 $result = ['result'=>null]; // ※変更1 8 try { 9 $e = null; 10 11 // バリデーション 12 $name = myValid( $process, $args['name'] ); 13 if( $name['result'] === 'error' ){ // ※変更2 14 $e = e('myValid()でエラー', 0, $e); 15 } 16 17 // SQLでレコードを取得 18 $row = myRow( $name['result'] ); 19 if( $row['result'] === 'error' ){ // ※変更3 20 $e = e('myRow()でエラー', 0, $e); 21 } 22 23 if ( $e ) { 24 throw $e; 25 }else{ 26 $result = $row; 27 } 28 } catch (Exception $e) { 29 $result = exception_to_array( __FUNCTION__, $e ); 30 } 31 32 return $result; 33} 34 35// ➁SQLから値を取得 36function myRow( $name ){ 37 $result = ['result'=>null]; // ※変更4 38 try { 39 $e = null; 40 41 // 本来のコード 42 // $row = $dbh->query( "SELECT * FROM t_user WHERE naem=$name" ); 43 // 本来のコードによって以下$rowが取得されたと仮定 44 $row = ['ID'=>1, 'name'=>$name, 'age'=>20]; 45 $result['result'] = $row; // ※変更5 46 47 // この関数でエラーチェック 48 if ( empty($row) ) $e = e('レコードがない', 4, $e); 49 50 if ($e) { 51 throw $e; 52 } 53 } catch (Exception $e) { 54 $result = exception_to_array( __FUNCTION__, $e ); 55 } 56 57 return $result; 58} 59 60// ➁引数をバリデーション 61function myValid( $process, $name ){ 62 $result = ['result'=>null]; // ※変更6 63 64 $ok = [ 65 'one'=>['a','b'], 66 'two'=>['x','y','z'] 67 ]; 68 69 try { 70 $e = null; 71 72 // この関数でエラーチェック 73 if ( ! isset($process) ) $e = e('processが空', 1, $e); 74 if ( ! isset($name) ) $e = e('nameが空', 2, $e); 75 if ( !$e ) { 76 if ( ! in_array( $name, $ok[$process], true ) ) { 77 $e = e('$nameが不正', 3, $e); 78 }else{ 79 $result['result'] = $name; // ※変更7 80 } 81 } 82 83 if ($e) { 84 throw $e; 85 } 86 } catch (Exception $e) { 87 $result = exception_to_array( __FUNCTION__, $e ); 88 } 89 90 return $result; 91} 92 93// エラーチェック用 94function e( $message, $code, $previous = null) { 95 return new Exception($message, $code, $previous); 96} 97function exception_to_array($func_name, Exception $e) { 98 do { 99 $errors['result'] = 'error'; // ※変更8 100 $errors[$func_name][$e->getCode()] = $e->getMessage(); 101 } while ($e = $e->getPrevious()); 102 return array_reverse($errors); 103} 104

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2020/06/10 12:32

「エラーをキャッチ」したいのですか?例外ではなくて?
myako

2020/06/10 12:38

すみませんエラーと例外を混同していました。「例外をキャッチ」したいです。
guest

回答1

0

前置き

PHP Fatal error: Uncaught Errorを正確にハンドリングするのは結構大変ですし、そもそも発生した時点でどうにもリカバリーできない状態になるので、エラー内容を把握して修正することをお勧めします。
参考お前は PHP 7 における Fatal Error / Catchable Fatal Error / Error / ErrorException / Exception の違いを言えるか?

回答

今回のケースだと例外をスタックに積むためにthrowせずに戻り値として返しているのに、
その戻り値を使用していないことが問題です。
throwと戻り値の違いについて把握する必要があります。

Call to a member function getPrevious() on nullなので、

PHP

1 //ここで$eがnullになってるので 2 $e = null; 3 4 // ➀のエラーをチェック 5 $name = myValid( $process, $args['name'] ); 6 //null->getPrevious() をしていることになる 7 //throwしているわけでは無いので、myValidの中でエラーがあっても$nameに格納される 8 $prev = $e->getPrevious();

今の構造のままだと、こういう感じにしないといけないでしょうね。

PHP

1 //ここで$eがnullになってるので 2 $e = null; 3 4 // ➀のエラーをチェック 5 $name = myValid( $process, $args['name'] ); 6 //null->getPrevious() をしていることになる 7 if(isset($name['error']) === true){ 8 $prev = $name->getPrevious(); 9 if ( $prev ) $e = e('myValid()でエラー', 0, $prev); 10 }

ただ、私には最終的にどうしたいのかがよくわかりません。
myValid()で例外が発生している=myRow()に進んではいけないはずなので、その場でthrowし直すなりして処理を止めないといけないのでは?


おそらく、
[PHP] まとめて例外をスローする小技
を参考にされたのかなと思いますが、まずは前述のthrowと戻り値の違いについて把握されること、参考URL中の前提となっている

というように Exception を使った処理を諦めている人が多いのではないだろうか?

という処理で実装出来るようにすること、
処理をどこで止めなければならないかを整理すること
スタックしない単一の例外で例外処理を実装してみること
をお勧めします。

投稿2020/06/10 12:53

編集2020/06/10 13:34
tanat

総合スコア18727

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問