何もない空虚

動画を作っていたりいなかったり

リアルゴールドの日 

こんにちは、14時半前、寒いですね。
今週の日曜の深夜に大雪が降って、関東は一面雪に覆われました。
おかげで電車は動かないわ寒いわでてんやわんや、やっぱり雪なんて降らなくて良いですね…。

簡単なPHPのお話。

というのも、先ほどPHPにて2つのエクセルファイルを読み込もうとしたんですが。
何故か2つ目のエクセルファイルの読み込み時に動作が止まってしまって、調べても原因がわからず困っていました。

で、色々ログに出して調べたところ、原因がわかったので簡単に書いておこうかなと思った次第です。
最初に書いていたPHPのイメージがこんな感じ。

for ($i = 0; $i < count($file_name); $i++)
{
    $target_file = $current_directory . "/xlsx/" . $file_name[$i];
    $obj_reader = PHPExcel_IOFactory::createReader('Excel2007');
    
    $obj_book = $obj_reader->load($target_file); ← 2週目のここで止まってた。
    
    $obj_sheet = $obj_book->getSheet(0);
    
    ・・・
    
    $obj_writer = PHPExcel_IOFactory::createWriter($obj_book, 'Excel2007');
    $obj_writer->save($target_file);
}

要するに$file_nameに複数のエクセルファイル名を格納しておいて、自身を上書きするようなロジックです。
1回目はきちんと処理されたんですが、2回目に$obj_book = $obj_reader->load($target_file);で処理が止まっていたんですね。

例外を吐くわけでもないのでうんうん唸っていたんですが、以下のように書くときちんと動きました。

for ($i = 0; $i < count($file_name); $i++)
{
    $target_file = $current_directory . "/xlsx/" . $file_name[$i];
    $obj_reader = PHPExcel_IOFactory::createReader('Excel2007');
    
    $obj_book = $obj_reader->load($target_file);
    
    $obj_sheet = $obj_book->getSheet(0);
    
    ・・・
    
    $obj_writer = PHPExcel_IOFactory::createWriter($obj_book, 'Excel2007');
    $obj_writer->save($target_file);

    $obj_book->disconnectWorksheets();
    unset($obj_book);
}

unsetはローカル変数の破棄で、どこのサイトでもメモリ負荷を抑えるためとか、リソースの確保のためとか書いてありました。

それはともかくとして、disconnectWorksheetsについて書いてあるサイトが全くなくて少し苦戦しました。
また書いてあったとしてもunsetと同じような意味合いで書いてあったりして、間違っちゃないんだけど、それは結果論だよなぁ…と。

多分読んで字のごとく、ワークシートから切断するとは思うんですが、これを行っていないサイトの多いこと多いこと。
エクセルファイルを読み込んだ後、必要なくなったらちゃんとdisconnectWorksheetsしないとダメだよ!ということですね。

2016.1.22 追記)

ここまで昨日書いた後、またloadで落ちる現象が多発しました。

して、渋々色々試したんですが、どうやらExcelのファイルの行数が少ない(= 小さいファイル)だと落ちないことがわかりまして。
確かにunsetなりdisconnectWorksheetsなりでメモリ消費を抑えるのも大事なんですが、そもそもファイルを読み込んでいる時点で落ちているのでこれだと解決になりません。

結論から言うと、ini_set('memory_limit', '1G');で対処できました。

要するに一時的にメモリの上限を上げてloadで落とさないようにしただけですが、効果てきめんでした。
昨日言っていた複数ファイル云々のくだりが恥ずかしいですね…メモリを食うって意味では間違ってなかったんですが。

とはいえ今回の対処法はあまり褒められたものでないのも事実なので、ご利用時は計画的に。

今回お世話になったサイト様方。
[RESOLVED]"$objReader->load($inputFileName)" KO #119
# 64Mはあんまりだと思った。(小並
PHPExcelで大きいエクセルファイルを読み込んだときメモリ不足
trackback: -- | コメント: -- | edit