PHPのNotice対策

久しぶりにサーバOSのバージョンを上げて、ついでにPHPのバージョンを5から7にした。
そうしたら今までに開発したアプリケーションが全然動かない。
ついでに、今まで見逃していたPHP Noticeが大量発生していた。

実はPHP4時代に、初めてPHPを触った時から気まぐれに機能を追加してきたので、
むちゃくちゃな内容がたくさんありすぎる。PHP4からPHP5にしたときは、
めんどくさいので、何の対策もしてこなかったのが致命的に辛い。

これから気が遠くなる作業が待っているが、備忘録としてここに対策を少しずつ記入していくことにする。

01. eregはもう対応しません。

はい。eregはもう対応しなくなりました。eregは5.3非推奨になっていて、7では削除されました。
eregの代わりに preg_matchを使おう。

ereg("\abc$")
↓
preg_match("/\abc$/");

02. explode listの組み合わせにはarray_pad

これまで

while( !feof( $fpym ) ) {
	$buffer = fgets($fpym, 1024);
	list($y[$cnt], $m[$cnt]) = explode(",",$buffer);
	$m[$cnt] = trim($m[$cnt]);
	$cnt++;
}

なんてことをしていたけれども、多分最後のEOFとかで、
Undefined offset: 1
なんて怒られてしまう。なので、array_padで足りない配列を埋めよう。

list($y[$cnt], $m[$cnt]) = array_pad(explode(",", $buffer), 2, null);

03. 内部エンコーディング htmlspecialchars

これまで

$a = htmlspecialchars($b,ENT_QUOTES);

としていたが、昔の名残で 表示のエンコードShift_JIS
でも、内部ではUTF-8なので、何故か

exit signal Illegal instruction (4)

というエラーがでる。
そこで、無理矢理Sfhift_JISに変換する.

$a = htmlspecialchars($b,ENT_QUOTES, "Shift_JIS");

これは、スクリプトで一括置換してもよいかも。

04. $_REQUEST $_GET系は、issetで明示的に.

これまで

$a = $_REQUEST['aaa']

なんてことをやっていて、なかったら$a=""じゃないかとして処理をしていたけどだめ。

if ( isset($_REQUEST['aaa']) ) {
$R_a = $_REQUEST['aaa'];
}

ということをしないといけない。これ、自動化できないか。なんかできそう。

05. A session had already been started - ignoring session_start()

これは、セッションが重複してsession_start()が呼ばれたときに起きる。

if ( !isset( $_SESSION ) ) {
    session_start()
}

にしよう。
もちろん終了するときも同様。

if( isset( $_SESSION ) ) {
    session_destroy();
}

regenerateも一緒。

06. Undefined index 配列じゃないとき

$_REQUESTが結構増えてくると毎回 issetを使うのが面倒なので、関数かするとよい。まあ、htmlspecialcharsいれてもいいかもね。

/** $_REQUEST['aaa'];をいきなり使うと、Notice:Undefinedが発生するため、それを防ぐ.
 * 例えば、$_REQUEST['abc'];を取得したい場合はこんな感じ。
 * $_R_abc = _R("abc");
 * @param str $_REQUEST['XXX'];のXXXの部分。
 * @return $_REQUEST['XXX'];のデータ.存在しない時は ""を返す.
 */
function _R( $str ) { /** {{{*/
	if ( isset($_REQUEST[$str]) ) {
		return $_REQUEST[$str];
	} else {
		return "";
	}
}
/**}}}*/

変数もどこで宣言したのか、途中で副作用が怖い場合は、直前にこんな風にしたらとりあえずNoticeは消える。本当は最初にきちんと宣言してたらいんだけど。

/** 未使用の変数でも、""として再定義させる.Notice: undefined variable対策.
 * 例えばいきなり、 aaa($x,$y)としたら$xが存在しないので、Noticeがでるので、
 * $x = _V("x"); $y= _V("y");とする.
 * 変更がどのように影響するか考えるのがややこしいとき対策.
 * もともと存在した場合はそのままその変数を返すので大丈夫.
 * @param $str 変数名
 * @return $strのデータ.存在しない時は""を返す.
 */
function _V( $str ) { /** {{{ */
	if ( isset(${$str}) ) {
		return ${$str};
	} else {
		return "";
	}
}
/**}}}*/

配列にこいつをかけても大丈夫かどうかは、まだ未検証。多分大丈夫だと思うけど。
→だめだった。
08で、追加の対策

07. A non-numeric value encountered のエラー

これは、数値ではないもの関係のエラーなので、数値にすれば直る。

$a = intval($a);

続きは後日。

08 Notice: Undefined index: XXXX の対策 配列の時

06. Undefined index 対策で多分できると記述したもののできなくて、Undefined indexが出た。
これの対策は厳しい。関数化させようと、引数に入れた時点でアウト。
基本的にemptyで対策をすればよいのだが、if を使うと、毎回参照する時点で何行も記述しないといけないのが面倒なので、参考演算子を使ってみた。

!empty($mintemperature[$i])?:$mintemperature[$i]="";//Notice: Undefined index対策
print $maxtemperature[$i];

こんな感じ。

PHP7だとこんなこともできる。

$a = $array['A'][$i]['B'] ?? '';

三項演算子をより手っ取り早くするかんじ。
Null合体演算子と呼ぶらしい。