Skip to content

Commit c146d6f

Browse files
authored
Merge pull request #222 from phpcr/phpstan-fixes
raise phpstan level and improve type safety
2 parents 6d28ee3 + 78040a9 commit c146d6f

28 files changed

+255
-114
lines changed

phpstan.neon.dist

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
parameters:
2-
level: 2
2+
level: 5
33
paths:
4-
- src
4+
- src/
5+
6+
ignoreErrors:
7+
# phpstan does not understand that the empty arrays are only the default
8+
-
9+
message: "#^Empty array passed to foreach\\.$#"
10+
count: 5
11+
path: src/PHPCR/Util/Console/Helper/PhpcrHelper.php
12+
# only formulated in phpdoc that the return value must be countable
13+
-
14+
message: "#expects array|Countable, Iterator<mixed, PHPCR\\Query\\RowInterface> given\\.$#"
15+
count: 1
16+
path: src/PHPCR/Util/Console/Command/NodesUpdateCommand.php

phpstan.tests.neon.dist

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
parameters:
2-
level: 1
2+
level: 7
33
paths:
4-
- tests
4+
- tests/
5+
6+
excludePaths:
7+
analyse:
8+
- tests/*/Fixtures/*
9+
10+
ignoreErrors:
11+
# not sure what is going on here
12+
-
13+
message: "#^Interface Iterator specifies template type TKey of interface Traversable as string but it's already specified as mixed\\.$#"
14+
count: 1
15+
path: tests/PHPCR/Tests/Stubs/MockNodeTypeManager.php
16+
17+
-
18+
message: "#^Interface Iterator specifies template type TValue of interface Traversable as PHPCR\\\\NodeType\\\\NodeTypeInterface but it's already specified as mixed\\.$#"
19+
count: 1
20+
path: tests/PHPCR/Tests/Stubs/MockNodeTypeManager.php
21+
22+
# too pedantic for tests
23+
-
24+
message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, array\\<int, string\\>\\|false given\\.$#"
25+
count: 1
26+
path: tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php
27+
28+
-
29+
message: "#^Parameter \\#3 \\.\\.\\.\\$arrays of function array_merge expects array, array\\<int, string\\>\\|false given\\.$#"
30+
count: 1
31+
path: tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php

src/PHPCR/Util/CND/Parser/AbstractParser.php

+4-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace PHPCR\Util\CND\Parser;
66

77
use PHPCR\Util\CND\Exception\ParserException;
8+
use PHPCR\Util\CND\Scanner\GenericToken;
89
use PHPCR\Util\CND\Scanner\GenericToken as Token;
910
use PHPCR\Util\CND\Scanner\TokenQueue;
1011

@@ -29,12 +30,8 @@ abstract class AbstractParser
2930
* Check the next token without consuming it and return true if it matches the given type and data.
3031
* If the data is not provided (equal to null) then only the token type is checked.
3132
* Return false otherwise.
32-
*
33-
* @param int $type The expected token type
34-
* @param string|null $data The expected data or null
35-
* @param bool $ignoreCase whether to do string comparisons case insensitive or sensitive
3633
*/
37-
protected function checkToken($type, string $data = null, bool $ignoreCase = false): bool
34+
protected function checkToken(int $type, string $data = null, bool $ignoreCase = false): bool
3835
{
3936
if ($this->tokenQueue->isEof()) {
4037
return false;
@@ -48,7 +45,7 @@ protected function checkToken($type, string $data = null, bool $ignoreCase = fal
4845

4946
if ($data && $token->getData() !== $data) {
5047
if ($ignoreCase && is_string($data) && is_string($token->getData())) {
51-
return strcasecmp($data, $token->getData());
48+
return 0 !== strcasecmp($data, $token->getData());
5249
}
5350

5451
return false;
@@ -89,7 +86,7 @@ protected function expectToken(int $type, string $data = null): Token
8986
if (!$this->checkToken($type, $data)) {
9087
throw new ParserException($this->tokenQueue, sprintf("Expected token [%s, '%s']", Token::getTypeName($type), $data));
9188
}
92-
89+
\assert($token instanceof GenericToken);
9390
$this->tokenQueue->next();
9491

9592
return $token;

src/PHPCR/Util/CND/Parser/CndParser.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ final class CndParser extends AbstractParser
7171
private array $namespaces = [];
7272

7373
/**
74-
* @var string[]
74+
* @var NodeTypeDefinitionInterface[]
7575
*/
7676
private array $nodeTypes = [];
7777

src/PHPCR/Util/CND/Scanner/GenericScanner.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ public function scan(ReaderInterface $reader): TokenQueue
2828
$this->resetQueue();
2929

3030
while (!$reader->isEof()) {
31-
$tokenFound = false;
32-
$tokenFound = $tokenFound || $this->consumeComments($reader);
31+
$tokenFound = $this->consumeComments($reader);
3332
$tokenFound = $tokenFound || $this->consumeNewLine($reader);
3433
$tokenFound = $tokenFound || $this->consumeSpaces($reader);
3534
$tokenFound = $tokenFound || $this->consumeString($reader);

src/PHPCR/Util/CND/Writer/CndWriter.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,7 @@ protected function writeNodeType(NodeTypeDefinitionInterface $nodeType): string
119119
if ($nodeType->getPrimaryItemName()) {
120120
$attributes .= 'primaryitem '.$nodeType->getPrimaryItemName().' ';
121121
}
122-
if ($attributes) {
123-
$s .= trim($attributes)."\n";
124-
}
122+
$s .= trim($attributes)."\n";
125123

126124
$s .= $this->writeProperties($nodeType->getDeclaredPropertyDefinitions());
127125

src/PHPCR/Util/Console/Command/BaseCommand.php

+18-3
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,31 @@ protected function getPhpcrSession(): SessionInterface
2525

2626
protected function getPhpcrHelper(): PhpcrHelper
2727
{
28-
return $this->getHelper('phpcr');
28+
$helper = $this->getHelper('phpcr');
29+
if (!$helper instanceof PhpcrHelper) {
30+
throw new \RuntimeException('phpcr must be the PhpcrHelper');
31+
}
32+
33+
return $helper;
2934
}
3035

3136
protected function getPhpcrConsoleDumperHelper(): PhpcrConsoleDumperHelper
3237
{
33-
return $this->getHelper('phpcr_console_dumper');
38+
$helper = $this->getHelper('phpcr_console_dumper');
39+
if (!$helper instanceof PhpcrConsoleDumperHelper) {
40+
throw new \RuntimeException('phpcr_console_dumper must be the PhpcrConsoleDumperHelper');
41+
}
42+
43+
return $helper;
3444
}
3545

3646
protected function getQuestionHelper(): QuestionHelper
3747
{
38-
return $this->getHelper('question');
48+
$helper = $this->getHelper('question');
49+
if (!$helper instanceof QuestionHelper) {
50+
throw new \RuntimeException('question must be the QuestionHelper');
51+
}
52+
53+
return $helper;
3954
}
4055
}

src/PHPCR/Util/Console/Helper/TreeDumper/ConsoleDumperPropertyVisitor.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public function __construct(OutputInterface $output, array $options = [])
4747
public function visit(ItemInterface $item): void
4848
{
4949
if (!$item instanceof PropertyInterface) {
50-
throw new \Exception(sprintf('Internal error: did not expect to visit a non-property object: %s', is_object($item) ? $item::class : $item));
50+
throw new \Exception(sprintf('Internal error: did not expect to visit a non-property object: %s', $item::class));
5151
}
5252

5353
$value = $item->getString();

src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php

-5
Original file line numberDiff line numberDiff line change
@@ -429,11 +429,6 @@ protected function parseNot(): NotInterface
429429
protected function parseComparison(): ComparisonInterface
430430
{
431431
$op1 = $this->parseDynamicOperand();
432-
433-
if (null === $op1) {
434-
throw new InvalidQueryException("Syntax error: dynamic operator expected in '{$this->sql2}'");
435-
}
436-
437432
$operator = $this->parseOperator();
438433
$op2 = $this->parseStaticOperand();
439434

tests/PHPCR/Tests/Stubs/MockNode.php

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
use PHPCR\NodeInterface;
88

9+
/**
10+
* @implements \Iterator<string, NodeInterface>
11+
*/
912
abstract class MockNode implements \Iterator, NodeInterface
1013
{
1114
}

tests/PHPCR/Tests/Stubs/MockNodeTypeManager.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
namespace PHPCR\Tests\Stubs;
66

7+
use PHPCR\NodeType\NodeTypeInterface;
78
use PHPCR\NodeType\NodeTypeManagerInterface;
89

10+
/**
11+
* @implements \Iterator<string, NodeTypeInterface>
12+
*/
913
abstract class MockNodeTypeManager implements \Iterator, NodeTypeManagerInterface
1014
{
1115
}

tests/PHPCR/Tests/Stubs/MockRow.php

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
use PHPCR\Query\RowInterface;
88

9+
/**
10+
* @implements \Iterator<string, mixed>
11+
*/
912
abstract class MockRow implements \Iterator, RowInterface
1013
{
1114
}

tests/PHPCR/Tests/Util/CND/Reader/FileReaderTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class FileReaderTest extends TestCase
2020
private $reader;
2121

2222
/**
23-
* @var array
23+
* @var string[]
2424
*/
2525
private $lines;
2626

tests/PHPCR/Tests/Util/CND/Scanner/GenericScannerTest.php

+9-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
class GenericScannerTest extends TestCase
1616
{
1717
/**
18-
* @var array<Token[]>
18+
* @var array<array{0: int, 1: string}>
1919
*/
2020
private array $expectedTokens = [
2121
// <opening php tag>
@@ -108,7 +108,7 @@ class GenericScannerTest extends TestCase
108108
];
109109

110110
/**
111-
* @var Token[]
111+
* @var array<array{0: int, 1: string}>
112112
*/
113113
protected array $expectedTokensNoEmptyToken;
114114

@@ -146,7 +146,10 @@ public function testFilteredScan(): void
146146
$this->assertTokens($this->expectedTokensNoEmptyToken, $queue);
147147
}
148148

149-
protected function assertTokens($tokens, TokenQueue $queue): void
149+
/**
150+
* @param array<array{0: int, 1: string}> $tokens
151+
*/
152+
protected function assertTokens(array $tokens, TokenQueue $queue): void
150153
{
151154
$queue->reset();
152155

@@ -155,6 +158,8 @@ protected function assertTokens($tokens, TokenQueue $queue): void
155158
$token = $queue->peek();
156159

157160
while ($it->valid()) {
161+
$this->assertInstanceOf(Token::class, $token);
162+
158163
$expectedToken = $it->current();
159164

160165
$this->assertFalse($queue->isEof(), 'There is no more tokens, expected = '.$expectedToken[1]);
@@ -168,7 +173,7 @@ protected function assertTokens($tokens, TokenQueue $queue): void
168173
$this->assertTrue($queue->isEof(), 'There are more unexpected tokens.');
169174
}
170175

171-
protected function assertToken($type, $data, Token|false $token): void
176+
protected function assertToken(int $type, string $data, Token $token): void
172177
{
173178
$this->assertEquals(
174179
$type,

tests/PHPCR/Tests/Util/Console/Command/BaseCommandTest.php

+12-16
Original file line numberDiff line numberDiff line change
@@ -27,37 +27,37 @@
2727
abstract class BaseCommandTest extends TestCase
2828
{
2929
/**
30-
* @var SessionInterface|MockObject
30+
* @var SessionInterface&MockObject
3131
* */
3232
public $session;
3333

3434
/**
35-
* @var WorkspaceInterface|MockObject
35+
* @var WorkspaceInterface&MockObject
3636
*/
3737
public $workspace;
3838

3939
/**
40-
* @var RepositoryInterface|MockObject
40+
* @var RepositoryInterface&MockObject
4141
*/
4242
public $repository;
4343

4444
/**
45-
* @var PhpcrConsoleDumperHelper|MockObject
45+
* @var PhpcrConsoleDumperHelper&MockObject
4646
*/
4747
public $dumperHelper;
4848

4949
/**
50-
* @var NodeInterface|MockObject
50+
* @var NodeInterface&MockObject
5151
*/
5252
public $node1;
5353

5454
/**
55-
* @var RowInterface|MockObject
55+
* @var RowInterface&MockObject
5656
*/
5757
public $row1;
5858

5959
/**
60-
* @var QueryManagerInterface|MockObject
60+
* @var QueryManagerInterface&MockObject
6161
*/
6262
public $queryManager;
6363

@@ -113,18 +113,14 @@ public function setUp(): void
113113
/**
114114
* Build and execute the command tester.
115115
*
116-
* @param string $name command name
117-
* @param array $args command arguments
118-
* @param int $status expected return status
119-
*
120-
* @return CommandTester
116+
* @param mixed[] $arguments
121117
*/
122-
public function executeCommand($name, $args, $status = 0)
118+
public function executeCommand(string $commandName, array $arguments, int $expectedReturnStatus = 0): CommandTester
123119
{
124-
$command = $this->application->find($name);
120+
$command = $this->application->find($commandName);
125121
$commandTester = new CommandTester($command);
126-
$args = array_merge(['command' => $command->getName()], $args);
127-
$this->assertEquals($status, $commandTester->execute($args));
122+
$arguments = array_merge(['command' => $command->getName()], $arguments);
123+
$this->assertEquals($expectedReturnStatus, $commandTester->execute($arguments));
128124

129125
return $commandTester;
130126
}

tests/PHPCR/Tests/Util/Console/Command/NodeDumpCommandTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
class NodeDumpCommandTest extends BaseCommandTest
1414
{
15-
/** @var TreeWalker|MockObject */
15+
/** @var TreeWalker&MockObject */
1616
protected $treeWalker;
1717

1818
public function setUp(): void

tests/PHPCR/Tests/Util/Console/Command/NodeMoveCommandTest.php

+15-3
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,27 @@
88

99
class NodeMoveCommandTest extends BaseCommandTest
1010
{
11-
public function provideCommand()
11+
/**
12+
* @return array<array<mixed[]>>
13+
*/
14+
public function provideCommand(): array
1215
{
13-
return [[['source' => '/foo', 'destination' => '/bar']]];
16+
return [
17+
[
18+
[
19+
'source' => '/foo',
20+
'destination' => '/bar',
21+
],
22+
],
23+
];
1424
}
1525

1626
/**
1727
* @dataProvider provideCommand
28+
*
29+
* @param array<mixed[]> $args
1830
*/
19-
public function testCommand($args): void
31+
public function testCommand(array $args): void
2032
{
2133
$this->session->expects($this->once())
2234
->method('move')

tests/PHPCR/Tests/Util/Console/Command/NodeTouchCommandTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
class NodeTouchCommandTest extends BaseCommandTest
1818
{
1919
/**
20-
* @var PhpcrHelper|MockObject
20+
* @var PhpcrHelper&MockObject
2121
*/
2222
public $phpcrHelper;
2323

tests/PHPCR/Tests/Util/Console/Command/NodeTypeListCommandTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
class NodeTypeListCommandTest extends BaseCommandTest
1212
{
1313
/**
14-
* @var MockNodeTypeManager|MockObject
14+
* @var MockNodeTypeManager&MockObject
1515
*/
1616
private $nodeTypeManager;
1717

0 commit comments

Comments
 (0)