あまりに罠すぎるので、ここに書いておけば、誰かは救えるはず。
XML_Parserはシングルトンクラスです(たぶん)。
(RSSに関してはPHPでRSS、unsetに関してはPHPのunset に改めて書いた記事があります)
XML_Parserはシングルトンクラスです(たぶん)。
(RSSに関してはPHPでRSS、unsetに関してはPHPのunset に改めて書いた記事があります)
当然、シングルトンクラスなんてものはPHPの仕様として存在するわけではないので、使うほうでシングルトンとして使わないとダイナミックにメモリーリークします。
同様に派生クラスのXML_RSSもです。
ちなみに、XML_Parser::freeは見てのとおりにリソース開放な感じのクラスですが、こんなものを呼んでメモリー開放されないので、注意してください。
ポイントはXML_Parser::parseで、こいつを呼ぶと何かのオブジェクトに自分自身へのリファレンスがとられるみたいで、
$iRss = new XML_Parser($iRes);
$iRss->parse();
unset($iRss);
ではメモリが開放されないので、いつか地獄を見ます(デフォルトのphp.iniなら128Mのメモリ確保後)。
正しい使い方は、グローバルオブジェクトとして使用し、毎回、XML_Parser::setInputFileでファイル名セットすることなのだろうけど、我輩のシステムはこんな仕様なんてことはどこにも日本語で書いていなかったので、上記のような方式でアボンヌしていたと。
ところがさすが俺、オブジェクトをunsetで開放できるコードが書けたので、方法を紹介しておこう。
(ちなみに、開放のコードを書いてから、こんな馬鹿なはずはないとXML_Parserのコードコメントを見たら、シングルトンぽい感じということを知ったというのがいきさつ)
方法は簡単で、XML_Parserの全プロパティをunsetしてから元をunsetするだけ。
XML_Parserクラス定義でvarされている変数を全部unsetしてください。
ちなみに、派生クラスのデストラクタでunsetする方法は使えません。なぜなら、上記のコードでさえデスクトラクタが呼び出されないからです。
XML_Parserにはデスクトラクタがないので、理論上問題ないはず。というか、プログラマ的にはメモリリークしていないから問題ないという結論にw
余談ですが、これも驚きの仕様なんだけど、PHPはクラスメンバー変数をunsetすると、定義がされていないことになるのです!!!
is_set関数を用いて非初期化を判定するなんて事をやっていると、当然、変数初期化はunsetということになるのだけど、通常のコードでは非常にクールな感じなのですが、コンストラクタでこれをやると、メソッドでこれを使うタイミングで未定義変数とかいわれます。
(そもそもコンストラクタでunsetする必要があるのかという点は、C++出身者の様式美という事にしておいて…)
なんとなくいえることは、PHP5あたりからのクラスの扱いの違いを考慮していないPEARライブラリは注意が必要というところですね。
$i = &new classA();
とかいうコードがあるライブラリは動作確認をしたほうがよい感じ。
同様に派生クラスのXML_RSSもです。
ちなみに、XML_Parser::freeは見てのとおりにリソース開放な感じのクラスですが、こんなものを呼んでメモリー開放されないので、注意してください。
ポイントはXML_Parser::parseで、こいつを呼ぶと何かのオブジェクトに自分自身へのリファレンスがとられるみたいで、
$iRss = new XML_Parser($iRes);
$iRss->parse();
unset($iRss);
ではメモリが開放されないので、いつか地獄を見ます(デフォルトのphp.iniなら128Mのメモリ確保後)。
正しい使い方は、グローバルオブジェクトとして使用し、毎回、XML_Parser::setInputFileでファイル名セットすることなのだろうけど、我輩のシステムはこんな仕様なんてことはどこにも日本語で書いていなかったので、上記のような方式でアボンヌしていたと。
ところがさすが俺、オブジェクトをunsetで開放できるコードが書けたので、方法を紹介しておこう。
(ちなみに、開放のコードを書いてから、こんな馬鹿なはずはないとXML_Parserのコードコメントを見たら、シングルトンぽい感じということを知ったというのがいきさつ)
方法は簡単で、XML_Parserの全プロパティをunsetしてから元をunsetするだけ。
XML_Parserクラス定義でvarされている変数を全部unsetしてください。
ちなみに、派生クラスのデストラクタでunsetする方法は使えません。なぜなら、上記のコードでさえデスクトラクタが呼び出されないからです。
XML_Parserにはデスクトラクタがないので、理論上問題ないはず。というか、プログラマ的にはメモリリークしていないから問題ないという結論にw
余談ですが、これも驚きの仕様なんだけど、PHPはクラスメンバー変数をunsetすると、定義がされていないことになるのです!!!
is_set関数を用いて非初期化を判定するなんて事をやっていると、当然、変数初期化はunsetということになるのだけど、通常のコードでは非常にクールな感じなのですが、コンストラクタでこれをやると、メソッドでこれを使うタイミングで未定義変数とかいわれます。
(そもそもコンストラクタでunsetする必要があるのかという点は、C++出身者の様式美という事にしておいて…)
なんとなくいえることは、PHP5あたりからのクラスの扱いの違いを考慮していないPEARライブラリは注意が必要というところですね。
$i = &new classA();
とかいうコードがあるライブラリは動作確認をしたほうがよい感じ。


