{"record":{"id":"c9babf170fb75fc3","repo":"PHPOffice/PhpSpreadsheet","slug":"reader-classes-must-implement-their-own-listworksh","errorCode":null,"errorMessage":"Reader classes must implement their own listWorksheetInfo() method","messagePattern":"Reader classes must implement their own listWorksheetInfo\\(\\) method","errorType":"exception","errorClass":"PhpSpreadsheetException","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Reader/BaseReader.php","lineNumber":321,"sourceCode":"\n            // Open file\n            $fileHandle = fopen($filename, 'rb');\n        }\n        if ($fileHandle === false) {\n            throw new ReaderException('Could not open file ' . $filename . ' for reading.');\n        }\n\n        $this->fileHandle = $fileHandle;\n    }\n\n    /**\n     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).\n     *\n     * @return array<int, array{worksheetName: string, lastColumnLetter: string, lastColumnIndex: int, totalRows: int, totalColumns: int, sheetState: string}>\n     */\n    public function listWorksheetInfo(string $filename): array\n    {\n        throw new PhpSpreadsheetException('Reader classes must implement their own listWorksheetInfo() method');\n    }\n\n    /**\n     * Returns names of the worksheets from a file,\n     * possibly without parsing the whole file to a Spreadsheet object.\n     * Readers will often have a more efficient method with which\n     * they can override this method.\n     *\n     * @return string[]\n     */\n    public function listWorksheetNames(string $filename): array\n    {\n        $returnArray = [];\n        $info = $this->listWorksheetInfo($filename);\n        foreach ($info as $infoArray) {\n            $returnArray[] = $infoArray['worksheetName'];\n        }\n","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Reader/BaseReader.php#L303-L339","documentation":"BaseReader::listWorksheetInfo() is a stub in the template-method style: it returns sheet metadata (name, last column, total rows, ...) only when a concrete reader overrides it. Calling it on a subclass that never implemented it hits the base throw, mirroring loadSpreadsheetFromFile().","triggerScenarios":"A custom BaseReader subclass without an override being passed to UI/reporting code that calls listWorksheetInfo($filename); tooling that enumerates sheet metadata over any IReader implementation.","commonSituations":"Custom readers written only for load(); admin tooling or preview panes that additionally query worksheet info and discover the gap at runtime.","solutions":["Implement public listWorksheetInfo(string $filename): array in the subclass, returning entries shaped per the docblock (worksheetName, lastColumnLetter, lastColumnIndex, totalRows, totalColumns, sheetState)","Or extend a concrete reader whose implementation you can reuse","Guard UI code to skip the info call when the reader does not really implement it (reflection check on the declaring class)"],"exampleFix":"// before\nclass MyReader extends BaseReader { }\n(new MyReader())->listWorksheetInfo('data.foo'); // throws\n\n// after\nclass MyReader extends BaseReader\n{\n    public function listWorksheetInfo(string $filename): array\n    {\n        return [\n            ['worksheetName' => 'Sheet1', 'lastColumnLetter' => 'A', 'lastColumnIndex' => 0,\n             'totalRows' => count(file($filename)), 'totalColumns' => 1, 'sheetState' => 'visible'],\n        ];\n    }\n}","handlingStrategy":"type-guard","validationCode":"$m = new ReflectionMethod($reader, 'listWorksheetInfo');\nif ($m->getDeclaringClass()->getName() === BaseReader::class) {\n    return []; // reader does not really implement sheet info — skip instead of crashing\n}","typeGuard":"function implementsWorksheetInfo(string $readerClass): bool\n{\n    return (new ReflectionMethod($readerClass, 'listWorksheetInfo'))\n        ->getDeclaringClass()->getName() !== BaseReader::class;\n}","tryCatchPattern":null,"preventionTips":["When building custom readers, implement both template methods (load and listWorksheetInfo) from the start","Have UI code degrade gracefully (hide the sheet-metadata panel) when a reader lacks a real info implementation"],"tags":["custom-reader","worksheet-info","base-reader"],"backgroundTag":"unimplemented-abstract-method","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}