PHP – 雛形 – 複数の例外のチェーン

概要

複数のエラーを補足していって、まとめて表示するなどの処理をしたい場合がある。たとえばユーザーIDとパスワードの妥当性をチェックし、それぞれのエラーを全て表示したいような場合。

このようなケースで例外を使うと、例外が発生した場合や意図的にスローした場合、その時点で例外処理に移行するので、複数のエラーを扱い難い。

Exception::getPrevious()

Exceptionクラスのコンストラクターは、3つの引数をとることができる。

public __construct (string $message = "", int $code = 0, Throwable $previous = null )

3つ目の引数はThrowableで、この引数にExceptionオブジェクトを指定すると、新たに生成されたオブジェクトの前に発生したExceptionオブジェクトがスタックに保持される。

$new_ex = new Exception('this exception', 0, $previous_ex)

最終的に得られたExceptionオブジェクトのスタック上にそれ以前のExceptionオブジェクトがある場合、getPrevious()メソッドで直前のオブジェクトが得られる。直前のExceptionオブジェクトがない場合はgetPrevious()の戻り値はnullとなる。

基本形

これらのことを利用して、複数の例外を途中で抜け出さずに蓄積する方法は以下のようになる。

  • 2行目の初期化は、1番目・・・n番目のどこが最初の例外をスローするかが確定していないため必須。
  • 17~19行目、適切な位置で例外をスローしないと反映されないが、例外が発生していない場合はスローしない

実行例

以下は実行例。1つ目と3つ目の条件式がfalseなので例外が積み重ねられ、2つ目はtrueなのでそのまま表示、そのあとに積まれた例外が表示される。

関数化・配列への格納

Exceptionオブジェクトの積み込みと、例外発生時のみの例外スロー、スタックされた例外に対する操作を関数化しておくと、再利用しやすく可読性も上がる。

18行目で配列の順序を反転し、スタックに積まれた順番(LIFO)からFIFOのリスト順にしている。

これらの関数を使って先と同じ処理をするコード

関数での例外発生のトレース

最初の関数で発生した例外への過程をスタックに残すには、以下のように関数内で前の例外を登録してスローする。

 

 

 

PHP – 雛形 – セッション

概要

セッション開始時

  • セッション開始時、サーバー側でセッションIDを生成する
  • サーバーはセッションIDをサーバー内に保存し、それをクライアントにCookieで保存する
  • クライアントはセッションIDをサーバーに送り、継続中のセッションでの接続を要求する
  • サーバーは送られてきたセッションIDのセッションが生きていればそのセッションで接続を続ける

セッション処理中

  • サーバーはセッション変数を通して必要な情報を得たりセットしたりする
  • セッション継続中、セッション変数の内容は保持される

セッション終了時

  • セッション変数をクリアする
  • クライアント側のセッションクッキーを完全に削除する
  • session_destroy()を実行する

処理の流れ

継続中セッションの確認

セッション中かどうか確認する必要がある場合、以下で確認。

isset($_COOKIE[session_name()])

セッション開始

  1. session_start()を実行する
  2. セッションで使用しているセッション変数($_SESSION['キー'])が定義されているか確認する
    • 定義されていなければセッション変数を定義してセッション開始
    • 定義されていればセッション継続

セッション終了時

  1. session_start()を実行する
  2. セッション変数をクリア($_SESSION = [])
  3. setcookie()でクライアントのセッションクッキーを削除
  4. session_destroy()を実行

セッションクッキーの名前はsession_name()で得られる。

セッションクッキーの削除

一般的なクッキーの削除は第3引数まで設定すればよいが、セッションクッキーの削除は第4引数のpathまで指定する必要がある。通常、セッションクッキーのパスはドキュメントルート('/')。

setcookie(session_name(), '', 0, '/')

さらにクライアント上のサーバーに関するドメインやセキュリティー設定情報も確実に消すために、session_get_cookie_params()で取得したパラメーターをsetcookie()の全引数に設定するのがよい。

 

PHP – 文字列のトークンによる分割

概要

strtok()は文字列を指定したトークンで分割する。

イテレーターとして順次取り出す操作に注意。

処理の流れ

以下のように、最初に文字列を指定してstrtok()を実行した後、文字列指定なしで実行し、切り分けられる文字列がなくなった時に結果がfalseになる。

