PHP 已经提供了您所需要的 99.9% SplFileObject
,您可以通过扩展来添加缺少的 0.1%。在以下示例CSVFile
中从它扩展:
$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
{
/**
* @param string $file
*/
public function __construct($file)
{
parent::__construct(new SplFileObject($file));
$this->setFlags(SplFileObject::READ_CSV);
}
}
由于TraversableIterator的标准装饰能力, CSVFile的第一个示例中的原始构造函数代码可以被 100% 复制。
最后一个添加还允许保持使用CSVFile迭代器的原始代码完整:
$csv = new CSVFile('../data/test.csv');
foreach ($csv as $line) {
var_dump($line);
}
因此,只需快速重构以允许更多代码重用。您可以免费获得KeyedArrayIterator。