Reading workbooks
Choose the Right Excel Reading Method
Choose a PHP Excel reading method by the result shape you need: streamed rows, arrays, first-row checks, counts, structured summaries, selected columns, or direct cells.
ReadSession::rows()ReadSession::toArray()ReadSession::first()ReadSession::countRows()ReadSession::hasRows()ReadSession::toStructuredSheetArray()ReadSession::cell()Choose the terminal method from what the application actually needs back.
File size matters, but output shape is the better first question. Avoid materializing rows just because an array is familiar when the workflow only needs a stream, count, first row, or one cell.
rows()Process records incrementally.
toArray()Use native PHP array operations.
first() / hasRows()Stop as soon as the question is answered.
cell()Read an exact worksheet location.
Match the task, return type, and memory behavior before writing the loop.
The terminal call is the contract boundary. After it returns, work with the returned generator, array, scalar, or cell value—not with ReadSession methods.
rows()GeneratorIncrementalUse when the application can handle each row as it arrives.
toArray()arrayRetainedUse for smaller results that genuinely need indexing or PHP array operations.
first()?arrayMinimalStop as soon as the first normalized data row is available.
hasRows()boolMinimalPrefer a Boolean result when existence is the only question.
countRows()intStreaming passUse when the count itself is the required result.
cell("B2")mixedTargetedUse for configuration cells or known workbook positions.
toStructuredSheetArray()arrayRetainedUse when source, empty, skipped, header, and returned counts matter together.
selectColumns() narrows the later read; it does not return rows by itself.
Project the fields you need, then finish with rows(), toArray(), first(), or another terminal method.
Prefer the smallest result shape that still solves the job.
Streaming and collection are both valid. The important part is choosing deliberately and keeping the resulting PHP type obvious in the code.
Stream when records can be handled one at a time.
This avoids retaining the complete returned dataset just to iterate over it.
$processed = 0;
foreach ($session->rows() as $row) {
processRow($row);
$processed++;
}Collect when later logic really needs a native array.
Useful for smaller results that need indexing, sorting, or other array operations.
$rows = $session->toArray();
if ($rows === []) {
return;
}
$firstEmail = $rows[0]['Email'] ?? null;Do not read more data than the question requires.
First-row, existence, count, and direct-cell methods communicate intent better than collecting every row first.
$first = $session->first();
$hasRows = $session->hasRows();
$count = $session->countRows();
$value = $sheet->cell('B2');Use structured output when source and returned counts belong together.
This is useful when row normalization and skipped-row accounting are part of the result contract.
$result = $sheet->toStructuredSheetArray([
'header_row' => 1,
'skip_empty_rows' => true,
'row_format' => 'flat',
]);
$rows = $result['rows'];
$counts = $result['summary']['row_counts'];Test “no data” according to the type the terminal method returns.
There is no universal isEmpty() call after execution. Once a terminal method returns, use the normal PHP check for that returned type.
rows()GeneratorTrack whether the loop yielded, or use hasRows() when a separate existence check is required.
toArray()array$rows === []
first()?array$row === null
hasRows()boolUse the returned Boolean directly.
countRows()int$count === 0
toStructuredSheetArray()array$result["rows"] === []
cell()mixedUse an application-specific null/value check.
Do not stack terminal methods when one pass can answer the workflow.
Calling countRows(), toArray(), and toStructuredSheetArray() in sequence can mean repeated worksheet work. Large-file code should usually gather application counters while processing the primary row stream.