一般的な利用例

以下のように複数のトークン文字を指定できる。

 

 

PHP – 配列の先頭・末尾要素の追加・抜き出し(破壊的)

概要

以下の関数は、配列の先頭・末尾に要素を追加し、要素を抜き出す。これらの関数は元の配列を変更する。

  • unshift()は配列の先頭に要素を追加し、要素数を返す
  • shift()は配列の先頭から要素を1つ抜き出す
  • push()は配列の末尾に要素を追加し、要素数を返す
  • pop()は配列の末尾から要素を1つ抜き出す

ただし連想配列については、これらの関数がうまく機能しない、臨んだ値を返さないということがあり、別の処理が必要。

非破壊的に先頭・末尾の要素を取り出す方法はこちら

配列

unshift()/shift()~先頭要素の追加・抜き出し

unshift()は配列の先頭に要素を追加し、追加後の配列の要素数を返す。追加後の配列は変更される。追加する要素は複数指定加可能。

unshift($array, $value[, $value ...]) : $size

shift()は配列の先頭から要素を1つ抜き出して返す。抜き出した後の配列は変更される。

shift($array) : $value

push()/pop()~末尾要素の追加・抜き出し

push()は配列の先頭に要素を追加し、追加後の配列の要素数を返す。追加後の配列は変更される。追加する要素は複数指定加可能。

push($array, $value[, $value ...]) : $size

pop()は配列の先頭から要素を1つ抜き出して返す。抜き出した後の配列は変更される。

pops($array) : $value

連想配列

unshift()/push()はよくない

連想配列への追加は、要素としてではなく配列として追加されてしまう。

shift()/pop()は値だけ返る

キーの取得が必要ない場合は、これらを使える。

結合演算子’+’は使える

配列の結合演算子を使えば、先頭・末尾への追加が素直にできる。

array_slice()とunset()による書き方

連想配列のキー・値のセットで取り出したい場合に、array_slice()で先頭や末尾要素を取り出し、そのキーを使ってunset()する方法。reset()end()でもよい

 

PHP – 配列の要素を削除する

配列

配列の要素の削除はunset()関数を使う。このときインデックスが飛んでしまうので、振りなおす場合はarray_values()で新たな配列として取り出す。

連想配列

連想配列の要素の削除はキーを削除してunset()を実行すればよい。

 

PHP – 配列の先頭・末尾・部分配列の取出し(非破壊的)

概要

配列の先頭・末尾要素をunshift()pop()で取り出すと、元の配列が変更される。

これを変更せずに要素や部分配列を取り出したいときの方法。

配列

reset()/end()

配列の先頭・末尾を取り出すことに特化した関数はないが、ポインターを先頭に巻き戻すrest()関数、最後に移動させるend()の戻り値が移動後の要素を指していることを利用する。

ただし、これらの関数がポインターを移動させるため、独自にポインターを使っている中で使うと副作用が生じ得る。

array_slice()

array_slice()関数は、0から始まるオフセットと長さを指定して配列の任意の部分配列を取り出す。

array_list($array, $offset, $length)

連想配列

連想配列の場合、array_slice()は想定通りに機能するが、先頭要素や末尾要素の場合は少し面倒。

部分列~array_slice()

部分列が連想配列として得られる。

先頭要素

reset()の引数に連想配列を指定した場合の戻り値は連想配列の「値」のみ。キーを取得するには、reset()で先頭に巻き戻された元の配列のキーを取得する。

ポインターを移動させるため副作用が生じ得る。

array_slice()を使ってもよく、この場合は副作用は生じない。

末尾要素

末尾要素は、reset()と同じようにend()関数を使ってポインターを移動させる。

ポインターを移動させるため副作用が生じ得る。

array_slice()を使っても末尾要素を取り出せるが、少しややこしくなる。

 

PHP – 雛形 – JSの確認ダイアログとの連動

概要

PHPでHTMLを操作する際、formからの送信前にユーザーに確認して、OKの場合だけ値をPHPで受け取る方法。

  • form要素のonsubmit属性で確認用の関数のreturnを設定
  • JSで確認用の関数を準備(return true/false)
  • submitに対する処理を普通にPHPで記述

