PHP5 + Symfony構成を使っているのですが、
strictエラーを出さないようにしたいとの要望が来ました。
strictエラーはPHP5に準拠したプログラミングしてないと
でてしまうメッセージ。
PHP4でも動くように作られているPEARはもちろんその対象と
なってしまいます。
出力レベルを変更すれば良いのですが、
それはやりたくないないとの方針なので、
PEARをどうしても使いたい場合は移植する必要があったり。
これが簡単かなと思っていたら、結構大変なことに気づきました。
アクセス修飾子をすべてのメンバ変数、メソッドにつける
基本的にstrictで出る多くは、アクセス修飾子、
「public/protected/private」をつけていないことや
静的関数「static」をつけていないことに起因してます。
まずそれぞれを一つづつ確認し、付記していく作業がはじまります。
※ちなみに本記述は
class外のfunctionは「関数」
class内のfunctionは「メソッド」
class内の変数(var)は「メンバ変数」
で統一しています。
PEARにはPHPDOCコメントが書いてあり、
「@access public」などと書いてあるので、ロボットのように
アクセス修飾子をひたすらにつけて行ってたのですが、
よく見るとコメントが書いてないところが多くあったりして、
その意味を理解しながら変更していかなければなりませんでした。
そして大量のプログラムをやっとの思いでつけ終わって、
さて動かそうと思うと、大量のエラーが!!!
どうやらコメントに書いてある「@access private」も
かなり間違っているのが含まれている様子。
やりやがったな。(コンバット越前ふうに)
ってことで再度意味を理解しながら、ちょくちょく変えていく作業。
個人的なプログラミングなら、置換ソフトを使って、
全てのアクセス修飾子とメンバ変数をpublicにしてしまうという
とってもワンパクなやり方をやってしまいたい。(保障しませんが)
ってかアスペクト指向プログラミングのAspectPHPを使って
強制的に処理を横取りしてやろうかと思ったりしましたが、
その辺は思いとどまり、ちまちまと開始。
やっとの思いで終了しました。
参照渡しと値渡し
PHP4では基本が「値渡し」だったわけですが、
PHP5では基本が「参照渡し」になっています。
値渡しでは、データを引き渡すときに値をコピーして渡す方式。
参照渡しでは、データを引き渡すときに、値が入ったアドレスを渡す方式。
つまり値はコピーを、参照渡しは実態を渡すイメージになります。
例)
//引き渡すデータオブジェクトの生成
$obj = new obj('こんにちは');
//呼び出すAクラスのオブジェクトの生成
$a = new Aisatsu();
//挨拶変更メソッドを呼び出す
$a->changeNight($obj);
//結果を出力する
echo($obj->get());
//挨拶クラス
class Aisatsu {
//文字を変更するfunction
function changeNight($obj){
$obj->set('こんばんは');
}
}
//データを保持するオブジェクト
class Obj {
//メンバ変数:データを保持する
private $str;
//コンストラクタ(PHP5だと__construct)
public Obj($str){
$this->str = $str;
}
//値をセットする
function set($str){
$this->str = $str;
}
//値をゲットする
function get(){
return $this->str;
}
}
上記の結果は
PHP4の場合「こんにちは」
PHP5の場合「こんばんは」
が出るという結果になります。
このように大きく動きが変わっていくので注意が必要です。
そのためfunctionへの引渡しに問題がないかを確認する必要があると同時に、
代入式の見直しも図っていく必要があります。
以下はPHP4とPHP5における、値渡しと参照渡しの方法です。
▼PHP4
値渡し : a = b;
参照渡し: a =& b;
▼PHP5
値渡し : a =clone b;
参照渡し: a = b;
もちろんプリミティブな値(乱暴な言い方をするとオブジェクトでないデータ)
については、常に値渡しと同意になるので問題になりません。
これまた乱暴なサンプルですが
a =& 3;
a = 3;
の結果は同じになります(常にコピー)。
a =& $obj;
a = $obj;
は結果が変わるというわけです。
このあたりを意識しながら、PEARのプログラムに修正を加えていく必要が
あります。
とっても急いでいる方は、
「=&」 をとりあえず 「=」に全置換してしまうという
ワンパクなやり方もありかもしれません。(やっぱり保障できないですが)
また function &abc() といった参照返しの記号も除去しなければなりません。
それと参照渡しのため、オブジェクトを返すべきところで
参照出来ない「null」を返すようにしているところは直す必要があります。
is_a関数は非推奨
is_a関数を使っているとe_strictエラーで「duplicated」と表示されます。
つまり書き直す必要があります。
is_a($obj, 'PEAR')
→
$obj instanceof PEAR
get_classの動作が変わる
PHP4でget_classするとクラス名が全て小文字になってしまいます。
PHP5でget_classすると大文字小文字そのままで取れるように変わりました。
例)HelloWorldClass
PHP4 get_class() → helloworldclass
PHP5 get_class() → HelloWorldClass
そのためget_classしているところでは大文字/小文字関わらず
比較する必要があります。
if (get_class($obj) == 'helloworldclass') {
}
if (strcasecmp(get_class(), 'helloworldclass') == 0){
}
エラーレベル引き下げるほうが結局楽
上記のように変更には多大なコストがかかります。
そもそも「e_strictエラー」は「e_noticeエラー」より下のエラーなので、
こだわりがなければオフにしてしまうのがオススメです。
まずエラーレベルの種類とビット値を列挙しておきます。
▼エラーレベルとビット値
値 定数
1 E_ERROR
2 E_WARNING
4 E_PARSE
8 E_NOTICE
16 E_CORE_ERROR
32 E_CORE_WARNING
64 E_COMPILE_ERROR
128 E_COMPILE_WARNING
256 E_USER_ERROR
512 E_USER_WARNING
1024 E_USER_NOTICE
2047 E_ALL
2048 E_STRICT
4096 E_RECOVERABLE_ERROR
※上記はPHP5までのコード値なので注意。
基本的に設定したエラーレベルより上のエラーレベルが出力されます。
これを参考に以下の設定で、このエラーを出力しないように出来ます。
(コードでも定数でもどちらでも設定可能です。)
▼PHPの設定
php.iniを以下のように変更します。
現在おそらく、以下のようになっている箇所があると思います。
error_reporting = E_ALL|E_STRICT
これを
error_reporting = E_ALL
に変更しましょう
▼symfonyを使っている場合の設定
symfonyはその処理の途中で、php.iniの設定をsymfonyの設定で
上書いています。そのため上記処理だけでなく、
symfonyの設定ファイルも触る必要があります。
(以下の設定はsymfonyに基づき、ビット値を使って設定しています。)
※設定ファイル
プロジェクト名/apps/アプリケーション名/config/setting.yml
※設定方法
各モードごとに設定があるので該当する箇所の
「error_reporting」を変更します。
error_reporting: 4095
この右側のコードに意味があり、
「E_ALL | E_STRICT」を意味する数値が4095ということになります。
つまりこれを
「E_ALL」にすればいいわけですから、
error_reporting: 2047
と設定すればよいということになります。
ちなみにPHP6では、E_ALLのビット値が「6143」に変更されるため、
E_STRICTを含む、全てのエラーが出るようになるので、
注意が必要です。
最後に
これでE_STRICT対応が完了しました。
念のために、テストを行い動作確認は行っておいたほうがよさそうです。
完全準拠した、PHP5プログラミング(Zend Engine2対応)は
過去の財産の兼ね合いから中々大変です。
ふとニュートンの名言を思い出しました。
「私がさらに遠くを見ることができたとしたら、
それはたんに私が巨人の肩に乗っていたからです。」
移植は面倒でしたが、みんなで作られたPEARというオープンソースのおかげで、
便利にプログラムさせてもらってるのも事実。
より便利になる手法があれば、自分自身が、考えて、作って、
色んな環境でも動くように貢献していかなくてはと感じました。
とりあえず気づいたところだけ列挙しました。
違うぞ!、足りないぞ!などありましたら、是非ツッコミをいれてもらえるとうれしいです。



