Pregunta

¿Por qué es mi script PHP colgando?

$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

Si puedo borrar la última línea (iterator_count(...) y reemplazarlo con este:

$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)
// ...

El $fileObject->eof() siempre devuelve false, así que conseguir un bucle infinito.

¿Por qué suceden estas cosas?Necesito obtener un número de línea.

¿Fue útil?

Solución

¿Por qué suceden estas cosas?

Usted está experimentando una peculiaridad en la forma en que el SplFileObject la clase está escrito.Sin llamar next() y current() métodos: utilizando el valor predeterminado (0) banderas—el iterador nunca se mueve hacia adelante.

El iterator_count() la función de las llamadas no current();comprueba valid() y llamadas next() sólo.Su medida de bucles sólo llame a uno u otro de current() y next().

Esto debe ser considerado un error (ya sea en PHP, o una falla en la documentación) y el siguiente código debe (y no) funciona como se esperaba.Los invito a el informe de esta mala conducta.

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

Soluciones

Un rápido paso lateral para conseguir que las cosas cambien es establecer la READ_AHEAD la bandera en el objeto.Esto hará que el next() método para leer la siguiente línea disponible.

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

Si, por cualquier razón, usted no desea que el la lectura anticipada comportamiento, a continuación, usted debe llamar a ambos next() y current() a ti mismo.

Volver al problema original de dos SplFileObjects

El siguiente ahora debería funcionar como se espera, lo que permite anexar a un archivo de lectura y su número de línea.

<?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));

Otros consejos

EDITADO 01

Si lo que necesitas es el número de líneas dentro del archivo:

<?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

?>


EDITADO 02

Este es el código de arriba, pero sin entrar en bucles infinitos debido a que el puntero de archivo:

<?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();

?>

Salidas

Línea:0 "Foo "

Línea:1 "Barra"

El Total De Líneas:2



RESPUESTA ORIGINAL

De la lógica aplicada fue un poco apagado.He simplificado el código:

<?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>";
}

?>

Salidas:

/tmp/EAdklY.txt

El Archivo Existe:1

Contenido Del Archivo:Foo Bar

Línea:0 Con:"Foo" es el final?no

Línea:1 Con:"Bar" es el final?no

Línea:2 Con:"" es el final?sí

Si bien puede parecer contra intuitivo, con PHP 5.3.9, este:

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

mientras que ser un bucle infinito, y nunca salir.

El siguiente va a salir, cuando el final del archivo:

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

Así:

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

debe ser reescrita como:

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

$i = $fileObject2->key();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top