最新記事一覧

PHP5でe_strictエラーを出さずにPEARを使ってみる 

現在関わってるサービスの一つでは、
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というオープンソースのおかげで、
便利にプログラムさせてもらってるのも事実。

より便利になる手法があれば、自分自身が、考えて、作って、
色んな環境でも動くように貢献していかなくてはと感じました。

とりあえず気づいたところだけ列挙しました。
違うぞ!、足りないぞ!などありましたら、是非ツッコミをいれてもらえるとうれしいです。
posted by 荒木 稔 | 2007年04月26日 | Comment(0) | TrackBack(0) | はてブに追加 このエントリーをはてなブックマークに追加