今朝のうえちょこ@ぼろぐ » [php][PEAR]Date_Holidays_Driver::setYear()が変がやっぱり気になったので、少しだけ調査。
※PEAR::Date_Holidays_Driver_Japanese 0.2.2がリリースされました。下記不具合を包括的に解決しています。0.2.0以前を使用してる方は、アップグレードすることを強くお勧めします。
PEAR::Date_Holidays_Driver_Japanese 0.2.2 - Do You PHP はてな
1.$this->_internalNamesが増殖する件 ===================
Date_Holidays_Driver::serYear()メソッドを呼び出すと、内部の仕様でDate_Holidays_Driver::_buildHolidays()メソッドが呼ばれます。_buildHolidays()メソッドは、各国別のドライバがその国々の祝日を登録するメソッドです。
_buildHolidays()メソッドの内部では、祝日の数だけDate_Holidays_Driver::_addHoliday()メソッドを呼び出して、祝日を登録します。_addHoliday()メソッドだけ抜き出してみます。
php:
-
/**
-
* Adds a holiday to the driver's holidays
-
*
-
* @param string $internalName internal name - must not contain characters
-
* that aren't allowed as variable-names
-
* @param mixed $date date (timestamp | string | PEAR::Date object)
-
* @param string $title holiday title
-
*
-
* @access protected
-
* @return void
-
*/
-
function _addHoliday($internalName, $date, $title)
-
{
-
if (! is_a($date,
'Date')) {
-
-
}
-
-
$this->_dates[$internalName] = $date;
-
$this->_titles['C'][$internalName] = $title;
-
-
$date->getMonth(),
-
$date->getDay(),
-
$date->getYear());
-
if (!isset($this-
>_holidays
[$isodate])) {
-
$this-
>_holidays
[$isodate] =
array();
-
}
-
array_push($this-
>_holidays
[$isodate],
$internalName);
-
array_push($this-
>_internalNames,
$internalName);
-
}
$this->_internalNamesが増殖する原因は、この_addHoliday()メソッドの最後のarray_push() x 2です。2回目以降のビルドのときに呼び出されると、$this->_datesや$this->_titlesは与えられた$internalNamesの祝日情報を上書きするのですが、$this->_holidays[$isodate]と$this->_internalNamesだけは上書きせず、後ろに追加します。これが増殖の原因。ただし、増殖することがバグであるかどうかは知りません(そういう仕様が正しいかもしれない)。しかし、素人目ではバグの気がしてなりません。
なお、ライブラリの修正方法としては、最後のarray_push()の前に、しっかりとif (! in_array())の条件分岐をしてあげることです。
2.振替休日と国民の祝日が表示されない件 ===================
2回目以降の再構築のとき、振替休日と国民の祝日が表示されなくなります。実は
$obj->getHolidayForDate($d, 'ja_JP');
つまり、日本語の翻訳ファイルを使用したときには表示されないのですが、
$obj->getHolidayForDate($d, 'C');
('C'というのは、内部仕様で、内部英名を現すロケール)を用いて英名にすると振替休日と国民の祝日が表示されます。
ここからわかることは、翻訳ファイルがらみで何かがおかしいということです。
さてさて、中身を見ていきます。
Date_Holidays_Driver_Japaneseでは、2回目以降の再構築の際、振替休日と国民の祝日の祝日情報を消去します。消去にはDate_Holidays_Driver::_removeHoliday()メソッドを用いています。そして、消去し終わると、すべての祝日を_addHolidays()メソッドで登録し、その上で振替休日と国民の祝日を計算します。
_removeHoliday()メソッドでは、指定した祝日に関する(翻訳情報を含む)すべての祝日情報を消去します。
_addHolidays()メソッドでは、内部英名の祝日情報を登録します。
よろしくないのは、_removeHoliday()は、翻訳情報を消してしまうのです。
安易な考えですが、_removeHoliday()メソッドでの翻訳情報の削除部分を取り除いてしまえばいいのでは!?と思いついてやってみたのですが、うまくいきませんでした。翻訳ファイルを読み込むDate_Holidays_Driver::addTranslationFile()メソッドは、どうやら、現在登録されている祝日だけの翻訳情報を読み込むようです。余分なデータを読み込まないのはいいことですが、年が変わって再構築でひょっこり新しい祝日が出てきてしまうと翻訳情報がないので、そのロケールでは表示できないのです。これが原因です。
エンドユーザー側の解決策としては、setYear()したら、addTranslationFile()で翻訳ファイルを読み直すのが手っ取り早いです。
ライブラリ自体の解決策としては、「this->_titles」とは別の系統に翻訳情報のマッピング変数を用意して、そこに「現在登録されている祝日のものだけ」読み込むのではなく「すべて」読み込んで、内部ロケール以外のロケールで表示するような要求があった場合、マッピング変数を用いて表示するとか、そういう感じですかね。とっても面倒な変更です。他にスマートな方法があればいいのですが。。。
そんなわけで、調査終了。原因がわかったのでスッキリ。ライブラリ自体にはモヤっとだけど。