From 58a5172b8f86a98f1bd700cdfe47ecf7a1fdb8c2 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 23 Feb 2019 10:22:18 +0100 Subject: [PATCH] =?UTF-8?q?Document=20Improvements=20=E2=80=A6=20(#899)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Document calculation caching; and how to disable it and how to flush the cache * Quoted text for string values beginning with `=`, so that they are still treated as strings and not as formulae * Warning about assigning cells to variables * Further warning about assigning cells to variables --- docs/topics/accessing-cells.md | 75 +++++++++++++++++++++++++++++++ docs/topics/calculation-engine.md | 24 ++++++++++ 2 files changed, 99 insertions(+) diff --git a/docs/topics/accessing-cells.md b/docs/topics/accessing-cells.md index f14e2bde..acf361cd 100644 --- a/docs/topics/accessing-cells.md +++ b/docs/topics/accessing-cells.md @@ -34,6 +34,54 @@ $spreadsheet->getActiveSheet() ->setValue('Some value'); ``` +### BEWARE: Cells assigned to variables as a Detached Reference + +As an "in-memory" model, PHPSpreadsheet can be very demanding of memory, +particularly when working with large spreadsheets. One technique used to +reduce this memory overhead is cell caching, so cells are actually +maintained in a collection that may or may not be held in memory while you +are working with the spreadsheet. Because of this, a call to `getCell()` +(or any similar method) returns the cell data, and a pointer to the collection. +While this is not normally an issue, it can become significant +if you assign the result of a call to `getCell()` to a variable. Any +subsequent calls to retrieve other cells will unset that pointer, although +the cell object will still retain its data values. + +What does this mean? Consider the following code: + +``` +$spreadSheet = new Spreadsheet(); +$workSheet = $spreadSheet->getActiveSheet(); + +// Set details for the formula that we want to evaluate, together with any data on which it depends +$workSheet->fromArray( + [1, 2, 3], + null, + 'A1' +); + +$cellC1 = $workSheet->getCell('C1'); +echo 'Value: ', $cellC1->getValue(), '; Address: ', $cellC1->getCoordinate(), PHP_EOL; + +$cellA1 = $workSheet->getCell('A1'); +echo 'Value: ', $cellA1->getValue(), '; Address: ', $cellA1->getCoordinate(), PHP_EOL; + +echo 'Value: ', $cellC1->getValue(), '; Address: ', $cellC1->getCoordinate(), PHP_EOL; +``` + +The call to `getCell('C1')` returns the cell at `C1` containing its value (`3`), +together with its link to the collection (used to identify its +address/coordinate `C1`). The subsequent call to access cell `A1` +modifies the value of `$cellC1`, detaching its link to the collection. + +So when we try to display the value and address a second time, we can display +its value, but trying to display its address/coordinate will throw an +exception because that link has been set to null. + +__Note:__ There are some internal methods that will fetch other cells from the +collection, and this too will detach the link to the collection from any cell +that you might have assigned to a variable. + ## Excel DataTypes MS Excel supports 7 basic datatypes: @@ -86,6 +134,33 @@ Formats handled by the advanced value binder include: You can read more about value binders later in this section of the documentation. +### Setting a formula in a Cell + +As stated above, if you store a string value with the first character an `=` +in a cell. PHPSpreadsheet will treat that value as a formula, and then you +can evaluate that formula by calling `getCalculatedValue()` against the cell. + +There may be times though, when you wish to store a value beginning with `=` +as a string, and that you don't want PHPSpreadsheet to evaluate as though it +was a formula. + +To do this, you need to "escape" the value by setting it as "quoted text". + +``` +// Set cell A4 with a formula +$spreadsheet->getActiveSheet()->setCellValue( + 'A4', + '=IF(A3, CONCATENATE(A1, " ", A2), CONCATENATE(A2, " ", A1))' +); +$spreadsheet->getActiveSheet()->getCell('A4') + ->->getStyle()->setQuotePrefix(true); +``` + +Then, even if you ask PHPSpreadsheet to return the calculated value for cell +`A4`, it will return `=IF(A3, CONCATENATE(A1, " ", A2), CONCATENATE(A2, " ", A1))` +as a string, and not try to evaluate the formula. + + ### Setting a date and/or time value in a cell Date or time values are held as timestamp in Excel (a simple floating diff --git a/docs/topics/calculation-engine.md b/docs/topics/calculation-engine.md index a20b0e33..779d73e1 100644 --- a/docs/topics/calculation-engine.md +++ b/docs/topics/calculation-engine.md @@ -43,6 +43,30 @@ inserted 2 new rows), changed to "SUM(E4:E11)". Also, the inserted cells duplicate style information of the previous cell, just like Excel's behaviour. Note that you can both insert rows and columns. +## Calculation Cache + +Once the Calculation engine has evaluated the formula in a cell, the result +will be cached, so if you call `getCalculatedValue()` a second time for the +same cell, the result will be returned from the cache rather than evaluating +the formula a second time. This helps boost performance, because evaluating +a formula is an expensive operation in terms of performance and speed. + +However, there may be times when you don't want this, perhaps you've changed +the underlying data and need to re-evaluate the same formula with that new +data. + +``` +Calculation::getInstance($spreadsheet)->disableCalculationCache(); +``` + +Will disable calculation caching, and flush the current calculation cache. + +If you want only to flush the cache, then you can call + +``` +Calculation::getInstance($spreadsheet)->clearCalculationCache(); +``` + ## Known limitations There are some known limitations to the PhpSpreadsheet calculation