回答編集履歴

7

NoRewindIteratorは内側じゃないとダメっぽい

2017/05/27 06:32

投稿

mpyw
mpyw

スコア5223

test CHANGED
@@ -34,9 +34,13 @@
34
34
 
35
35
 
36
36
 
37
+ // Rewindされないようにラップする
38
+
39
+ $it = new NoRewindIterator($file);
40
+
37
41
  // 空行を読み飛ばすようにラップする
38
42
 
39
- $it = new CallbackFilterIterator($file, function ($row) { return $row !== [null]; });
43
+ $it = new CallbackFilterIterator($it, function ($row) { return $row !== [null]; });
40
44
 
41
45
  // $pオフセットから$e件に制限するようにラップする
42
46
 
@@ -44,9 +48,9 @@
44
48
 
45
49
 
46
50
 
47
- // rewindを防ぎながら配列に変換
51
+ // 配列に変換
48
52
 
49
- $records = iterator_to_array(new NoRewindIterator($it));
53
+ $records = iterator_to_array($it);
50
54
 
51
55
 
52
56
 

6

もうちょいシンプルに

2017/05/27 06:32

投稿

mpyw
mpyw

スコア5223

test CHANGED
@@ -38,19 +38,15 @@
38
38
 
39
39
  $it = new CallbackFilterIterator($file, function ($row) { return $row !== [null]; });
40
40
 
41
- // rewindさせないようにラップする
42
-
43
- $it = new NoRewindIterator($it);
44
-
45
41
  // $pオフセットから$e件に制限するようにラップする
46
42
 
47
43
  $it = new LimitIterator($it, $p, $e);
48
44
 
49
45
 
50
46
 
51
- // 配列に変換
47
+ // rewindを防ぎながら配列に変換
52
48
 
53
- $records = iterator_to_array($it);
49
+ $records = iterator_to_array(new NoRewindIterator($it));
54
50
 
55
51
 
56
52
 

5

バグ修正 \(File::READ_AHEADおよびFile::SKIP_EMPTYはHTTP URLに対しては使えない模様\)

2017/05/27 06:28

投稿

mpyw
mpyw

スコア5223

test CHANGED
@@ -28,21 +28,29 @@
28
28
 
29
29
  $file = new File('http://example.com/ttt.txt', 'rb');
30
30
 
31
- $file->setFlags(File::READ_CSV | File::SKIP_EMPTY | File::READ_AHEAD | File::DROP_NEW_LINE); // CSVモード
31
+ $file->setFlags(File::READ_CSV | File::DROP_NEW_LINE); // CSVモード (但し空行読み飛ばしモードは使えない)
32
32
 
33
33
  $file->setCsvControl("\t"); // セパレータをタブ文字に
34
34
 
35
35
 
36
36
 
37
- // SplFileObjectはイテレータでもあが,iterator_to_array適用時に
37
+ // 空行を読み飛ばすようにラップす
38
38
 
39
- // rewind処理が発生してしまうのでNoRewindIteratorでラップする。
39
+ $it = new CallbackFilterIterator($file, function ($row) { return $row !== [null]; });
40
40
 
41
- // 更に,必要部分だけを効率的残せるLimitIteratorでラップする
41
+ // rewindさせいようにラップする
42
42
 
43
- // 最後に配列に変換する。
43
+ $it = new NoRewindIterator($it);
44
44
 
45
+ // $pオフセットから$e件に制限するようにラップする
46
+
45
- $records = iterator_to_array(new LimitIterator(new NoRewindIterator($file), $p, $e));
47
+ $it = new LimitIterator($it, $p, $e);
48
+
49
+
50
+
51
+ // 配列に変換
52
+
53
+ $records = iterator_to_array($it);
46
54
 
47
55
 
48
56
 

4

蛇足

2017/05/27 06:25

投稿

mpyw
mpyw

スコア5223

test CHANGED
@@ -112,4 +112,8 @@
112
112
 
113
113
 
114
114
 