実装例

以下のHTMLでは、form要素の属性でonsubmit="return ask()“を設定。true/falseを返すask()関数は別途定義している。

HTML側でask()の結果がfalseのときは先へ進まず、trueの時にPOSTが実行される。

PHP側では、HTMLからPOSTされたときの処理を普通に書けばよい。

 

 

なお上の例では関数ask()を別に定義したが、以下のように直接confirm()関数を書き込んでも実行される。

<form onsubmit="return confirm('本気ですか?')">

 

PHP – 雛形 – Cookie

概要

  • Cookieはサーバー側からクライアントのブラウザーに変数のように情報を記録する仕組み
  • クライアントに対するCookieの設定はsetcookie()関数で行う
    • Cookieの設定の際はtime()関数を使って有効期限をセットする
  • PHPではスーパーグローバル変数$_COOKIEを通して参照する
  • Cookieの削除はsetcookie()で過去の時刻を有効期限としてセットする

基本の流れ

Cookieのセット

サーバー側のPHPでsetcookie()でクライアントのCookieをセットする。

setcookie('キー', 値, 有効期限)

有効期限は現時点からの秒数で指定し、通常はtime()+破棄までの秒数で指定する。

Cookieの参照

クライアントに特定のキーのCookieがセットされているかどうかはisset()でチェック。

isset($_COOKIE['キー']) : true/false

セットされている場合は連想配列としてキーを指定して参照する。

Cookieの削除

Cookieの削除は、setcookie()で有効期限を過去の時刻でセットする。たとえばtime()-ある程度の秒数、0を指定してもよい。

HTMLは以下を処理する。

  • もしPHP側で変数が定義されていれば、既に登録された好きな食べ物として表示
  • 好きな食べ物を登録する

PHPコードでは以下のような処理をしている。

  • Cookieがセットされていればその内容を変数に代入する
  • 全てが空白であれば無視する
  • 空白でなければその内容をCookieにセットする
  • header()関数で改めてこのページを実行しなおす

 

PHP – 雛形 – 全角も含めた文字列のトリム

概要

  • PHPにはtrim系の関数が準備されているが、全角スペースには対応していない
  • str_replace()を使うと、前後だけでなく文字列中のスペースが除去されてしまう
  • そこで、preg_replace()で正規表現によって前後のスペースだけ除去する

実装例

以下のコードの関数の中でトリムを実装している。

第1引数でサーチする文字、第2引数でマッチした文字の変更後の文字、第3引数で対象文字列を指定。

第1引数は「先頭か末尾にある半角か全角のスペース」を表現しているが、その過程は以下のとおり。

  • '/.../u'で正規表現の文字列をUTF-8として扱う
  • '/\A...|...\z/'uで先頭部分か末尾部分を指定
  • [\x20\xE3\x80\x80]は文字クラスで、\x20が半角スペース、\xE3\x80\x80が全角スペースを表し、それらの何れかの文字を指定
  • []++文字クラスの後の++は絶対量指定子と呼ばれるもので、通常使われる最大量指定子+(1文字以上にマッチ)に対してバックトラックが抑制されるとのこと

その他の文字のトリム

文字クラス[]の中に指定する文字列。

\p{Z}
区切り文字(半角・全角スペースも含まれる)。
\p{C}
その他の文字(制御文字)。

PHP – 複数のsubmitで処理を分ける

概要

複数のsubmitから異なるターゲットに遷移するには、formタグでaction属性を設定せず、それぞれのinputでformacion属性を設定する。

一つのターゲットで異なるsubmitごとの処理を分けたいときは、それぞれのinputにname属性を設定し、PHP側のissetでそれぞれが定義されているかどうかによって処理を分けるとよい。

以下のHTMLでは3つのsubmit(送信1、送信2、その他の送信)を配置し、前者2つにはname属性の値として”submit1″、”submit2″を設定し、その他の送信にはname属性を設定していない。

以下はこれを受け取るPHPコードで、isset()によって$_POST['submit1']$_POST['submit2']が定義されていればそれぞれに対応した処理をし、それ以外の場合には「その他の送信」としている。

実行すると3つの送信ボタンが表示され、それぞれを押すとボタンに対応したメッセージが表示される。