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 calling next()
and current()
methods—using the default (0
) flags—the iterator never moves forward.
The iterator_count()
function never calls current()
; it checks valid()
and calls next()
only. Your bespoke loops only call one or other of current()
and next()
.
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.
// NOTE: This currently runs in an infinite loop!
$file = new SplFileObject(__FILE__);
var_dump(iterator_count($file));
Workarounds
One quick sidestep to get things moving is to set the READ_AHEAD
flag on the object. This will cause the next()
method to read the next available line.
$file->setFlags(SplFileObject::READ_AHEAD);
If, for any reason, you do not want the read ahead behaviour then you must call both next()
and current()
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.
<?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));