Skip to content

Commit da9cec7

Browse files
authored
Add PHPStan static analysis at level 0, minimal fixes (#42)
1 parent 294b650 commit da9cec7

File tree

8 files changed

+93
-31
lines changed

8 files changed

+93
-31
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
6060
- name: Install dependencies
6161
run: |
62-
composer remove --no-update --dev friendsofphp/php-cs-fixer
62+
composer remove --no-update --dev friendsofphp/php-cs-fixer phpstan/phpstan
6363
composer install --no-interaction --prefer-dist --no-progress
6464
6565
- name: Lint code
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Static Analysis
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
- master
9+
10+
jobs:
11+
phpstan:
12+
name: PHPStan
13+
runs-on: ubuntu-latest
14+
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
php-version:
19+
- '8.2'
20+
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
25+
- name: Setup PHP
26+
uses: shivammathur/setup-php@v2
27+
with:
28+
php-version: ${{ matrix.php-version }}
29+
coverage: none
30+
31+
- name: Get composer cache directory
32+
id: composer-cache
33+
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_ENV
34+
35+
- name: Cache dependencies
36+
uses: actions/cache@v4
37+
with:
38+
path: ${{ env.dir }}
39+
key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('**/composer.json') }}
40+
restore-keys: |
41+
composer-${{ runner.os }}-${{ matrix.php-version }}-
42+
composer-${{ runner.os }}-
43+
44+
- name: Install dependencies
45+
run: composer install --prefer-dist --no-progress --no-suggest
46+
47+
- name: Run PHPStan
48+
run: vendor/bin/phpstan analyse

Spreadsheet/Excel/Writer/Parser.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,12 @@ protected function _initializeHashes()
249249
'ptgRefN' => 0x2C,
250250
'ptgAreaN' => 0x2D,
251251
'ptgMemAreaN' => 0x2E,
252-
'ptgMemNoMemN' => 0x2F,
252+
// 'ptgMemNoMemN' => 0x2F, // Overwritten by 0x6F
253253
'ptgNameX' => 0x39,
254254
'ptgRef3d' => 0x3A,
255255
'ptgArea3d' => 0x3B,
256256
'ptgRefErr3d' => 0x3C,
257-
'ptgAreaErr3d' => 0x3D,
257+
// 'ptgAreaErr3d' => 0x3D, // Overwritten by 0x7D
258258
'ptgArrayV' => 0x40,
259259
'ptgFuncV' => 0x41,
260260
'ptgFuncVarV' => 0x42,
@@ -263,20 +263,20 @@ protected function _initializeHashes()
263263
'ptgAreaV' => 0x45,
264264
'ptgMemAreaV' => 0x46,
265265
'ptgMemErrV' => 0x47,
266-
'ptgMemNoMemV' => 0x48,
266+
// 'ptgMemNoMemV' => 0x48, // Duplicate of 0x28 (ptgMemNoMem) in Excel spec
267267
'ptgMemFuncV' => 0x49,
268268
'ptgRefErrV' => 0x4A,
269269
'ptgAreaErrV' => 0x4B,
270270
'ptgRefNV' => 0x4C,
271271
'ptgAreaNV' => 0x4D,
272272
'ptgMemAreaNV' => 0x4E,
273-
'ptgMemNoMemN' => 0x4F,
273+
// 'ptgMemNoMemN' => 0x4F, // Overwritten by 0x6F
274274
'ptgFuncCEV' => 0x58,
275275
'ptgNameXV' => 0x59,
276276
'ptgRef3dV' => 0x5A,
277277
'ptgArea3dV' => 0x5B,
278278
'ptgRefErr3dV' => 0x5C,
279-
'ptgAreaErr3d' => 0x5D,
279+
// 'ptgAreaErr3d' => 0x5D, // Duplicate of 0x3D
280280
'ptgArrayA' => 0x60,
281281
'ptgFuncA' => 0x61,
282282
'ptgFuncVarA' => 0x62,
@@ -285,7 +285,7 @@ protected function _initializeHashes()
285285
'ptgAreaA' => 0x65,
286286
'ptgMemAreaA' => 0x66,
287287
'ptgMemErrA' => 0x67,
288-
'ptgMemNoMemA' => 0x68,
288+
// 'ptgMemNoMemA' => 0x68, // Duplicate of 0x28 (ptgMemNoMem) in Excel spec
289289
'ptgMemFuncA' => 0x69,
290290
'ptgRefErrA' => 0x6A,
291291
'ptgAreaErrA' => 0x6B,
@@ -671,6 +671,8 @@ protected function _convertFunction($token, $num_args)
671671
if ($args == -1) {
672672
return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]);
673673
}
674+
675+
throw new \InvalidArgumentException("Invalid argument count $args for function $token");
674676
}
675677

