Changes
- Feature: formula calculation. evaluateFormula(string $formula) evaluates an Excel formula and returns its result — operator precedence and arithmetic, cell and range references (A1, A1:A3) resolved against the values already written, aggregates (SUM / AVERAGE / MIN / MAX / COUNT / COUNTA), and logical/text functions (IF, CONCATENATE, UPPER, LEN, ...), with Excel error values (#DIV/0!, #NUM!, ...) surfaced as strings. computeFormula(bool $enable = true) opts the workbook into caching, so insertFormula() writes the computed result into the file and other readers see the value without recalculating.
- Feature: round-trip editing of an existing workbook. openFile() a saved .xlsx and change it in place — cell values, styles, merged ranges, dates and sheet dimensions — add new worksheets, and insert images and charts into the opened workbook, then output() the result. The existing write methods (insertText / insertImage / insertChart / mergeCells / setRow / addSheet, ...) work unchanged in edit mode; unsupported edit operations are now reported instead of being silently dropped.
- Performance: normal-mode (non constant_memory) export is about 27% faster with roughly 18% lower peak memory; the constant_memory streaming path gained an integer fast-path that skips float formatting for whole-number cells.
- Fix: the reader returned 0 for negative or zero decimals read through nextCellCallback (the numeric branch was selected on the sign of the value instead of its parsed type); negative and fractional values now read back correctly.
- Fix: locale independence. Numbers are written and parsed with a '.' decimal point regardless of the host LC_NUMERIC, so using the extension under a ','-decimal locale (for example after setlocale(LC_ALL, 'de_DE')) no longer corrupts written values or misreads cell values, row heights, column widths and font sizes.
- Fix: the formula engine is hardened against malformed or hostile input passed to evaluateFormula — deeply nested or over-long expressions can no longer overflow the stack, and an oversized range aggregate such as SUM(A1:XFD1048576) returns #NUM! instead of hanging.
- Fix: numerous memory-safety and robustness corrections across the reader, the edit path and XML output, including NULL-dereference guards on allocation failure.
- Note: 3.0.0 is a major release — the reader and writer now share a single unified core alongside the new formula and round-trip editing engines above. All existing class methods, signatures and Excel::* / Format::* constant values are unchanged, so upgrading requires no code changes.