eval()関数を使うfopen()関数とのジレンマXSLT関数にXMLデータを渡す方法はXMLファイルを指定する方法とXMLデータを配列で渡す方法があります。
何らかの処理が必要でXMLデータを配列で渡す場合、fopen()関数でファイルを開いてデータを読み込むことになるわけですが、この方法だとXMLファイル内のPHP命令はそのままテキストデータとして読み込まれます。
XMLファイルを元にPHPでXSLT処理してHTMLを生成する場面は多いはずですが(このサイトはほぼ全てこの手順で作られています。)肝心のXMLデータが動的に変化できないため柔軟性が低くなってしまうのが難点です。
PHPのヘルプに解決策が乗っていました。
$data_xml =
preg_replace_callback( "/<\?php(.*?)\?>/si", "eval_buffer", $data_xml );
<?phpから?>の範囲をpreg_replace_callback()で置換すればいいわけです。eval()の性質上、普通のpreg_replace()では置換できません。
function eval_buffer( $string ) {
ob_start();
eval( "$string[1]" );
$result = ob_get_contents();
ob_end_clean();
return $result;
}
呼び出す関数ではob_start()でeval()が出力する内容をバッファリングしてから返り値として返します。return eval( "$string[1]" );としないのは、eval()はその場ですぐに評価されるため、実際にprintなどの命令が出力されてしまい返り値として返すことが出来ないからです。
この方法だと分割されたPHP命令間で変数の引き継ぎやユーザー定義関数を使い回すことが出来ません。各PHPモード部は別々に評価されます。
また、基本的にはローカル変数なので変数が書き換えられることはありませんが、global宣言されている場合は上書きされることがあるので注意してください。ユーザー定義関数も引き継がれます。requireするときと同じようにあつかった方が安全だと言えます。