Why is my PHP script hanging?
$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
If I delete the last line (iterator_count(...
) and replace it with this:
$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)
// ...
The $fileObject->eof()
always returns false so I get an infinite loop.
Why are these things happening? I need to get a line count.
Why are these things happening?
You are experiencing a peculiarity in the way that the
SplFileObject
class is written. Without callingnext()
andcurrent()
methods—using the default (0
) flags—the iterator never moves forward.The
iterator_count()
function never callscurrent()
; it checksvalid()
and callsnext()
only. Your bespoke loops only call one or other ofcurrent()
andnext()
.This should be considered a bug (whether in PHP itself, or a failure in the documentation) and the following code should (and does not) work as expected. I invite you to report this misbehaviour.
Workarounds
One quick sidestep to get things moving is to set the
READ_AHEAD
flag on the object. This will cause thenext()
method to read the next available line.If, for any reason, you do not want the read ahead behaviour then you must call both
next()
andcurrent()
yourself.Back to the original problem of two SplFileObjects
The following should now work as you expected, allowing appending to a file and reading its line count.