0

为什么我的 PHP 脚本挂起?

$path = tempnam(sys_get_temp_dir(), '').'.txt';
$fileInfo = new \SplFileInfo($path);
$fileObject = $fileInfo->openFile('a');
$fileObject->fwrite("test line\n");
$fileObject2 = $fileInfo->openFile('r');
var_dump(file_exists($path));          // bool(true)
var_dump(file_get_contents($path));    // string(10) "test line
                                       // "
var_dump(iterator_count($fileObject2)); // Hangs on this

如果我删除最后一行 ( iterator_count(...) 并将其替换为:

$i = 0;
$fileObject2->rewind();
while (!$fileObject2->eof()) {
    var_dump($fileObject2->eof());
    var_dump($i++);
    $fileObject2->next();
}

// Output:
// bool(false)
// int(0)
// bool(false)
// int(1)
// bool(false)
// int(2)
// bool(false)
// int(3)
// bool(false)
// int(4)
// ...

总是返回 false所以$fileObject->eof()我得到一个无限循环。

为什么会发生这些事情?我需要计算行数。

4

3 回答 3

2

为什么会发生这些事情?

您正在经历SplFileObject课程编写方式的特殊性。如果没有调用next() current()方法——使用默认 ( 0) 标志——迭代器永远不会向前移动。

iterator_count()函数从不调用current(); 它只检查valid()和调用next()current()您的定制循环仅调用and中的一个或另一个next()

这应该被认为是一个错误(无论是在 PHP 本身中,还是在文档中的故障),并且以下代码应该(并且不)按预期工作。我邀请您举报这种不当行为

// NOTE: This currently runs in an infinite loop!
$file = new SplFileObject(__FILE__);
var_dump(iterator_count($file));

解决方法

让事情动起来的一个快速回避方法是READ_AHEAD在对象上设置标志。这将导致该next()方法读取下一个可用行。

$file->setFlags(SplFileObject::READ_AHEAD);

如果出于任何原因,您不想要预读行为,那么您必须调用两者next()和您current()自己。

回到原来两个SplFileObjects的问题

以下内容现在应该可以按您的预期工作,允许附加到文件并读取其行数。

<?php
$info = new SplFileInfo(__FILE__);
$write = $info->openFile('a');
$write->fwrite("// new line\n");
$read = $info->openFile('r');
$read->setFlags(SplFileObject::READ_AHEAD);
var_dump(iterator_count($read));
于 2012-07-30T20:31:19.240 回答
1

已编辑 01

如果您需要的是文件内的行数:

<?php

$path = tempnam(sys_get_temp_dir(), '').'.txt';

$fileInfo = new SplFileInfo($path);
$fileObject = $fileInfo->openFile('a+');

$fileObject->fwrite("Foo".PHP_EOL);
$fileObject->fwrite("Bar".PHP_EOL);

echo count(file($path));  // outputs 2

?>


已编辑 02

这是您上面的代码,但由于文件指针而没有进入无限循环:

<?php

$path = tempnam(sys_get_temp_dir(), '').'.txt';

$fileInfo = new SplFileInfo($path);
$fileObject = $fileInfo->openFile('a+');

$fileObject->fwrite("Foo".PHP_EOL);
$fileObject->fwrite("Bar");

foreach($fileObject as $line_num => $line) {
    echo 'Line: '.$line_num.' "'.$line.'"'."<br/>";
}
echo 'Total Lines:' . $fileObject->key();

?>

输出

行:0“Foo”

线:1“酒吧”

总行数:2



原始答案

应用的逻辑有点不对劲。我简化了代码:

<?php

// set path to tmp with random file name
echo $path = tempnam(sys_get_temp_dir(), '').'.txt';
echo "<br/>";

// new object
$fileInfo = new \SplFileInfo($path);

// open to write
$fileObject = $fileInfo->openFile('a');

// write two lines
$fileObject->fwrite("Foo".PHP_EOL);
$fileObject->fwrite("Bar".PHP_EOL);

// open to read
$fileObject2 = $fileInfo->openFile('r');

// output contents
echo "File Exists: " .file_exists($path);
echo "<br/>";
echo "File Contents: " . file_get_contents($path);
echo "<br/>";

// foreach line get line number and line contents 
foreach($fileObject2 as $line_num => $line) {
  echo 'Line: '.$line_num;
  echo ' With: "'.$line.'" is the end? '.($fileObject2->eof()?'yes':'no')."<br>";
}

?>

输出:

/tmp/EAdklY.txt

文件存在:1

文件内容:Foo Bar

Line: 0 With: "Foo" 结束了?不

Line: 1 With: "Bar" 是结束吗?不

行:2 用:“”是结束?是的

于 2012-07-29T03:54:20.493 回答
0

虽然这似乎违反直觉,但在 PHP 5.3.9 中,这是:

<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
    $f->next();
}

while 是一个无限循环,永远不会退出。

当到达文件末尾时,以下内容将退出:

<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
    $f->current();
}

所以:

$i = 0;
$fileObject2->rewind();
while (!$fileObject2->eof()) {
    var_dump($fileObject2->eof());
    var_dump($i++);
    $fileObject2->next();
}

应改写为:

$fileObject2->rewind();
while (!$fileObject2->eof()) {
    $fileObject2->current();
}

$i = $fileObject2->key();
于 2012-07-29T02:58:33.797 回答