Eliminate Some Scrutinizer 'Major' Problems (#3109)
Almost all of these are handled through annotations. This shouldn't be our "go-to" solution, but it becomes necessary because Scrutinizer's analysis is often incorrect. Here is a typical example, from Cells.php.
```php
if ($this->currentCellIsDirty && isset($this->currentCoordinate, $this->currentCell)) {
$this->currentCell->detach();
```
Scrutinizer complains that `$this->currentCell` can be null here, but the `isset` condition guarantees that it must be non-null. Perhaps Scrutinizer is worried that `isset` might be overridden, and will accept only an explicit equality test for null for each of the isset arguments. Changing the code to do this seems riskier than just adding the annotation.
A far more common, and more frustrating, example is:
```php
foreach ($simpleXmlElement as $element) {
var_dump($element->method());
}
```
Scrutinizer complains that element might be null. I don't think it can. I have previously added code in places to eliminate the objection, and that may be a practical solution when `$element` is used many times in the loop. But, when it's used only once, annotating the objection away seems like a better solution (less overhead, clearer code). Many of the changes in this PR fall into this category.
This commit is contained in:
parent
befbc564f4
commit
31d0a2e9f9
|
|
@ -1966,18 +1966,6 @@ parameters:
|
||||||
message: "#^Parameter \\#1 \\$underline of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Font\\:\\:mapUnderline\\(\\) expects string, string\\|null given\\.$#"
|
message: "#^Parameter \\#1 \\$underline of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Font\\:\\:mapUnderline\\(\\) expects string, string\\|null given\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: src/PhpSpreadsheet/Writer/Xls/Font.php
|
path: src/PhpSpreadsheet/Writer/Xls/Font.php
|
||||||
-
|
|
||||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:advance\\(\\) has no return type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Writer/Xls/Parser.php
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$spreadsheet has no type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Writer/Xls/Parser.php
|
|
||||||
-
|
|
||||||
message: "#^Unreachable statement \\- code above always terminates\\.$#"
|
|
||||||
count: 5
|
|
||||||
path: src/PhpSpreadsheet/Writer/Xls/Parser.php
|
|
||||||
-
|
-
|
||||||
message: "#^Cannot access offset 'encoding' on array\\|false\\.$#"
|
message: "#^Cannot access offset 'encoding' on array\\|false\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class Exception extends PhpSpreadsheetException
|
||||||
* @param mixed $line
|
* @param mixed $line
|
||||||
* @param mixed $context
|
* @param mixed $context
|
||||||
*/
|
*/
|
||||||
public static function errorHandlerCallback($code, $string, $file, $line, $context): void
|
public static function errorHandlerCallback($code, $string, $file, $line, /** @scrutinizer ignore-unused */ $context): void
|
||||||
{
|
{
|
||||||
$e = new self($string, $code);
|
$e = new self($string, $code);
|
||||||
$e->line = $line;
|
$e->line = $line;
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,7 @@ class Cells
|
||||||
private function storeCurrentCell(): void
|
private function storeCurrentCell(): void
|
||||||
{
|
{
|
||||||
if ($this->currentCellIsDirty && isset($this->currentCoordinate, $this->currentCell)) {
|
if ($this->currentCellIsDirty && isset($this->currentCoordinate, $this->currentCell)) {
|
||||||
$this->currentCell->detach();
|
$this->currentCell->/** @scrutinizer ignore-call */ detach();
|
||||||
|
|
||||||
$stored = $this->cache->set($this->cachePrefix . $this->currentCoordinate, $this->currentCell);
|
$stored = $this->cache->set($this->cachePrefix . $this->currentCoordinate, $this->currentCell);
|
||||||
if ($stored === false) {
|
if ($stored === false) {
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ class Gnumeric extends BaseReader
|
||||||
// name in line with the formula, not the reverse
|
// name in line with the formula, not the reverse
|
||||||
$this->spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);
|
$this->spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);
|
||||||
|
|
||||||
$visibility = $sheetOrNull->attributes()['Visibility'] ?? 'GNM_SHEET_VISIBILITY_VISIBLE';
|
$visibility = $sheet->attributes()['Visibility'] ?? 'GNM_SHEET_VISIBILITY_VISIBLE';
|
||||||
if ((string) $visibility !== 'GNM_SHEET_VISIBILITY_VISIBLE') {
|
if ((string) $visibility !== 'GNM_SHEET_VISIBILITY_VISIBLE') {
|
||||||
$this->spreadsheet->getActiveSheet()->setSheetState(Worksheet::SHEETSTATE_HIDDEN);
|
$this->spreadsheet->getActiveSheet()->setSheetState(Worksheet::SHEETSTATE_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ class Styles
|
||||||
private function readStyles(SimpleXMLElement $styleRegion, int $maxRow, int $maxCol): void
|
private function readStyles(SimpleXMLElement $styleRegion, int $maxRow, int $maxCol): void
|
||||||
{
|
{
|
||||||
foreach ($styleRegion as $style) {
|
foreach ($styleRegion as $style) {
|
||||||
|
/** @scrutinizer ignore-call */
|
||||||
$styleAttributes = $style->attributes();
|
$styleAttributes = $style->attributes();
|
||||||
if ($styleAttributes !== null && ($styleAttributes['startRow'] <= $maxRow) && ($styleAttributes['startCol'] <= $maxCol)) {
|
if ($styleAttributes !== null && ($styleAttributes['startRow'] <= $maxRow) && ($styleAttributes['startCol'] <= $maxCol)) {
|
||||||
$cellRange = $this->readStyleRange($styleAttributes, $maxCol, $maxRow);
|
$cellRange = $this->readStyleRange($styleAttributes, $maxCol, $maxRow);
|
||||||
|
|
@ -117,7 +118,7 @@ class Styles
|
||||||
if ($this->readDataOnly === false && $styleAttributes !== null) {
|
if ($this->readDataOnly === false && $styleAttributes !== null) {
|
||||||
// If readDataOnly is false, we set all formatting information
|
// If readDataOnly is false, we set all formatting information
|
||||||
$styleArray['numberFormat']['formatCode'] = $formatCode;
|
$styleArray['numberFormat']['formatCode'] = $formatCode;
|
||||||
$styleArray = $this->readStyle($styleArray, $styleAttributes, $style);
|
$styleArray = $this->readStyle($styleArray, $styleAttributes, /** @scrutinizer ignore-type */ $style);
|
||||||
}
|
}
|
||||||
$this->spreadsheet->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray);
|
$this->spreadsheet->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray);
|
||||||
}
|
}
|
||||||
|
|
@ -268,10 +269,12 @@ class Styles
|
||||||
$this->addBorderStyle($srssb, $styleArray, 'right');
|
$this->addBorderStyle($srssb, $styleArray, 'right');
|
||||||
$this->addBorderDiagonal($srssb, $styleArray);
|
$this->addBorderDiagonal($srssb, $styleArray);
|
||||||
}
|
}
|
||||||
|
// TO DO
|
||||||
|
/*
|
||||||
if (isset($style->Style->HyperLink)) {
|
if (isset($style->Style->HyperLink)) {
|
||||||
// TO DO
|
|
||||||
$hyperlink = $style->Style->HyperLink->attributes();
|
$hyperlink = $style->Style->HyperLink->attributes();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return $styleArray;
|
return $styleArray;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ class Ods extends BaseReader
|
||||||
if ($zip->open($filename) === true) {
|
if ($zip->open($filename) === true) {
|
||||||
// check if it is an OOXML archive
|
// check if it is an OOXML archive
|
||||||
$stat = $zip->statName('mimetype');
|
$stat = $zip->statName('mimetype');
|
||||||
if ($stat && ($stat['size'] <= 255)) {
|
if (!empty($stat) && ($stat['size'] <= 255)) {
|
||||||
$mimeType = $zip->getFromName($stat['name']);
|
$mimeType = $zip->getFromName($stat['name']);
|
||||||
} elseif ($zip->statName('META-INF/manifest.xml')) {
|
} elseif ($zip->statName('META-INF/manifest.xml')) {
|
||||||
$xml = simplexml_load_string(
|
$xml = simplexml_load_string(
|
||||||
|
|
@ -64,6 +64,7 @@ class Ods extends BaseReader
|
||||||
if (isset($namespacesContent['manifest'])) {
|
if (isset($namespacesContent['manifest'])) {
|
||||||
$manifest = $xml->children($namespacesContent['manifest']);
|
$manifest = $xml->children($namespacesContent['manifest']);
|
||||||
foreach ($manifest as $manifestDataSet) {
|
foreach ($manifest as $manifestDataSet) {
|
||||||
|
/** @scrutinizer ignore-call */
|
||||||
$manifestAttributes = $manifestDataSet->attributes($namespacesContent['manifest']);
|
$manifestAttributes = $manifestDataSet->attributes($namespacesContent['manifest']);
|
||||||
if ($manifestAttributes && $manifestAttributes->{'full-path'} == '/') {
|
if ($manifestAttributes && $manifestAttributes->{'full-path'} == '/') {
|
||||||
$mimeType = (string) $manifestAttributes->{'media-type'};
|
$mimeType = (string) $manifestAttributes->{'media-type'};
|
||||||
|
|
@ -311,7 +312,7 @@ class Ods extends BaseReader
|
||||||
|
|
||||||
// Check loadSheetsOnly
|
// Check loadSheetsOnly
|
||||||
if (
|
if (
|
||||||
isset($this->loadSheetsOnly)
|
$this->loadSheetsOnly !== null
|
||||||
&& $worksheetName
|
&& $worksheetName
|
||||||
&& !in_array($worksheetName, $this->loadSheetsOnly)
|
&& !in_array($worksheetName, $this->loadSheetsOnly)
|
||||||
) {
|
) {
|
||||||
|
|
@ -507,7 +508,7 @@ class Ods extends BaseReader
|
||||||
|
|
||||||
$dataValue = Date::PHPToExcel(
|
$dataValue = Date::PHPToExcel(
|
||||||
strtotime(
|
strtotime(
|
||||||
'01-01-1970 ' . implode(':', sscanf($timeValue, 'PT%dH%dM%dS') ?? [])
|
'01-01-1970 ' . implode(':', /** @scrutinizer ignore-type */ sscanf($timeValue, 'PT%dH%dM%dS') ?? [])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$formatting = NumberFormat::FORMAT_DATE_TIME4;
|
$formatting = NumberFormat::FORMAT_DATE_TIME4;
|
||||||
|
|
@ -693,6 +694,7 @@ class Ods extends BaseReader
|
||||||
|
|
||||||
// Multiple spaces?
|
// Multiple spaces?
|
||||||
/** @var DOMAttr $cAttr */
|
/** @var DOMAttr $cAttr */
|
||||||
|
/** @scrutinizer ignore-call */
|
||||||
$cAttr = $child->attributes->getNamedItem('c');
|
$cAttr = $child->attributes->getNamedItem('c');
|
||||||
$multiplier = self::getMultiplier($cAttr);
|
$multiplier = self::getMultiplier($cAttr);
|
||||||
$str .= str_repeat(' ', $multiplier);
|
$str .= str_repeat(' ', $multiplier);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class Properties
|
||||||
foreach ($officeProperty as $officePropertyData) {
|
foreach ($officeProperty as $officePropertyData) {
|
||||||
// @var \SimpleXMLElement $officePropertyData
|
// @var \SimpleXMLElement $officePropertyData
|
||||||
if (isset($namespacesMeta['dc'])) {
|
if (isset($namespacesMeta['dc'])) {
|
||||||
|
/** @scrutinizer ignore-call */
|
||||||
$officePropertiesDC = $officePropertyData->children($namespacesMeta['dc']);
|
$officePropertiesDC = $officePropertyData->children($namespacesMeta['dc']);
|
||||||
$this->setCoreProperties($docProps, $officePropertiesDC);
|
$this->setCoreProperties($docProps, $officePropertiesDC);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ class Border extends Supervisor
|
||||||
/** @var Style */
|
/** @var Style */
|
||||||
$parent = $this->parent;
|
$parent = $this->parent;
|
||||||
|
|
||||||
return $parent->getStyleArray([$this->parentPropertyName => $array]);
|
return $parent->/** @scrutinizer ignore-call */ getStyleArray([$this->parentPropertyName => $array]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ class Color extends Supervisor
|
||||||
/** @var Style */
|
/** @var Style */
|
||||||
$parent = $this->parent;
|
$parent = $this->parent;
|
||||||
|
|
||||||
return $parent->getStyleArray([$this->parentPropertyName => $array]);
|
return $parent->/** @scrutinizer ignore-call */ getStyleArray([$this->parentPropertyName => $array]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
||||||
|
|
||||||
use Iterator;
|
use Iterator as NativeIterator;
|
||||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||||
use PhpOffice\PhpSpreadsheet\Collection\Cells;
|
use PhpOffice\PhpSpreadsheet\Collection\Cells;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template TKey
|
* @template TKey
|
||||||
*
|
*
|
||||||
* @implements Iterator<TKey, Cell>
|
* @implements NativeIterator<TKey, Cell>
|
||||||
*/
|
*/
|
||||||
abstract class CellIterator implements Iterator
|
abstract class CellIterator implements NativeIterator
|
||||||
{
|
{
|
||||||
public const TREAT_NULL_VALUE_AS_EMPTY_CELL = 1;
|
public const TREAT_NULL_VALUE_AS_EMPTY_CELL = 1;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ class Column
|
||||||
$cellIterator = $this->getCellIterator();
|
$cellIterator = $this->getCellIterator();
|
||||||
$cellIterator->setIterateOnlyExistingCells(true);
|
$cellIterator->setIterateOnlyExistingCells(true);
|
||||||
foreach ($cellIterator as $cell) {
|
foreach ($cellIterator as $cell) {
|
||||||
|
/** @scrutinizer ignore-call */
|
||||||
$value = $cell->getValue();
|
$value = $cell->getValue();
|
||||||
if ($value === null && $nullValueCellIsEmpty === true) {
|
if ($value === null && $nullValueCellIsEmpty === true) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
||||||
|
|
||||||
use Iterator;
|
use Iterator as NativeIterator;
|
||||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||||
use PhpOffice\PhpSpreadsheet\Exception;
|
use PhpOffice\PhpSpreadsheet\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @implements Iterator<string, Column>
|
* @implements NativeIterator<string, Column>
|
||||||
*/
|
*/
|
||||||
class ColumnIterator implements Iterator
|
class ColumnIterator implements NativeIterator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Worksheet to iterate.
|
* Worksheet to iterate.
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ class Row
|
||||||
$cellIterator = $this->getCellIterator();
|
$cellIterator = $this->getCellIterator();
|
||||||
$cellIterator->setIterateOnlyExistingCells(true);
|
$cellIterator->setIterateOnlyExistingCells(true);
|
||||||
foreach ($cellIterator as $cell) {
|
foreach ($cellIterator as $cell) {
|
||||||
|
/** @scrutinizer ignore-call */
|
||||||
$value = $cell->getValue();
|
$value = $cell->getValue();
|
||||||
if ($value === null && $nullValueCellIsEmpty === true) {
|
if ($value === null && $nullValueCellIsEmpty === true) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
||||||
|
|
||||||
use Iterator;
|
use Iterator as NativeIterator;
|
||||||
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @implements Iterator<int, Row>
|
* @implements NativeIterator<int, Row>
|
||||||
*/
|
*/
|
||||||
class RowIterator implements Iterator
|
class RowIterator implements NativeIterator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Worksheet to iterate.
|
* Worksheet to iterate.
|
||||||
|
|
|
||||||
|
|
@ -469,6 +469,7 @@ class Parser
|
||||||
'BAHTTEXT' => [368, 1, 0, 0],
|
'BAHTTEXT' => [368, 1, 0, 0],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** @var Spreadsheet */
|
||||||
private $spreadsheet;
|
private $spreadsheet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -752,6 +753,8 @@ class Parser
|
||||||
throw new WriterException('Defined Name is too long');
|
throw new WriterException('Defined Name is too long');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new WriterException('Cannot yet write formulae with defined names to Xls');
|
||||||
|
/*
|
||||||
$nameReference = 1;
|
$nameReference = 1;
|
||||||
foreach ($this->spreadsheet->getDefinedNames() as $definedName) {
|
foreach ($this->spreadsheet->getDefinedNames() as $definedName) {
|
||||||
if ($name === $definedName->getName()) {
|
if ($name === $definedName->getName()) {
|
||||||
|
|
@ -762,9 +765,9 @@ class Parser
|
||||||
|
|
||||||
$ptgRef = pack('Cvxx', $this->ptg['ptgName'], $nameReference);
|
$ptgRef = pack('Cvxx', $this->ptg['ptgName'], $nameReference);
|
||||||
|
|
||||||
throw new WriterException('Cannot yet write formulae with defined names to Xls');
|
|
||||||
|
|
||||||
return $ptgRef;
|
return $ptgRef;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -965,7 +968,7 @@ class Parser
|
||||||
/**
|
/**
|
||||||
* Advance to the next valid token.
|
* Advance to the next valid token.
|
||||||
*/
|
*/
|
||||||
private function advance()
|
private function advance(): void
|
||||||
{
|
{
|
||||||
$token = '';
|
$token = '';
|
||||||
$i = $this->currentCharacter;
|
$i = $this->currentCharacter;
|
||||||
|
|
@ -995,7 +998,7 @@ class Parser
|
||||||
$this->currentCharacter = $i + 1;
|
$this->currentCharacter = $i + 1;
|
||||||
$this->currentToken = $token;
|
$this->currentToken = $token;
|
||||||
|
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($i < ($formula_length - 2)) {
|
if ($i < ($formula_length - 2)) {
|
||||||
|
|
@ -1035,7 +1038,6 @@ class Parser
|
||||||
case '%':
|
case '%':
|
||||||
return $token;
|
return $token;
|
||||||
|
|
||||||
break;
|
|
||||||
case '>':
|
case '>':
|
||||||
if ($this->lookAhead === '=') { // it's a GE token
|
if ($this->lookAhead === '=') { // it's a GE token
|
||||||
break;
|
break;
|
||||||
|
|
@ -1043,7 +1045,6 @@ class Parser
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
|
|
||||||
break;
|
|
||||||
case '<':
|
case '<':
|
||||||
// it's a LE or a NE token
|
// it's a LE or a NE token
|
||||||
if (($this->lookAhead === '=') || ($this->lookAhead === '>')) {
|
if (($this->lookAhead === '=') || ($this->lookAhead === '>')) {
|
||||||
|
|
@ -1052,7 +1053,6 @@ class Parser
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// if it's a reference A1 or $A$1 or $A1 or A$1
|
// if it's a reference A1 or $A$1 or $A1 or A$1
|
||||||
if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?\d+$/', $token) && !preg_match('/\d/', $this->lookAhead) && ($this->lookAhead !== ':') && ($this->lookAhead !== '.') && ($this->lookAhead !== '!')) {
|
if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?\d+$/', $token) && !preg_match('/\d/', $this->lookAhead) && ($this->lookAhead !== ':') && ($this->lookAhead !== '.') && ($this->lookAhead !== '!')) {
|
||||||
|
|
@ -1278,7 +1278,8 @@ class Parser
|
||||||
*/
|
*/
|
||||||
private function fact()
|
private function fact()
|
||||||
{
|
{
|
||||||
if ($this->currentToken === '(') {
|
$currentToken = $this->currentToken;
|
||||||
|
if ($currentToken === '(') {
|
||||||
$this->advance(); // eat the "("
|
$this->advance(); // eat the "("
|
||||||
$result = $this->parenthesizedExpression();
|
$result = $this->parenthesizedExpression();
|
||||||
if ($this->currentToken !== ')') {
|
if ($this->currentToken !== ')') {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue