PHP、静态分析和递归类型检查



我正在研究一个数据库ORM,它使用数组来定义WHERE子句,例如

$articles->find('all', [
'OR' => [
'category_id IS NULL',
'category_id' => $id,
],
]);

";数组键";成为SQL的一部分,所以它们必须是开发人员定义的字符串(也称为literal-string(,否则可能会出现以下错误:

$articles->find('all', [
'OR' => [
'category_id IS NULL',
'category_id = ' . $id, // INSECURE, SQLi
],
]);

如果";数组值";只包含要参数化的值(即用户值(,然后我可以将参数类型指定为array<literal-string, int|string>

但是,正如您在使用"OR"键时注意到的那样,该参数可以包含嵌套数组,并且可以是多个级别的深度。

有可能让静态分析工具,如诗篇或PHPStan来处理这个吗?


我可以使用CakePHP实现作为它如何工作的示例:

<?php
class orm {
/**
* @param array<int, literal-string|array<mixed>>|array<literal-string, int|string|array<mixed>> $conditions
*/
public function find(string $finder, array $conditions): void {
print_r($this->_addConditions($conditions));
}
/**
* @param array<int, literal-string|array<mixed>>|array<literal-string, int|string|array<mixed>> $conditions
* @param literal-string $conjunction
* @return array{literal-string, array<int, mixed>}
*/
private function _addConditions(array $conditions, string $conjunction = 'AND'): array {
// https://github.com/cakephp/cakephp/blob/ab052da10dc5ceb2444c29aef838d10844fe5995/src/Database/Expression/QueryExpression.php#L654
$operators = ['and', 'or', 'xor'];
$sql = [];
$parameters = [];
foreach ($conditions as $k => $c) {
if (is_numeric($k)) {
if (is_array($c)) {
/** @var array<int, array<mixed>> $sub_conditions */
$sub_conditions = $c;
list($new_sql, $new_parameters) = $this->_addConditions($sub_conditions, 'AND');
$sql[] = $new_sql;
$parameters = array_merge($parameters, $new_parameters);
} else if (is_string($c)) {
$sql[] = $c; // $c must be a literal-string
}
} else {
$operatorId = array_search(strtolower($k), $operators);
if ($operatorId !== false) {
/** @var array<literal-string, int|string|array<mixed>> $sub_conditions */
$sub_conditions = $c;
list($new_sql, $new_parameters) = $this->_addConditions($sub_conditions, $operators[$operatorId]);
$sql[] = $new_sql;
$parameters = array_merge($parameters, $new_parameters);
} else {
$sql[] = $k . ' = ?'; // $k must be a literal-string
$parameters[] = $c;
}
}
}
/** @var literal-string $sql */
$sql = '(' . implode(' ' . $conjunction . ' ', $sql) . ')';
return [$sql, $parameters];
}
}
$articles = new orm();
?>

PHPStan

"递归类型现在不受支持,我不知道它们是否会"2021年3月。

"PHPStan不支持递归类型,因为它们很难做到;2022年5月。

诗篇

"递归类型不受《诗篇》的支持(可能永远不会是tbh(";2019年7月。

"是的,你不能——如果你搜索问题,你会看到一些递归类型的请求出现了(我已经驳回了("2020年2月。

最新更新