0

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を返すため、無限ループになります。

なぜこれらのことが起こっているのですか?行数を取得する必要があります。

4

3 に答える 3

2

なぜこれらのことが起こっているのですか?

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

回避策

物事を動かすための簡単な回避策の1つはREAD_AHEAD、オブジェクトにフラグを設定することです。これにより、next()メソッドは次の使用可能な行を読み取ります。

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

何らかの理由で先読みnext()動作を望まない場合は、両方と自分自身を呼び出す必要がありcurrent()ます。

2つのSplFileObjectの元の問題に戻る

これで、ファイルに追加してその行数を読み取ることができるようになり、期待どおりに機能するはずです。

<?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));
于 2012-07-30T20:31:19.240 に答える
1

編集01

必要なのがファイル内の行数である場合:

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

?>


編集02

これは上記のコードですが、ファイルポインタが原因で無限ループに陥ることはありません。

<?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あり: ""は終わりですか?はい

于 2012-07-29T03:54:20.493 に答える
0

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();
于 2012-07-29T02:58:33.797 に答える