PHP:以 OOP 方式搜索 CSV 文件

标签 php oop object loops csv

我需要编写一个脚本来搜索 CSV 文件,并对其执行特定的搜索功能;

  1. 查找列中的重复项
  2. 在另一列中查找与禁止条目列表的匹配项
  3. 在指定列上通过正则表达式匹配查找条目

现在,我完全可以按程序编写代码,但由于我现在正在转向面向对象编程,所以我想改用类和对象实例。

但是,在 OOP 中思考对我来说还不是很自然,所以我不完全确定该走哪条路。我不是在寻找特定的代码,而是在寻找有关如何设计脚本的建议。

我目前的想法是这样的;

  1. 创建一个文件类。这将处理数据的导入/导出
  2. 创建一个搜索类。文件的子类。这将包含各种搜索方法

它如何在 index.php 中运行:

  1. 从 index.php 文件对象中的 csv 中获取一个数组
  2. 创建循环以遍历数组的值
  3. 从搜索对象调用循环中的方法并将它们回显

我看到这种方法的问题是这样的;

  • 我想指向数组中的不同元素以查看特定的“列”。我可以将我的循环放在一个函数中并将其作为参数传递,但我觉得这种做法违背了 OOP 的要点
  • 我的搜索方法将以不同的方式起作用。使用嵌套循环搜索重复条目非常简单,但我不需要嵌套循环来执行简单的单词或正则表达式搜索。

我应该这样走吗?

  1. 创建一个文件类。这将处理数据的导入/导出
  2. 创建一个循环类文件类的子类。这将包含处理遍历数组的方法
  3. 创建一个搜索类。循环的子类。这将包含各种搜索方法

我的主要问题是似乎我可能需要多个搜索对象并在我的循环类中迭代它。

任何帮助将不胜感激。我对 OOP 很陌生,虽然我了解各个部分,但我还无法看到更大的图景。我可能使我正在尝试做的事情过于复杂,或者可能有一种我还看不到的更简单的方法。

最佳答案

PHP 已经提供了一种方法来 read a CSV file in an OO manner with SplFileObject :

$file = new SplFileObject("data.csv");

// tell object that it is reading a CSV file
$file->setFlags(SplFileObject::READ_CSV);
$file->setCsvControl(',', '"', '\\');

// iterate over the data
foreach ($file as $row) {
    list ($fruit, $quantity) = $row;
    // Do something with values
}

由于 SplFileObject 流过 CSV 数据,因此内存消耗非常低,您可以有效地处理大型 CSV 文件,但由于它是文件 i/o,所以它不是最快的。但是,SplFileObject 实现了 Iterator 接口(interface),因此您可以将该 $file 实例包装到其他迭代器中以修改迭代。例如,要限制文件 i/o,您可以将其包装到 CachingIterator 中:

$cachedFile = new CachingIterator($file, CachingIterator::FULL_CACHE);

要填充缓存,您需要遍历 $cachedFile。这将填充缓存

foreach ($cachedFile as $row) {

然后要遍历缓存,您需要这样做

foreach ($cachedFile->getCache() as $row) {

权衡显然是增加了内存。

现在,要执行您的查询,您可以将 CachingIterator 或 SplFileObject 包装到 FilterIterator 中,这将在迭代 csv 数据时限制输出

class BannedEntriesFilter extends FilterIterator
{
    private $bannedEntries = array();

    public function setBannedEntries(array $bannedEntries)
    {
        $this->bannedEntries = $bannedEntries;
    }

    public function accept()
    {
        foreach ($this->current() as $key => $val) {
            return !$this->isBannedEntryInColumn($val, $key);
        }
    }

    public function $isBannedEntryInColumn($entry, $column)
    {
        return isset($this->bannedEntries[$column])
            && in_array($this->bannedEntries[$column], $entry);
    }
}

FilterIterator 将忽略内部 Iterator 中不满足 FilterIterator 的 accept 方法中的测试的所有条目。上面,我们检查 csv 文件中的当前行是否与禁止条目数组匹配,如果匹配,则数据不包含在迭代中。你可以这样使用它:

$filteredCachedFile = new BannedEntriesFilter(
    new ArrayIterator($cachedFile->getCache())
)

由于缓存的结果始终是一个数组,因此我们需要将该数组包装到一个 ArrayIterator 中,然后才能将其包装到我们的 FilterIterator 中。请注意,要使用缓存,您还需要至少迭代一次 CachingIterator。我们只是假设您已经在上面做了。下一步是配置禁止条目

$filteredCachedFile->setBannedEntries(
    array(
        // banned entries for column 0
        array('foo', 'bar'),
        // banned entries for column 1
        array( …
    )
);

我想这很简单。您有一个多维数组,CSV 数据中的每一列都有一个条目,其中包含被禁止的条目。然后您只需遍历该实例,它只会为您提供没有禁止条目的行

foreach ($filteredCachedFile as $row) {
    // do something with filtered rows
}

或者,如果您只想将结果放入数组中:

$results = iterator_to_array($filteredCachedFile);

您可以堆叠多个 FilterIterator 以进一步限制结果。如果您不想为每个过滤都编写一个类,请查看 CallbackFilterIterator,它允许在运行时传递接受逻辑:

$filteredCachedFile = new CallbackFilterIterator(
    new ArrayIterator($cachedFile->getCache()),
    function(array $row) {
        static $bannedEntries = array(
            array('foo', 'bar'),
            …
        );
        foreach ($row as $key => $val) {
            // logic from above returning boolean if match is found
        }
    }
);

关于PHP:以 OOP 方式搜索 CSV 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13249018/

相关文章:

PHP MySQL计算AS不工作

javascript - 生成列表中的 $_GET 在显示页面上未定义

php - 优化在 codeigniter 中进行查询的方式

javascript - 在对象数组中连接数组

javascript - 从 Javascript 中的递归函数返回对象数组

php - 根据另一个下拉列表中的所选值限制日期

oop - 软件开发模式、方法论(敏捷、dsdm 等)和范例(特别是面向对象)之间有什么区别?

Python 过程或面向对象

php - 我们可以在 php 类中定义很多方法吗?

带参数的 Javascript "class"扩展?