676678
/**

Spreadsheet/Excel/Writer/Worksheet.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ public function getData($cleanup = true)
754754
// Return data stored in memory
755755
if (isset($this->_data)) {
756756
$tmp = $this->_data;
757-
unset($this->_data);
757+
$this->_data = null;
758758
if ($this->_using_tmpfile) {
759759
fseek($this->_filehandle, 0);
760760
}
@@ -3679,4 +3679,4 @@ protected function _storeDataValidity()
36793679
$this->_append($header . $dv);
36803680
}
36813681
}
3682-
}
3682+
}

composer.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@
3838
"require-dev": {
3939
"friendsofphp/php-cs-fixer": "^3.64",
4040
"php-coveralls/php-coveralls": "^2.2",
41+
"php-parallel-lint/php-parallel-lint": "^1.4",
42+
"phpstan/phpstan": "^2.1",
4143
"phpunit/phpunit": ">=5 <10",
42-
"sanmai/phpunit-legacy-adapter": "^6 || ^8",
43-
"php-parallel-lint/php-parallel-lint": "^1.4"
44+
"sanmai/phpunit-legacy-adapter": "^6 || ^8"
4445
},
4546
"autoload": {
4647
"psr-0": {
@@ -60,5 +61,8 @@
6061
"support": {
6162
"issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Spreadsheet_Excel_Writer",
6263
"source": "https://github.com/pear/Spreadsheet_Excel_Writer"
64+
},
65+
"config": {
66+
"sort-packages": true
6367
}
6468
}

phpstan.neon

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
parameters:
2+
level: 0
3+
paths:
4+
- Spreadsheet
5+
ignoreErrors:
6+
-
7+
message: '#Method .*_substituteCellref.* should return array but return statement is missing#'
8+
path: Spreadsheet/Excel/Writer/Worksheet.php

test/Test/Spreadsheet/Excel/Writer/ParserTest.php

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,25 @@ public function testConvertFunctionReturnsValue()
1515
{
1616
$parser = new Spreadsheet_Excel_Writer_Parser(0, 0x0500);
1717

18-
// Access protected method via reflection
1918
$method = new \ReflectionMethod($parser, '_convertFunction');
2019
$method->setAccessible(true);
2120

22-
// Test with a function that has fixed args (should return early)
23-
// TIME has 3 fixed arguments
21+
// Fixed args (TIME=3) should return without issue
2422
$result = $method->invoke($parser, 'TIME', 3);
2523
$this->assertNotEmpty($result);
2624
$this->assertTrue(is_string($result));
2725

28-
// Test variable args path - SUM has variable args
26+
// Variable args (SUM=-1) should return without issue
2927
$result = $method->invoke($parser, 'SUM', 2);
3028
$this->assertNotEmpty($result);
3129
$this->assertTrue(is_string($result));
30+
31+
// Array structure: [function_number, arg_count, unknown, volatile_flag]
32+
$parser->_functions['INVALID'] = array(999, -2, 0, 0); // -2 is not valid
33+
34+
$this->expectException(\InvalidArgumentException::class);
35+
$this->expectExceptionMessage('Invalid argument count -2 for function INVALID');
36+
$method->invoke($parser, 'INVALID', 1);
3237
}
3338

3439
/**
@@ -46,27 +51,19 @@ public function testDuplicatePtgValues()
4651
{
4752
$parser = new Spreadsheet_Excel_Writer_Parser(0, 0x0500);
4853

49-
// Access protected property via reflection
5054
$property = new \ReflectionProperty($parser, 'ptg');
5155
$property->setAccessible(true);
5256
$ptg = $property->getValue($parser);
5357

54-
// Test ptgMemNoMemN - should have the LAST duplicate value
55-
// Original duplicates: 0x2F (commented), 0x4F (commented), 0x6F (active)
56-
$this->assertArrayHasKey('ptgMemNoMemN', $ptg,
57-
'ptgMemNoMemN key should exist in ptg array');
58-
$this->assertSame(0x6F, $ptg['ptgMemNoMemN'],
59-
'ptgMemNoMemN should be 0x6F (the last duplicate), not 0x2F or 0x4F');
58+
// ptgMemNoMemN: last duplicate at 0x6F wins (0x2F, 0x4F were overwritten)
59+
$this->assertArrayHasKey('ptgMemNoMemN', $ptg);
60+
$this->assertSame(0x6F, $ptg['ptgMemNoMemN']);
6061

61-
// Test ptgAreaErr3d - should have the LAST duplicate value
62-
// Original duplicates: 0x3D (commented), 0x5D (commented), 0x7D (active)
63-
$this->assertArrayHasKey('ptgAreaErr3d', $ptg,
64-
'ptgAreaErr3d key should exist in ptg array');
65-
$this->assertSame(0x7D, $ptg['ptgAreaErr3d'],
66-
'ptgAreaErr3d should be 0x7D (the last duplicate), not 0x3D or 0x5D');
62+
// ptgAreaErr3d: last duplicate at 0x7D wins (0x3D, 0x5D were overwritten)
63+
$this->assertArrayHasKey('ptgAreaErr3d', $ptg);
64+
$this->assertSame(0x7D, $ptg['ptgAreaErr3d']);
6765

68-
// Verify that ptgMemNoMem exists with value 0x28
69-
// (The duplicates at 0x48 and 0x68 are commented out per Excel spec)
70-
$this->assertSame(0x28, $ptg['ptgMemNoMem'], 'ptgMemNoMem should be 0x28');
66+
// ptgMemNoMem base variant at 0x28 (0x48, 0x68 duplicates removed per Excel spec)
67+
$this->assertSame(0x28, $ptg['ptgMemNoMem']);
7168
}
7269
}

test/Test/Spreadsheet/Excel/Writer/WorksheetTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,8 @@ public function testGetDataClearsDataProperty()
9797

9898
// Check that data was returned
9999
$this->assertEquals($testData, $result);
100+
101+
// Check that _data is now null (not unset)
102+
$this->assertNull($property->getValue($this->worksheet));
100103
}
101104
}

0 commit comments

Comments
 (0)