PHPで新しく知ったこと - try/catch、threw句、ルーティングなど

Hugoサイトのカスタマイズと同時進行でphpの勉強をしたいと思っています。

いよいよ手元にあるLaravelの本でサイトを作ろう(原点回帰)!としたところ、
それよりは基礎です!というお話を頂きました。

ごもっともです。

基本的な知識や一般的な関数・処理を知らなくては実際Laravelサイトを作っても身にならないので、ここは時間がかかっても基礎力を付けることを重視していきます。

ひとまず新しく知ったphpのことについてメモしていきます。

try/catch句とthrew句、Exceptionクラス

PHPで例外処理を使う方法【初心者向け】 | TechAcademyマガジン

PHP: Exception - Manual

こちらの記事のコードを参考にさせていただきました。

(PHP) try-catch文の使い方を解説 | hara-chan.com

function addNum($a,$b){
  try {
    // 処理
    // 例外が起こったとき、例外を投げる
    if ( is_numeric($a) == false) {
        throw new Exception('引数1が数字ではありません');
    }
    if ( is_numeric($b) == false) {
        throw new Exception ('引数2が数字ではありません');
    }
    return $a + $b;      
  } catch (Exception $e) {
    // 例外処理
    var_dump($e -> getMessage());    // 「引数1(または2)が数字ではありません」と出る
    return;
  }
}

意味は直訳で「try = 試みる」、「Exception = 例外」、「throw = 投げる」、「catch = 捕まえる」です。
投げて捕まえる、と言う表現はどこから来たのですかね。

それはさておき、
catchは例外が起こらないと処理されないことがわかりました。

catch句の最後に return があります。
改めてreturnを調べると、

関数を途中で終了する場合は、返り値を指定せずに任意の場所でreturnのみを記述することで制御が呼び出し元に戻ります。

という意味にあたるので、今回の場合は必ずしも必要ないように思います。

throw new Exception ()インスタンス化したものを投げて、catch (Exception $e) で引数としてインスタンス化したものを捕えて変数($e)に代入しています。 オブジェクト(インスタンス)名は任意ですがExceptionの「e」や「ex」がよく使われているのだと思います。

$e -> getMessage() でthrow句で投げたメッセージが取得できます。

試しに addNum() の引数に両方数字を入れた場合と、片方、両方に文字を入れた場合(例外)を入れてみました。

var_dump(addNum(1, 2));

var_dump(addNum('いち', 2));

var_dump(addNum('いち', 'に'));

両方数字の場合は「3」と出ます。

引数1つ目($a)に文字が入っている場合は「"引数1が数字ではありません"NULL」と出ます。
これは $a を検証して出た例外のメッセージと return $a + $b処理されないという意味を表しているNULLです。
この場合 '$b' を検証せずに例外が投げられています。

また、getMessage()メソッド以外にも getCode() など、クラスに応じてメソッドは色々あるみたいです。

そしてExceptionクラス以外にもInvalidArgumentException クラスなど、例外クラスは色々あるみたいです。

finally句もあります

例外が発生してもしなくても、try の下に finally のブロックを書くと、中が処理されます。

PHPでfinallyを扱う方法【初心者向け】 | TechAcademyマガジン

try,、throw、catchと併せて覚えておいたほうが良さそうです。

phpではthrow句は必要?

throw が書かれていないものを見かけたので、書かない場合はどうなるのか確かめました。

うまくロジックが書けているか疑問ですが、具体的には上のコードでtryブロックの中のif文処理を行わず、throw句を入れませんでした。
$e -> getMessage() はメッセージを設定していないのでその下に var_dump('例外です') と加えてみました。

先ほどの3パターンの addNum() を確かめた結果、順に3、2、0と出ました。

例外にならず $a + $b の処理が行われ、catchで捕まえていませんでした。

調べたところ、

【PHP入門⑫】例外処理 ~初心者でも安心!基礎から学べるプログラミング講座~ | Snome;

PHPの場合は、throwしないとcatchしてくれません。 Javaの様に勝手にthrowしてくれることは無いので、例外処理を書く場合は、ちゃんとthrowしているか確認してください。

なんと。間違っていたコードだったのでしょうか。

改めて調べました。

【PHP超入門】クラス~例外処理~PDOの基礎 - Qiita
PHPの定義済みの関数やクラスは例外を投げてくれるのか)
☆前述したExceptionクラスの種類について、catch (Exception $e) の意味についてもこちらの記事に書かれています。

定義済みの関数の多くは、エラー報告だけで例外は投げてくれないけど、エラーを例外に変換することもできるよって書いてあります。 新しい定義済みのクラスの一部は、例外を投げてくれるとも書いてあります。

throw と書かなくても例外を投げてくれる関数があるのですね。
例外を投げない関数は throw が必要なのでしょうか(これが“エラーを例外に変換”?)。

あとはtry/catch句を使う理由は、エラーで表示される内容(パスワードなど)が表に出てしまわないようにcatchする、とありました。
エラーはログに出す処理もcatch句の中に書いたりするのですね。

例外処理。読めるけど書けない類のコードだなという印象ですが、大事な部分では入れなくてはいけない処理ですね。

call_user_func_array()

コールバック関数に配列の引数を渡す場合に使う関数です。

コールバック関数とは引数の関数のことでした。

call_user_func_array(array($instance, $method), $params);
// call_user_func_array ( コールバック関数名, パラメータの配列 );

第一、第二引数ともに配列です。クラスのメソッドを指定して、そこに配列でメソッドの引数を渡して実行します。

ここでは 'array($instance, $method)' の部分をコールバック関数としています。

「【PHP】コールバック関数の使い方・サンプル(レポート出力するデータを後から差し替える)」
https://notepad-blog.com/content/95/

まだまだ根強いコールバック関数への苦手意識。早くなくしたいです。

ルーティング

ルーティングの概念を理解する【Webフレームワークの基礎知識】 | Web白熱教室

ルーティングはクライアントのリクエストとサーバーの処理をひもづける作業

phpフレームワークに限ったことではない用語でした。

既存のフレームワークで作られたサイトで新しくページを追加したときにうまく行かず(404になってしまった)、原因はルーティングが設定されていないからでした。

ルーティングではリクエストURLによってこのControllerを使う、など設定されているのですが、書き方はサイトの構造によって様々みたいです。

WordPressの場合は内部で行われているんですかね。パーマリンクの処理周りでしょうか。

そのルーティングに一役買っているのがフロントコントローラーでした!

フロントコントローラー

PHP フレームワークを理解する為のフロントコントローラとページコントローラ | h19e

フロントコントローラは、URLに関係なくすべて同一のファイルにアクセスされます。

同一のファイルにアクセスをまとめることで管理しやすいということでしょうか(未確認)。

フロントコントローラーの「コントローラー」は、MCVのコントローラー(Controller)とは別の意味で使われているそうです。

フロントコントローラー(一番上のindex.php)に転送するために.htaccessが働いているというのは盲点でした。
(普通に考えても、実体のファイルがないはずのurlでアクセスできるのは不思議なのに)

アクセスしているURLはそのままで、リダイレクトではなく転送(書き換え)しています。

例:https://example.com/hoge にアクセス
.htaccess

RewriteRule (.*)$ /index.php?r=$1

https://example.com/index.php?r=hoge に書き換え
→ GETパラメータ(r=1)によって使うクラスやControllerを決める。

というようにURLによってページ表示されています。

.htaccess mod_rewriteによる正規表現を使ったリダイレクト設定

正規表現...勉強しなくては。

GETパラメータがなくてはならないですね!

さいごに

後ろの方はボリュームが小さくなってしまいました。
大事な部分だと思うので、また復習して追記したいです。

phpの基礎力を付けるために、おなじみのTODOリストを作ってみようと思っています。
TODOリストはソースコードも用意してくださっているサイトを見ながら作るのもありですが、 今ある知識でイチからやってみるのもありかなと思っています。(あまりできる気がしない)

そういえば以前メール送信してみて深堀りするはずが頓挫しています(記事が下書きで終わっていました)。

完成まで持っていきたいです!