Skip to content

Commit fe34824

Browse files
authored
Merge pull request #84 from artemeon/feat/phpstan-level-9
2 parents 67a7e74 + d7375b6 commit fe34824

16 files changed

Lines changed: 127 additions & 52 deletions

phpstan.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ includes:
22
- phpstan-baseline.neon
33

44
parameters:
5-
level: 8
5+
level: 9
66
paths:
77
- src
88
- tests

src/Connection.php

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Artemeon\Database\Schema\DataType;
2525
use Artemeon\Database\Schema\Table;
2626
use Artemeon\Database\Schema\TableIndex;
27+
use BackedEnum;
2728
use Generator;
2829
use InvalidArgumentException;
2930
use Override;
@@ -45,7 +46,7 @@ class Connection implements ConnectionInterface
4546
/**
4647
* Array to cache queries.
4748
*
48-
* @var array<string, list<mixed>>
49+
* @var array<string, array<int, array<string, mixed>>>
4950
*/
5051
private array $queryCache = [];
5152

@@ -310,8 +311,6 @@ public function _pQuery(string $query, array $params = [], array $escapes = []):
310311
$this->dbconnect();
311312
}
312313

313-
$output = false;
314-
315314
$query = $this->processQuery($query);
316315

317316
// Increasing the counter
@@ -445,6 +444,8 @@ public function getPArray(
445444
/**
446445
* @inheritDoc
447446
* @throws ConnectionException
447+
*
448+
* @return Generator<list<array<non-empty-string, mixed>>>
448449
*/
449450
#[Override]
450451
public function getGenerator(string $query, array $params = [], int $chunkSize = 2048, bool $paging = true): Generator
@@ -605,7 +606,7 @@ public function iterateColumn(string $query, array $params = []): Generator
605606
/**
606607
* Writes the last DB-Error to the screen.
607608
*
608-
* @param list<mixed> $params
609+
* @param list<scalar|null> $params
609610
*
610611
* @throws QueryException
611612
* @throws ConnectionException
@@ -1149,7 +1150,7 @@ private function processQuery(string $query): string
11491150
}
11501151

11511152
/**
1152-
* @param list<mixed> $params
1153+
* @param list<scalar|null> $params
11531154
*/
11541155
private function addQueryToList(string $query, array $params, bool $cached, float $startTime): void
11551156
{
@@ -1220,19 +1221,19 @@ public function getCacheSize(): int
12201221
* An internal wrapper to dbsafeString, used to process a complete array of parameters
12211222
* as used by prepared statements.
12221223
*
1223-
* @param array<array-key, mixed> $params
1224+
* @param array<array-key, BackedEnum|EscapeableParameterInterface|scalar|null> $params
12241225
* @param list<bool>|false $escapes An array of boolean for each param, used to block the escaping of html-special chars.
12251226
* If not passed, all params will be cleaned.
12261227
*
1227-
* @return list<mixed>
1228+
* @return list<scalar|null>
12281229
*
12291230
* @see Db::dbsafeString($string, $htmlSpecialChars = true)
12301231
*/
12311232
private function dbsafeParams(array $params, array | false $escapes = []): array
12321233
{
12331234
$replace = [];
12341235
foreach ($params as $key => $param) {
1235-
if ($param instanceof \BackedEnum) {
1236+
if ($param instanceof BackedEnum) {
12361237
$replace[$key] = $param->value;
12371238

12381239
continue;
@@ -1261,7 +1262,7 @@ private function dbsafeParams(array $params, array | false $escapes = []): array
12611262
/**
12621263
* Makes a string db-safe.
12631264
*
1264-
* @return int|float|null|string
1265+
* @return ($input is float ? float : ($input is int ? int : ($input is bool ? int<0,1> : ($input is null ? null : ($input is scalar ? string : mixed)))))
12651266
* @deprecated we need to get rid of this
12661267
*/
12671268
public function dbsafeString(mixed $input, bool $htmlSpecialChars = true, bool $addSlashes = true): mixed
@@ -1284,12 +1285,12 @@ public function dbsafeString(mixed $input, bool $htmlSpecialChars = true, bool $
12841285
}
12851286

12861287
// escape special chars
1287-
if ($htmlSpecialChars) {
1288+
if (is_scalar($input) && $htmlSpecialChars) {
12881289
$input = html_entity_decode((string) $input, ENT_COMPAT, 'UTF-8');
12891290
$input = htmlspecialchars($input, ENT_COMPAT, 'UTF-8');
12901291
}
12911292

1292-
if ($addSlashes) {
1293+
if (is_scalar($input) && $addSlashes) {
12931294
$input = addslashes((string) $input);
12941295
}
12951296

@@ -1392,7 +1393,7 @@ public function escape(mixed $value): mixed
13921393
public function prettifyQuery(string $query, array $params): string
13931394
{
13941395
foreach ($params as $param) {
1395-
if (!is_numeric($param) && $param !== null) {
1396+
if (is_string($param)) {
13961397
$param = "'$param'";
13971398
}
13981399

@@ -1403,7 +1404,7 @@ public function prettifyQuery(string $query, array $params): string
14031404
}
14041405

14051406
$pos = strpos($query, '?');
1406-
if ($pos !== false) {
1407+
if ($pos !== false && is_string($param)) {
14071408
$query = substr_replace($query, $param, $pos, 1);
14081409
}
14091410
}

src/ConnectionInterface.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ interface ConnectionInterface extends DoctrineConnectionInterface
3636
* Method to get an array of rows for a given query from the database.
3737
* Makes use of prepared statements.
3838
*
39-
* @param list<mixed> $params
39+
* @param list<scalar|null> $params
4040
* @param list<bool> $escapes
4141
*
4242
* @throws QueryException
@@ -54,7 +54,7 @@ public function getPArray(string $query, array $params = [], ?int $start = null,
5454
* Returns one row from a result-set.
5555
* Makes use of prepared statements.
5656
*
57-
* @param list<mixed> $params
57+
* @param list<scalar|null> $params
5858
* @param list<bool> $escapes
5959
*
6060
* @throws QueryException
@@ -69,7 +69,7 @@ public function getPRow(string $query, array $params = [], int $number = 0, bool
6969
*
7070
* @param string $tableName the table name from which to select the row
7171
* @param list<string> $columns a flat list of column names to select
72-
* @param array<string, mixed> $identifiers mapping of column name to value to search for (e.g. ["id" => 1])
72+
* @param array<string, scalar|null> $identifiers mapping of column name to value to search for (e.g. ["id" => 1])
7373
* @param bool $cached whether a previously selected result can be reused
7474
* @param list<bool>|null $escapes which parameters to escape (described in {@see dbsafeParams})
7575
* @throws QueryException
@@ -91,7 +91,7 @@ public function selectRow(string $tableName, array $columns, array $identifiers,
9191
* false and don't modify the result set you will get an endless loop, so you must get sure that in the end the
9292
* result set will be empty.
9393
*
94-
* @param list<mixed> $params
94+
* @param list<scalar|null> $params
9595
*
9696
* @throws QueryException
9797
* @see iterateAssociative
@@ -103,7 +103,7 @@ public function getGenerator(string $query, array $params = [], int $chunkSize =
103103
*
104104
* Sending a prepared statement to the database
105105
*
106-
* @param list<mixed> $params
106+
* @param list<scalar|null> $params
107107
* @param list<bool> $escapes An array of booleans for each param, used to block the escaping of html-special chars.
108108
* If not passed, all params will be cleaned.
109109
* @throws QueryException
@@ -122,7 +122,7 @@ public function getAffectedRowsCount(): int;
122122
* INSERT INTO $table ($columns) VALUES (?, ?), (?, ?)...
123123
*
124124
* @param list<string> $columns
125-
* @param list<mixed> $valueSets
125+
* @param list<array<scalar|null>> $valueSets
126126
* @param list<bool>|null $escapes
127127
* @throws QueryException
128128
*/
@@ -135,7 +135,7 @@ public function multiInsert(string $tableName, array $columns, array $valueSets,
135135
* otherwise data might be lost. And: params are sent to the database unescaped.
136136
*
137137
* @param list<string> $columns
138-
* @param list<mixed> $values
138+
* @param list<scalar|null> $values
139139
* @param list<string> $primaryColumns
140140
*
141141
* @throws QueryException
@@ -196,7 +196,7 @@ public function getDatatype(DataType $type): string;
196196
* Used to send a `CREATE TABLE` statement to the database.
197197
* By passing the query through this method, the driver can add db-specific commands.
198198
*
199-
* @param array<non-empty-string, array{0: DataType, 1: bool, 2?: mixed}> $columns
199+
* @param array<non-empty-string, array{0: DataType, 1: bool, 2?: string}> $columns
200200
* @param list<string> $keys
201201
* @param list<list<string>|string> $indices
202202
*
@@ -312,7 +312,7 @@ public function encloseTableName(string $tableName): string;
312312
* Helper to replace all param-placeholder with the matching value, only to be used
313313
* to render a debuggable-statement.
314314
*
315-
* @param list<mixed> $params
315+
* @param list<scalar|null> $params
316316
*/
317317
public function prettifyQuery(string $query, array $params): string;
318318

@@ -349,6 +349,10 @@ public function getStringLengthExpression(string $targetString): string;
349349
/**
350350
* Converts a PHP value to a value, which can be inserted into a table. I.e. it truncates the value to
351351
* the fitting length for the provided datatype.
352+
*
353+
* @param scalar|null $value
354+
*
355+
* @return scalar|null
352356
*/
353357
public function convertToDatabaseValue(mixed $value, DataType $type): mixed;
354358

@@ -427,6 +431,10 @@ public function flushPreparedStatementsCache(): void;
427431
*/
428432
public function getColumnsOfTable(string $tableName): array;
429433

434+
/**
435+
* @param scalar|null $value
436+
* @return scalar|null
437+
*/
430438
public function escape(mixed $value): mixed;
431439

432440
public function hasOpenTransactions(): bool;

src/DoctrineConnectionInterface.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ interface DoctrineConnectionInterface
2727
/**
2828
* Prepares and executes an SQL query and returns the result as an array of associative arrays.
2929
*
30-
* @param list<mixed> $params
30+
* @param list<scalar|null> $params
3131
*
3232
* @return list<array<string, mixed>>
3333
*/
@@ -37,7 +37,7 @@ public function fetchAllAssociative(string $query, array $params = []): array;
3737
* Prepares and executes an SQL query and returns the first row of the result
3838
* as an associative array.
3939
*
40-
* @param list<mixed> $params
40+
* @param list<scalar|null> $params
4141
*
4242
* @return array<string, mixed>|false
4343
*/
@@ -46,7 +46,7 @@ public function fetchAssociative(string $query, array $params = []): array | fal
4646
/**
4747
* Prepares and executes an SQL query and returns the result as an array of the first column values.
4848
*
49-
* @param list<mixed> $params
49+
* @param list<scalar|null> $params
5050
*
5151
* @return list<mixed>
5252
*/
@@ -55,22 +55,22 @@ public function fetchFirstColumn(string $query, array $params = []): array;
5555
/**
5656
* Prepares and executes an SQL query and returns the value of a single column of the first row of the result.
5757
*
58-
* @param list<mixed> $params
58+
* @param list<scalar|null> $params
5959
*/
6060
public function fetchOne(string $query, array $params = []): mixed;
6161

6262
/**
6363
* Prepares and executes an SQL query and returns the result as an iterator over rows represented
6464
* as associative arrays.
6565
*
66-
* @param list<mixed> $params
66+
* @param list<scalar|null> $params
6767
*/
6868
public function iterateAssociative(string $query, array $params = []): Generator;
6969

7070
/**
7171
* Prepares and executes an SQL query and returns the result as an iterator over the first column values.
7272
*
73-
* @param list<mixed> $params
73+
* @param list<scalar|null> $params
7474
*/
7575
public function iterateColumn(string $query, array $params = []): Generator;
7676

@@ -84,32 +84,32 @@ public function iterateColumn(string $query, array $params = []): Generator;
8484
* - Session control statements: ALTER SESSION, SET, DECLARE, etc.
8585
* - Other statements that don't yield a row set.
8686
*
87-
* @param list<mixed> $params
87+
* @param list<scalar|null> $params
8888
*/
8989
public function executeStatement(string $query, array $params = []): int;
9090

9191
/**
9292
* Creates a simple insert for a single row where the values parameter is an associative array with column names to
9393
* value mapping.
9494
*
95-
* @param array<string, mixed> $values
95+
* @param array<non-empty-string, scalar|null> $values
9696
* @param list<bool>|null $escapes
9797
*/
9898
public function insert(string $tableName, array $values, ?array $escapes = null): int;
9999

100100
/**
101101
* Updates a row on the provided table by the identifier columns.
102102
*
103-
* @param array<string, mixed> $values
104-
* @param array<string, mixed> $identifier
103+
* @param array<string, scalar|null> $values
104+
* @param array<string, scalar|null> $identifier
105105
* @param list<bool>|null $escapes
106106
*/
107107
public function update(string $tableName, array $values, array $identifier, ?array $escapes = null): int;
108108

109109
/**
110110
* Deletes a row on the provided table by the identifier columns.
111111
*
112-
* @param array<string, mixed> $identifier
112+
* @param array<string, scalar|null> $identifier
113113
*/
114114
public function delete(string $tableName, array $identifier): int;
115115

src/Driver/DriverAbstract.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
/**
2626
* Base class for all database-drivers, holds methods to be used by all drivers.
2727
*
28-
* @author sidler@mulchprod.de
28+
* @template CacheType
2929
*/
3030
abstract class DriverAbstract implements DriverInterface
3131
{
3232
/**
33-
* @var array<array-key, mixed>
33+
* @var array<array-key, CacheType>
3434
*/
3535
protected array $statementsCache = [];
3636

@@ -225,6 +225,7 @@ public function insertOrUpdate(string $table, array $columns, array $values, arr
225225

226226
$enclosedTableName = $this->encloseTableName($table);
227227

228+
/** @var list<array{cnt:numeric-string}>|false $rows */
228229
$rows = $this->getPArray("SELECT COUNT(*) AS cnt FROM $enclosedTableName WHERE " . implode(' AND ', $primaryCompares), $primaryValues)->current();
229230

230231
if ($rows === false) {

src/Driver/MysqliDriver.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
/**
3535
* DB-driver for MySQL using the php-mysqli-interface.
36+
*
37+
* @template-extends DriverAbstract<false|mysqli_stmt>
3638
*/
3739
class MysqliDriver extends DriverAbstract
3840
{
@@ -257,6 +259,7 @@ public function getTables(): array
257259
{
258260
$generator = $this->getPArray('SHOW TABLE STATUS', []);
259261
$result = [];
262+
/** @var array{Name:string} $row */
260263
foreach ($generator as $row) {
261264
$result[] = ['name' => $row['Name']];
262265
}
@@ -275,6 +278,7 @@ public function getTableInformation(string $tableName): Table
275278

276279
// fetch all columns
277280
$columnInfo = $this->getPArray("SHOW COLUMNS FROM $tableName", []);
281+
/** @var array{Field:non-empty-string,Type:string,Null:string} $column */
278282
foreach ($columnInfo as $column) {
279283
$table->addColumn(
280284
TableColumn::make($column['Field'])
@@ -287,6 +291,7 @@ public function getTableInformation(string $tableName): Table
287291
// fetch all indexes
288292
$indexes = $this->getPArray("SHOW INDEX FROM $tableName WHERE Key_name != 'PRIMARY'", []);
289293
$indexAggr = [];
294+
/** @var array{Key_name:string,Column_name:string} $indexInfo */
290295
foreach ($indexes as $indexInfo) {
291296
$indexAggr[$indexInfo['Key_name']] ??= [];
292297
$indexAggr[$indexInfo['Key_name']][] = $indexInfo['Column_name'];
@@ -299,6 +304,7 @@ public function getTableInformation(string $tableName): Table
299304

300305
// fetch all keys
301306
$keys = $this->getPArray("SHOW KEYS FROM $tableName WHERE Key_name = 'PRIMARY'", []);
307+
/** @var array{Column_name:string} $keyInfo */
302308
foreach ($keys as $keyInfo) {
303309
$key = new TableKey($keyInfo['Column_name']);
304310
$table->addPrimaryKey($key);

0 commit comments

Comments
 (0)