PHP - SplFileObject -使用seek()方法时第二行输出错误


PHP - SplFileObject - Wrong output for second line when using seek() method

转到UPDATE查看现在的实际问题。老问题已经解决了第一个答案由伯特彼得斯提交。

老问题:

我有几个文件命名为file.1.txt, file.2.txt, file.3.txt,…我正在使用SplFileObject读取第一个文件,并使用foreach循环迭代其内容:

$file = new SplFileObject("file.1.txt");
foreach ($file as $row) {
  // ...
}

其他文件可能被读取,也可能不被读取,这取决于我正在读取的第一个文件的内容。在所有情况下,应该只有一个其他文件(file.2.txt或file.3.txt)可以在下一步中使用。所以在foreach循环的某个地方有一个if语句来处理这个

所有的文件都有相同的结构,所以问题来了。我不想为读取下一个文件创建新的foreach -因为我写的它可能根本不需要,所以我想使用现有的foreach而不是编写新的foreach。是否有可能用其他文件的内容覆盖$file变量,并只使用一个foreach或任何其他循环来迭代它?例如:

foreach ($file as $row) {
  // ...
  if ($contentContainsSomething) {
    $file = new SplFileObject("file.2.txt");
    // somehow reset foreach to read file.2.txt from start
  }
}

我不喜欢用goto语句来解决这个问题。递归似乎是合适的解决方案,但如果有一种方法可以动态地更改循环中的对象,我更喜欢这种解决方案。

更新:正如"老问题"中提到的,所有使用的文件(file.1.txt, file.2.txt,…)都具有相同的结构,所以这就是为什么我不想编写更多相同的循环和复制代码。相反,我使用了@Danack(由他在SO聊天中建议)的代码,这已经是解决方案的一部分。下面是读取更多文件而不需要任何升级的基本代码:

$path = "file.1.txt";
$whileCounter = 0;
while ($path != null) {
  $file = new SplFileObject($path);
  $file->setFlags(SplFileObject::READ_CSV);
  $file->setCsvControl("'t");
  $path = null;
  foreach ($file as $rowKey => $row) {
    // echo row  }
  $path = "file.2.txt";
  if ($whileCounter > 0) {
    break; // solution to stop loop, just for now
  }
  $whileCounter++;
}

所以这段代码没有任何问题,并按预期输出文件的行。问题是当我想用seek()方法读取下一行文件时,因为我想对附加到下一行的一些信息做出决定。因此,如果我使用seek($rowKey + 1),这有助于我获得下一行数据(当行更改时,我使用$file->current()),然后我调用seek($rowKey)到达前一行,那么下一个文件将输出第一行两次,第二行将丢失。第三行和之后的所有打印都很好。这是用下面的代码实现的问题:

$path = "file.1.txt";
$whileCounter = 0;
while ($path != null) {
  $file = new SplFileObject($path);
  $file->setFlags(SplFileObject::READ_CSV);
  $file->setCsvControl("'t");
  $path = null;
  foreach ($file as $rowKey => $row) {
    if ($whileCounter > 0) {
      var_dump($row);
      echo "<br>";
    }
    $file->seek($rowKey + 1);
    if ($file->valid()) {
      $file->seek($rowKey);
    } else {
      var_dump($row);
      echo "<br>";
      $path = "file.2.txt";
    }
  }
  $whileCounter++;
}

如果您应用自定义.csv文件(至少有5行非空行)而不是file.1.txt和file.2.txt,您将看到第二个和第三个输出是相同的(第二个和第三个输出是file.2.txt的第一行和"第二"行)。这里有什么问题吗?

没有。Foreach在$file变量上使用迭代器,即使更改了$file的值,该迭代器仍然有效。

或者,换句话说,foreach将继续查看$file之前的内容,不管你之后对它做什么。这是因为$file实际上不是SplFileObject,而是对它的引用,而foreach使用了该引用。