使用PHP的SplFileObject
已经可以满足99.9%的需求,你可以通过继承来实现缺失的0.1%。在以下示例中,CSVFile
是从SplFileObject
继承而来的:
$csv = new CSVFile('../data/test.csv');
foreach ($csv as $line)
{
var_dump($line);
}
以下是您提供的示例数据:
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(4) "1500"
["Note"]=> string(6) "loaded"
}
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(4) "2500"
["Note"]=> string(0) ""
}
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(0) ""
["Note"]=> string(6) "loaded"
}
CSVFile
的定义如下:
class CSVFile extends SplFileObject
{
private $keys;
public function __construct($file)
{
parent::__construct($file);
$this->setFlags(SplFileObject::READ_CSV);
}
public function rewind()
{
parent::rewind();
$this->keys = parent::current();
parent::next();
}
public function current()
{
return array_combine($this->keys, parent::current());
}
public function getKeys()
{
return $this->keys;
}
}
如果你这样做,细节将被良好地封装起来。此外,在
current()
函数内处理错误(例如计数不匹配)更容易,因此使用数据的代码无需处理它。
编辑:
但是,所给示例在可重用性方面很短。与其从
SplFileObject扩展,还不如聚合它。
class KeyedArrayIterator extends IteratorIterator
{
private $keys;
public function rewind()
{
parent::rewind();
$this->keys = parent::current();
parent::next();
}
public function current()
{
return array_combine($this->keys, parent::current());
}
public function getKeys()
{
return $this->keys;
}
}
这段代码是完全相同的,但构造函数封装的细节被省略了。这种简化允许更广泛地使用该类型,例如(但不仅限于)使用所述SplFileObject:
$file = new SplFileObject('../data/test.csv');
$file->setFlags($file::READ_CSV);
$csv = new KeyedArrayIterator($file);
foreach ($csv as $line) {
var_dump($line);
}
如果这听起来过于冗长,它可以再次包装以使其外观更加美观。
class CSVFile extends KeyedArrayIterator
{
public function __construct($file)
{
parent::__construct(new SplFileObject($file));
$this->setFlags(SplFileObject::READ_CSV);
}
}
在可遍历迭代器TraversableIterator的标准修饰性的支持下,第一个CSVFile示例中的原始构造函数代码可以完全复制。
这个最后的补充还允许保持使用CSVFile迭代器的原始代码不变:
$csv = new CSVFile('../data/test.csv');
foreach ($csv as $line) {
var_dump($line);
}
所以只需进行快速的重构以允许更多的代码复用。你将免费获得一个 KeyedArrayIterator 。