PHP5.1.0以上の環境では、CSVファイルを読み込むためのSplFileObjectクラスが用意されている。
基本的には以下の参考元と変わらないが、いくつかの方法を試してみる。
##まずはCSVファイルを用意する
今回は、1行目にカラム名が含まれるものを用意した。
以下では、カラム名を除いて値を参照する方法を考えたい。
name,hometown,age,job
Alice,London,25,teacher
Philipp,Geneva,33,economist
Taro,Tokyo,55,doctor
##ケース1:シンプルに値を取得
$fp = new SplFileObject('people.csvへのpath');
$fp->setFlags(SplFileObject::READ_CSV);
foreach ($fp as $line) {
var_dump($line);
}
array(4) {
[0]=>
string(4) "name"
[1]=>
string(8) "hometown"
[2]=>
string(3) "age"
[3]=>
string(3) "job"
}
array(4) {
[0]=>
string(5) "Alice"
[1]=>
string(6) "London"
[2]=>
string(2) "25"
[3]=>
string(7) "teacher"
}
array(4) {
[0]=>
string(7) "Philipp"
[1]=>
string(6) "Geneva"
[2]=>
string(2) "33"
[3]=>
string(9) "economist"
}
array(4) {
[0]=>
string(4) "Taro"
[1]=>
string(5) "Tokyo"
[2]=>
string(2) "55"
[3]=>
string(6) "doctor"
}
array(1) {
[0]=>
NULL
}
伝統的(原始的)なfopenとfgetを用いるコードより圧倒的に綺麗だが、カラム名と空白行が取得されてしまう。
##ケース2:seekメソッドを用いてみる
SplFileObject::seek — ファイルポインタを指定行に移動させる
seekメソッドのパラメータは
ゼロを起点とした移動させる行数
らしいので、1を入れてみる。
ただし、いくつかメソッドを使う。
SplFileObject::current — ファイルの現在の行を取得する
SplFileObject::eof — ファイルの終端に到達しているか調べる
SplFileObject::next — 次の行を読み出す
$fp = new SplFileObject('people.csvへのpath');
$fp->setFlags(SplFileObject::READ_CSV);
$fp->seek(1);
while (! $fp->eof()) {
var_dump($fp->current());
$fp->next();
}
array(4) {
[0]=>
string(5) "Alice"
[1]=>
string(6) "London"
[2]=>
string(2) "25"
[3]=>
string(7) "teacher"
}
array(4) {
[0]=>
string(7) "Philipp"
[1]=>
string(6) "Geneva"
[2]=>
string(2) "33"
[3]=>
string(9) "economist"
}
array(4) {
[0]=>
string(4) "Taro"
[1]=>
string(5) "Tokyo"
[2]=>
string(2) "55"
[3]=>
string(6) "doctor"
}
array(1) {
[0]=>
NULL
}
空白行が残る。。。
ポインタの問題か。。。
##ケース3:foreachに再帰する
ただし、
SplFileObject::key — 行番号を取得する
を使って、最初の行だけ除くよう処理する。
$fp = new SplFileObject('people.csvへのpath');
$fp->setFlags(SplFileObject::READ_CSV);
foreach ($fp as $line) {
if ($fp->key() > 0 && ! $fp->eof()) {
var_dump($line);
}
}
array(4) {
[0]=>
string(5) "Alice"
[1]=>
string(6) "London"
[2]=>
string(2) "25"
[3]=>
string(7) "teacher"
}
array(4) {
[0]=>
string(7) "Philipp"
[1]=>
string(6) "Geneva"
[2]=>
string(2) "33"
[3]=>
string(9) "economist"
}
array(4) {
[0]=>
string(4) "Taro"
[1]=>
string(5) "Tokyo"
[2]=>
string(2) "55"
[3]=>
string(6) "doctor"
}
おそらく、このコードが一番見やすく綺麗である。
##まとめ
カラム名と空白行を除いた上で値を取得するには、ケース3がいいと思われる。
しかし、膨大な行数のファイルを読み込むときには、その行数と同じだけのif処理が行われることになる。
したがって、値を取得して何かの処理を行う際に、速度だけを意識すればいいときはケース1を使ってみるのもありかもしれない。