转到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
使用了该引用。