115
- 上記を満たす場合,一時的な配列を生成する必要すらありません。イテレータのままそのまま`foreach`で回してもらって構いません。条件を満たしていないのにやってしまうと,`foreach`ループ中に通信障害が発生したときにHTMLが中途半端な状態でぶっ壊れて出力されてしまうので注意
115
+ 上記を満たす場合,一時的な配列を生成する必要すらありません。イテレータのまま`foreach`で回してもらって構いません。ただし条件を満たしていないのにやってしまうと,`foreach`ループ中に通信障害が発生したときにHTMLが中途半端な状態でぶっ壊れて出力されてしまうので注意
116
+
117
+
118
+
119
+ 一度配列を作る意味としては,「一度作ってしまえば配列は絶対に壊れることが無い」と保証できるからですね。HTTP経由でURLをオープンしているイテレータは不安定なことを意識しなければなりません。

3

蛇足

2017/05/26 14:06

投稿

mpyw
mpyw

スコア5223

test CHANGED
@@ -99,3 +99,17 @@
99
99
  </ul>
100
100
 
101
101
  ```
102
+
103
+
104
+
105
+ 蛇足ですが,
106
+
107
+
108
+
109
+ - [ob_start](http://php.net/manual/ja/function.ob-start.php)を使って出力HTMLのバッファリングを行っている
110
+
111
+ - エラーや例外が発生したときには正常系で使うHTMLのバッファを破棄してエラー用のHTMLに切り替える処理を書いている
112
+
113
+
114
+
115
+ 上記を満たす場合,一時的な配列を生成する必要すらありません。イテレータのままそのまま`foreach`で回してもらって構いません。(条件を満たしていないのにやってしまうと,`foreach`ループ中に通信障害が発生したときにHTMLが中途半端な状態でぶっ壊れて出力されてしまうので注意)

2

LimitIterator使ったほうがよさそう

2017/05/26 14:04

投稿

mpyw
mpyw

スコア5223

test CHANGED
@@ -1,4 +1,8 @@
1
- [PHP: NoRewindIterator - Manual](http://php.net/manual/ja/class.norewinditerator.php) なんてあったんですね,勉強になりました。不可逆なストリームを扱う際には必須ですね。
1
+ [NoRewindIterator](http://php.net/manual/ja/class.norewinditerator.php) なんてあったんですね,勉強になりました。不可逆なストリームを扱う際には必須ですね。
2
+
3
+
4
+
5
+ あと調べていたら[LimitIterator](http://php.net/manual/ja/class.limititerator.php)なるものもあるようです!一度全部配列に変換してから切り取るよりも,部分的にイテレータの段階で読み捨てを行ったほうがメモリ効率が圧倒的にいいので是非こちらで。
2
6
 
3
7
 
4
8
 
@@ -30,11 +34,15 @@
30
34
 
31
35
 
32
36
 
33
- // イテレータを配列変換して切り取り
37
+ // SplFileObjectはイテレータでもあるが,iterator_to_array適用時
34
38
 
35
- // 但し最初にrewind処理が発生してしまうのでNoRewindIteratorでラップする
39
+ // rewind処理が発生してしまうのでNoRewindIteratorでラップする
36
40
 
41
+ // 更に,必要な部分だけを効率的に残せるLimitIteratorでラップする。
42
+
43
+ // 最後に配列に変換する。
44
+
37
- $records = array_slice(iterator_to_array(new NoRewindIterator($file)), $p, $e, true);
45
+ $records = iterator_to_array(new LimitIterator(new NoRewindIterator($file), $p, $e));
38
46
 
39
47
 
40
48
 

1

シングルクオート派

2017/05/26 13:59

投稿

mpyw
mpyw

スコア5223

test CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  // SplFileObjectでURLをオープンする
24
24
 
25
- $file = new File("http://example.com/ttt.txt", 'rb');
25
+ $file = new File('http://example.com/ttt.txt', 'rb');
26
26
 
27
27
  $file->setFlags(File::READ_CSV | File::SKIP_EMPTY | File::READ_AHEAD | File::DROP_NEW_LINE); // CSVモード
28
28