philiprehberger / php-csv
Memory-efficient CSV reader and writer with header mapping and type casting
v1.1.1
2026-03-17 20:06 UTC
Requires
- php: ^8.2
Requires (Dev)
- laravel/pint: ^1.0
- phpstan/phpstan: ^1.12|^2.0
- phpunit/phpunit: ^11.0
README
Memory-efficient CSV reader and writer with header mapping and type casting.
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.2 |
Installation
composer require philiprehberger/php-csv
Usage
Reading a CSV file
use PhilipRehberger\Csv\Csv; // Read from file with headers $rows = Csv::read('data.csv')->toArray(); // [['name' => 'Alice', 'age' => '30'], ...] // Read from string $rows = Csv::readString($csvContent)->toArray();
Generator-based iteration
The reader uses PHP generators for memory-efficient processing of large files:
foreach (Csv::read('large-file.csv') as $row) { // Process one row at a time — constant memory usage }
Type casting
Automatically detect and cast value types:
$rows = Csv::read('data.csv') ->castTypes(true) ->toArray(); // "42" -> int, "3.14" -> float, "true"/"false" -> bool, "" -> null
Filtering and mapping
$rows = Csv::read('data.csv') ->castTypes(true) ->filter(fn (array $row) => $row['age'] >= 18) ->map(fn (array $row) => [...$row, 'label' => strtoupper($row['name'])]) ->toArray();
Row Validation
Validate each row during reading. Invalid rows are skipped and errors are collected:
$reader = Csv::read('data.csv') ->validate(fn (array $row) => isset($row['email']) && str_contains($row['email'], '@')); $rows = $reader->toArray(); // Inspect which rows failed validation foreach ($reader->getValidationErrors() as $error) { echo "Row {$error['row']}: {$error['error']}\n"; }
The validator can also throw an exception to provide a specific error message:
$reader = Csv::read('data.csv') ->validate(function (array $row) { if (empty($row['name'])) { throw new \InvalidArgumentException('Name is required'); } return true; });
Progress Tracking
Monitor processing progress with a callback invoked after each row:
Csv::read('large-file.csv') ->withProgress(function (int $rowNumber) { if ($rowNumber % 1000 === 0) { echo "Processed {$rowNumber} rows...\n"; } }) ->each(fn (array $row) => processRow($row));
Custom delimiters
$rows = Csv::readString($tsv) ->delimiter("\t") ->toArray();
Writing CSV
use PhilipRehberger\Csv\Csv; Csv::write('output.csv') ->headers(['name', 'age', 'city']) ->row(['name' => 'Alice', 'age' => 30, 'city' => 'Berlin']) ->row(['name' => 'Bob', 'age' => 25, 'city' => 'Vienna']) ->save(); // Or get as string $csv = Csv::write('') ->headers(['name', 'age']) ->rows($data) ->toString();
Streaming Writer
Write rows directly to disk without buffering, ideal for very large files:
use PhilipRehberger\Csv\Csv; $writer = Csv::streamWrite('large-output.csv'); $writer->writeHeader(['id', 'name', 'value']); foreach ($dataSource as $record) { $writer->writeRow([$record->id, $record->name, $record->value]); } $writer->close();
BOM for Excel
Prepend a UTF-8 BOM for Excel compatibility:
Csv::write('output.csv') ->headers(['name', 'age']) ->rows($data) ->bom(true) ->save();
API
Csv (static entry)
| Method | Description |
|---|---|
Csv::read(string $path): CsvReader |
Create a reader from a file path |
Csv::readString(string $content): CsvReader |
Create a reader from a string |
Csv::write(string $path): CsvWriter |
Create a writer for a file path |
Csv::streamWrite(string $path, string $delimiter = ','): StreamingWriter |
Create a streaming writer for a file path |
CsvReader
| Method | Description |
|---|---|
delimiter(string $char): self |
Set the field delimiter (default ,) |
enclosure(string $char): self |
Set the field enclosure (default ") |
hasHeader(bool $flag): self |
Whether the first row is a header (default true) |
skipEmpty(bool $flag): self |
Skip empty rows (default true) |
castTypes(bool $flag): self |
Auto-detect types: int, float, bool, null |
filter(callable $fn): self |
Filter rows by a predicate |
map(callable $fn): self |
Transform each row |
validate(callable $fn): self |
Validate rows; invalid ones are skipped |
withProgress(callable $fn): self |
Set a progress callback (receives row number) |
getValidationErrors(): array |
Get errors from the last read |
each(callable $fn): void |
Execute a callback for each row |
toArray(): array |
Collect all rows into an array |
count(): int |
Count the number of rows |
CsvWriter
| Method | Description |
|---|---|
headers(array $headers): self |
Set column headers |
row(array $row): self |
Add a single row |
rows(array $rows): self |
Add multiple rows |
delimiter(string $char): self |
Set the field delimiter (default ,) |
bom(bool $flag): self |
Prepend UTF-8 BOM for Excel |
save(): void |
Write to the configured file path |
toString(): string |
Return the CSV as a string |
StreamingWriter
| Method | Description |
|---|---|
writeHeader(array $headers): void |
Write the header row |
writeRow(array $row): void |
Write a single data row |
writeRows(array $rows): void |
Write multiple data rows |
isHeaderWritten(): bool |
Whether the header has been written |
close(): void |
Close the file handle |
Development
composer install vendor/bin/phpunit vendor/bin/pint --test vendor/bin/phpstan analyse
License
MIT