「グローバル多次元配列」というとなんか強そうだ。

本日はphpとsqlの話。
興味のない人には全く役に立たず、役に立つ人には立つかもしれん程度の話である。
多次元配列をグローバール変数として扱う。forで回してDBのテーブルから多次元連想配列を作る。というのがお題。


大量の文字データーが入ったテーブルがあり、これを対照リストにしたがって変換して表示する機能を作るとする。
例えば、データーのテーブルに「はとまめむぎそら」や「むらそとむぎ」と入ってたとして、これを「はと、すずめ」や「むぎ、いね」の対照リストを通して「すずめまめいねそら」や「むらそといね」と表示するということである。
最初は対照リストをテーブルから読まずに、「はとまめむぎそら」が入った$strを

function mojihenkan($str){
$str = ereg_replace("むぎ","いね", $str);
$str = ereg_replace("はと","すずめ", $str);
return $str;
}

てな感じの関数に渡していたのだが、この対照リストを簡単に更新できるようにDB化してテーブルに入れたのだが、実際値を変換する際に、データーのテーブルがそれほど数が無い場合はselectしてレコードの1値ずつに対して対照リストテーブルをselectして値を取り出せばいいが、データーが数十万件あるとかなりレスポンスが遅い。
データーテーブルに20万件、対照リストテーブルに20件あったとして、対照リストテーブルから値を取り出すだけの全く同じクエリが400万回実行されるので遅いわけだ。
便利にはなったが遅くなった。これは困った。ということで色々対策を考え、sqlの実行結果をキャッシュするモジュールzendのフレームワークを入れてやろうかと思ったのだが、器械の力や金の力に物を言わす成金のようで嫌やし、こういう無駄な激しく美しくないコードを書くのは美意識に反する。根本的な実装の問題なのだ。
ということで、最初に一度対照リストテーブルから値を取り出して、for文で回してそれを二次元の連想配列に格納し、後から実際の変換時にユーザー定義関数でforを回してその配列を使って値を変換する手順をとった。
例えば、対照リストテーブルのレコードを二次元の連想配列に
$henkan[1][id]=1 $henkan[1][mae]=はと $henkan[1][ato]=すずめ
$henkan[2][id]=2 $henkan[2][mae]=むぎ $henkan[2][ato]=いね
という風に格納し、
データーテーブルの1レコードのデーター「はとまめむぎそら」などが入った$str一つごとに

for ($i=1 ; $henkan[$i][id}!="" ; $i++){
$str = ereg_replace($henkan[$i][mae],$henkan[$i][ato], $str);
}

と回して変換してやるわけやけど、このforの所を引数$strを使うユーザー定義関数にすると、対照リストテーブルが入った配列は何も値が入っておらず、グローバル変数として呼び出してやらんといかんようだ。
配列でない変数だとglobal $hensuuとか書けばいいだけやけど、配列はどう書けばいいのか?
forごとに
global $henkan[$i][id],$henkan[$i][mae],$henkan[$i][ato] ;
でも駄目で、forの外で
global $henkan[$i][];
global $henkan[][];
でも駄目。
グローバル配列だのグローバル連想配列だのという単語でぐぐっても何も出ない。ここのところにだいぶはまった。
結局色々試行錯誤してみてわかったのだが、は多次元配列だろうと一次元だろうと連想配列だろうと、global $henkan ;
でいいようだ。ついで言うとグローバル配列なる単語も使わんぽい。
で、

function mojihenkan($str){
global $henkan;
for ($i=1 ; $henkan[$i][id}!="" ; $i++){
$str = ereg_replace($henkan[$i][mae],$henkan[$i][ato], $str);
}
return $str;
}

てな感じの関数を、

$result = sqlite_query($db, $sql);
while ($row = sqlite_fetch_array($result, SQLITE_ASSOC)) {
print ( mojihenkan($row[moji]) );
}

てな感じで呼んでやれば解決。

コメントする

メールアドレスが公開されることはありません。

PAGE TOP