Repository navigation
Expand file tree
/
Copy pathReader.php
More file actions
131 lines (113 loc) · 2.89 KB
/
Copy pathReader.php
File metadata and controls
131 lines (113 loc) · 2.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
namespace SOB\CSV;
/**
* Base class for a simple CSV reader supporting files, string or streams as input
*
* Emulates an array of records (arrays), implimented as an Iterator, so can be used in a foreach statements.
*
* - If your CSV has headers (the default), then the keys of the returned array will be the header values.
* - You can also specify a different field separator, for example ("\t") for tabs.
* - Use rewind to reset to the top of the file.
* - The header record is NEVER returned as a record. The first iteration will be the first record in the file, excluding the header record if specified.
* - An empty stream will return -1 as the current index.
*
* @implements \Iterator<array<string, string>>
*/
abstract class Reader implements \Iterator
{
/** @var array<string, string> */
private array $current = [];
/** @var array<string> */
private array $headers = [];
private int $index = 0;
/**
* @param ?resource $stream
*/
public function __construct(protected $stream, private readonly bool $headerRow, private readonly string $separator, private string $enclosure, private string $escape)
{
$this->rewind();
}
/** @return array<string, string> */
public function current() : array
{
return $this->current;
}
/**
* @return int index of the record in the CSV stream. Zero is index of first data record. -1 means the CSV stream is empty
*/
public function key() : int
{
return $this->index;
}
/**
* Load the next record in the stream
*/
public function next() : void
{
$this->current = [];
if ($this->stream)
{
$array = \fgetcsv($this->stream, 0, $this->separator, $this->enclosure, $this->escape);
if ($array)
{
++$this->index;
if ($this->headers)
{
foreach ($this->headers as $index => $header)
{
if (isset($array[$index]))
{
$this->current[$header] = $array[$index];
}
else
{
break;
}
}
}
else
{
$this->current = $array; // @phpstan-ignore-line
}
}
}
}
/**
* rewind the reader to the first record
*/
public function rewind() : void
{
$this->index = -1;
$this->open();
if ($this->stream)
{
\rewind($this->stream);
if ($this->headerRow)
{
$this->headers = \fgetcsv($this->stream, 0, $this->separator, $this->enclosure, $this->escape);
}
}
$this->next();
}
/**
* You can specify headers if your file does not include them. The headers will be used as the key in the returned associative array for each record.
*
* @param array<string> $headers of strings
*/
public function setHeaders(array $headers) : static
{
$this->headers = $headers;
return $this;
}
public function valid() : bool
{
return $this->current && $this->stream;
}
/**
* Override the open method to support your data type
*/
protected function open() : static
{
return $this;
}
}