oleibman 2f445a1ade Change Hash Code for Worksheet
Fix #4192. Although that issue can be dealt with by changing user code, it would be better to fix it within PhpSpreadsheet. A cloned worksheet may have a pointer to a spreadsheet to which it is not attached. Code can assume it does belong to the spreadsheet, and throw an exception when the spreadsheet cannot find the worksheet in question. It may also not throw an exception when it should.

In my comments to the issue, I was concerned that adding in the needed protection would add overhead to an extremely common situation (setting a cell's value) in order to avoid a pretty rare problem. However, there are problems with both the accuracy and efficiency of the existing code, and I think any performance losses caused by the additional checks will be offset by the performance gains and accuracy of the new code.

Spreadsheet `getIndex` attempts to find the index of a worksheet within its spreadsheet collection. It does so by comparing the hash codes of each sheet in its collection with the hash code of the sheet it is looking for. Its major problem problem is performance-related, namely that it recomputes the hash code of the target sheet with each iteration.

A more severe problem is the accuracy of the hash code. It generates this by hashing together the sheet title, the string range of its auto-filter, and a character representation of whether sheet protection is enabled. Title should definitely be part of the calculation (it must be unique for all sheets attached to a spreadsheet), but it is not clear why this subset of the other properties of Worksheet is used. It tries to save some cycles by using a `dirty` property to indicate whether re-hashing is necessary. It sets that property whenever the title changes, or when `setProtection` is called. So, it doesn't set it when auto-filter changes, and you can easily bypass `setProtection` when changing any of the `Protection` properties. Not to mention the many other properties of worksheet that can be changed. Additionally, if you clone a worksheet, the clone and the original will have the same hash code, which can lead to problems:
```php
$clone = clone $original;
$spreadsheet->getSheet($spreadsheet->getIndex($clone))
    ->setCellValue('A1', 100);
```
That code will change the value of A1 in the original, not the clone.

The `hash` property in Worksheet will now be calculated immediately when the object is constructed or cloned or unserialized. It will not be recalculated, and there is no longer a need for the `dirty` property, which is removed. Hash will be generated by spl_object_id, which was designed for this purpose. (So was spl_object_hash, but many online references suggest that \_id performs much better than \_hash.) Our problem example above will now throw an Exception, as it should, rather than changing the wrong cell. `setValueExplicit`, the problem in the original issue, will now test that the worksheet is attached to the spreadsheet before doing any style manipulation. In order that this not be a breaking change, `getHashCode` will continue to return string, but it is deprecated in favor of `getHashInt`, and Worksheet will no longer implement IComparable to facilitate the deprecation.

I had a vague hope that this change might help with issue #641. It doesn't.
2024-10-30 17:25:49 -07:00
2024-10-30 17:25:49 -07:00

PhpSpreadsheet

Build Status Code Quality Code Coverage Total Downloads Latest Stable Version License Join the chat at https://gitter.im/PHPOffice/PhpSpreadsheet

PhpSpreadsheet is a library written in pure PHP and offers a set of classes that allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc.

Installation

See the install instructions.

Documentation

Read more about it, including install instructions, in the official documentation. Or check out the API documentation.

Please ask your support questions on StackOverflow, or have a quick chat on Gitter.

Patreon

I am now running a Patreon to support the work that I do on PhpSpreadsheet.

Supporters will receive access to articles about working with PhpSpreadsheet, and how to use some of its more advanced features.

Posts already available to Patreon supporters:

  • The Dating Game
    • A look at how MS Excel (and PhpSpreadsheet) handle date and time values.
  • Looping the Loop
    • Advice on Iterating through the rows and cells in a worksheet.

And for Patrons at levels actively using PhpSpreadsheet:

  • Behind the Mask
    • A look at Number Format Masks.

The Next Article (currently Work in Progress):

  • Formula for Success
    • How to debug formulae that don't produce the expected result.

My aim is to post at least one article each month, taking a detailed look at some feature of MS Excel and how to use that feature in PhpSpreadsheet, or on how to perform different activities in PhpSpreadsheet.

Planned posts for the future include topics like:

  • Tables
  • Structured References
  • AutoFiltering
  • Array Formulae
  • Conditional Formatting
  • Data Validation
  • Value Binders
  • Images
  • Charts

After a period of six months exclusive to Patreon supporters, articles will be incorporated into the public documentation for the library.

PHPExcel vs PhpSpreadsheet ?

PhpSpreadsheet is the next version of PHPExcel. It breaks compatibility to dramatically improve the code base quality (namespaces, PSR compliance, use of latest PHP language features, etc.).

Because all efforts have shifted to PhpSpreadsheet, PHPExcel will no longer be maintained. All contributions for PHPExcel, patches and new features, should target PhpSpreadsheet master branch.

Do you need to migrate? There is an automated tool for that.

License

PhpSpreadsheet is licensed under MIT.

Languages
PHP 99.8%
HTML 0.2%