$fichier->eof() retourne toujours false lors de l'utilisation de PHP SplFileObject en " r " à la mode
-
13-12-2019 - |
Question
Pourquoi mon script PHP en suspens?
$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 je supprime la dernière ligne (iterator_count(...
) et de le remplacer par ceci:
$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)
// ...
L' $fileObject->eof()
renvoie toujours false si je reçois une boucle infinie.
Pourquoi ces choses se produire?J'ai besoin d'obtenir un nombre de lignes.
La solution
Pourquoi ces choses se produire?
Vous rencontrez une particularité dans la manière que l' SplFileObject
la classe est écrit.Sans appel next()
et current()
méthodes—l'utilisation de la valeur par défaut (0
) indicateurs—l'itérateur ne jamais se déplace vers l'avant.
L' iterator_count()
la fonction n'appelle jamais current()
;il vérifie valid()
et les appels next()
seulement.Votre sur mesure boucles d'appeler uniquement une ou l'autre de current()
et next()
.
Cela devrait être considéré comme un bug (que ce soit en PHP lui-même, ou une défaillance dans la documentation) et le code suivant devrait (et) ne s'applique pas fonctionner comme prévu.Je vous invite à le rapport présente les débordements.
// NOTE: This currently runs in an infinite loop!
$file = new SplFileObject(__FILE__);
var_dump(iterator_count($file));
Solutions de contournement
Un rapide pas de côté pour faire bouger les choses est de mettre la READ_AHEAD
drapeau sur l'objet.Ce sera la cause de la next()
méthode pour lire la prochaine ligne disponible.
$file->setFlags(SplFileObject::READ_AHEAD);
Si, pour une raison quelconque, vous ne voulez pas le lire à l'avance comportement, alors vous devez appeler à la fois next()
et current()
vous-même.
De retour au problème initial de deux SplFileObjects
La suite devrait maintenant fonctionner comme prévu, permettant l'ajout d'un fichier et la lecture de son nombre de lignes.
<?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));
Autres conseils
ÉDITÉ 01
Si ce que vous avez besoin est le nombre de lignes dans le fichier:
<?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
?>
ÉDITÉ 02
C'est votre code ci-dessus, mais sans entrer dans une boucle infinie en raison du pointeur de fichier:
<?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();
?>
Sorties
Ligne:0 "Foo "
Ligne:1 "Bar"
Nombre De Lignes:2
RÉPONSE ORIGINALE À CETTE QUESTION
De la logique appliquée en était un peu éteint.J'ai simplifié le code:
<?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>";
}
?>
Sorties:
/tmp/EAdklY.txt
Le Fichier Existe:1
Le Contenu Du Fichier:Foo Bar
Ligne:0 Avec:"Foo" est la fin?pas de
Ligne:1 Avec:"Bar ", c'est la fin?pas de
Ligne:2 Avec:"" est-ce la fin?oui
Même si cela peut sembler contre-intuitif, avec PHP 5.3.9, ceci:
<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
$f->next();
}
tout être une boucle infinie, et de ne jamais quitter.
À la suite d'une sortie de, lorsque la fin du fichier est atteinte:
<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
$f->current();
}
Donc:
$i = 0;
$fileObject2->rewind();
while (!$fileObject2->eof()) {
var_dump($fileObject2->eof());
var_dump($i++);
$fileObject2->next();
}
devrait être réécrit comme suit:
$fileObject2->rewind();
while (!$fileObject2->eof()) {
$fileObject2->current();
}
$i = $fileObject2->key();