Почему мой скрипт 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) // ...
$fileObject->eof()
всегда возвращает false, поэтому я получаю бесконечный цикл.
Почему все это происходит? Мне нужно получить количество строк.
Почему все это происходит?
Вы испытываете особенность в том, как SplFileObject
класс SplFileObject
. Без вызова методов next()
и current()
с использованием флагов по умолчанию ( 0
) – итератор никогда не продвигается вперед.
Функция iterator_count()
никогда не вызывает current()
; он проверяет valid()
и вызывает next()
. Ваши индивидуальные контуры звонят только по одному или другому из current()
и next()
.
Это должно считаться ошибкой (будь то в самом PHP или сбое в документации), а следующий код должен (и не работает) работать должным образом. Я приглашаю вас сообщить об этом неправильном поведении .
// NOTE: This currently runs in an infinite loop! $file = new SplFileObject(__FILE__); var_dump(iterator_count($file));
обходные
Одним из быстрых шагов для перемещения вещей является установка на READ_AHEAD
флага объекта. Это заставит next()
метод 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));
Если вам нужно количество строк внутри файла:
<?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 ?>
Это ваш код выше, но без ввода бесконечных циклов из-за указателя файла:
<?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
Линия: 0 С: «Foo» – это конец? нет
Линия: 1 С: «Бар» – это конец? нет
Строка: 2 С помощью: «» – это конец? да
Хотя это может показаться контрастным интуитивным, с PHP 5.3.9, это:
<?php $f = new SplFileObject('test.txt', 'r'); while (!$f->eof()) { $f->next(); }
а быть бесконечным циклом и никогда не выходить.
Следующее выйдет, когда будет достигнут конец файла:
<?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();