ClickHouse поддерживает типизированные параметры через HTTP: {name:Type} — сервер сам парсит значения, SQL injection невозможен на уровне протокола.
Query::isUseInUrlBindingsParams()уже детектит{p1:UInt8}синтаксисQuery::getUrlBindingsParams()извлекает params для URLHttp::makeRequest()передаёт их какparam_*в query string- НО: нет удобного API в Client, нет валидации типов, нет документации
- Добавить
Client::selectWithParams(string $sql, array $params, string $format = 'JSON')$params = ['p1' => ['value' => 42, 'type' => 'UInt32']]- Формирует
param_p1=42в URL, тип уже в SQL:{p1:UInt32}
- Добавить
Client::writeWithParams(string $sql, array $params)— аналог для DDL/DML - Валидация: проверять что все
{name:Type}из SQL имеют соответствующий param - Конвертация PHP-типов в CH-значения (DateTimeInterface → string, array → JSON и т.д.)
- Не ломать существующий
select()/write()— новые методы параллельно - Тесты: unit (без CH) + integration (с CH 21 и 26)
- Документация:
doc/native-params.md
src/Client.php— новые методыsrc/Query/Query.php— валидация params vs SQL placeholderssrc/Query/ParamValueConverter.php— новый: конвертация PHP → CH stringtests/NativeParamsTest.php— unittests/ClickHouse26/NativeParamsTest.php— integration (native params лучше тестить на 26.x)
Расширить ValueFormatter и добавить систему типов для native parameters.
ValueFormatter: int, float, bool, string, null, DateTimeInterface, Expression, TypeUInt64— единственный кастомный тип- Нет поддержки: DateTime64, Date32, IPv4/IPv6, UUID, Map, Tuple, Enum, Decimal, Geo-типы
-
src/Type/— расширить систему типов:-
Int8,Int16,Int32,Int64,Int128,Int256 -
UInt8,UInt16,UInt32,UInt64(уже есть),UInt128,UInt256 -
Float32,Float64 -
Decimal(P, S),Decimal32,Decimal64,Decimal128,Decimal256 -
Bool
-
- Тесты на каждый тип: insert + select + сравнение
-
String,FixedString(N) -
Date,Date32 -
DateTime,DateTime64(precision, timezone) -
UUID -
IPv4,IPv6 -
Enum8,Enum16 - Тесты
-
Array(T)— уже частично работает, формализовать -
Tuple(T1, T2, ...) -
Map(K, V) -
Nullable(T)— уже частично работает -
LowCardinality(T) -
Nested(name1 T1, name2 T2)— уже частично, формализовать - Тесты
-
JSON/Object('json') - Geo:
Point,Ring,LineString,Polygon,MultiPolygon -
SimpleAggregateFunction,AggregateFunction - Тесты
src/Type/
├── Type.php (базовый интерфейс — уже есть)
├── NumericType.php (уже есть)
├── UInt64.php (уже есть)
├── TypeRegistry.php — NEW: маппинг CH type name → PHP class
├── Date32.php
├── DateTime64.php
├── IPv4.php
├── IPv6.php
├── UUIDType.php
├── MapType.php
└── TupleType.php
- Каждый тип реализует
Typeинтерфейс (getValue()) TypeRegistry— singleton с маппингом'DateTime64' → DateTime64::class- Обратная совместимость: существующий код без типов продолжает работать
- Типы опциональны — можно передавать raw values как раньше
Обогатить исключения информацией из ClickHouse: error code, exception name, stack trace.
DatabaseException— парситCode: N. DB::Exception: messageTransportException— curl ошибкиQueryException— общие ошибки запросов- НЕТ: CH exception class name, query ID, stack trace от сервера
-
DatabaseException— добавить поля:-
getClickHouseExceptionName(): ?string—SYNTAX_ERROR,TABLE_NOT_FOUNDи т.д. -
getQueryId(): ?string— из заголовкаX-ClickHouse-Query-Id -
getServerVersion(): ?string— из ответа
-
- Парсить новый формат ошибок CH 22+:
(EXCEPTION_NAME) (version X.Y.Z) - Расширить regex в Statement:
CLICKHOUSE_ERROR_REGEX - НЕ менять конструктор
DatabaseException— добавить сеттеры/фабрику - Тесты: unit с mock ответами + data provider с разными форматами ошибок
- Тесты на CH 21 (старый формат) и CH 26 (новый формат)
src/Exception/DatabaseException.php— расширитьsrc/Statement.php— парсинг вparseErrorClickHouse()tests/ExceptionParsingTest.php— unit тесты с data provider
Поэтапно поднять PHPStan с level 1 до max.
phpstan.neon.dist: level 1, phpVersion 80406- PHPStan 2.1, PHP 8.4.6
- 0 ошибок на level 1
- Level 2 → исправить ошибки → коммит
- Level 3 → исправить ошибки → коммит
- Level 4 → исправить ошибки → коммит
- Level 5 → исправить ошибки → коммит (основные type checks)
- Level 6 → исправить ошибки → коммит (missing typehints)
- Level 7 → исправить ошибки → коммит (union types)
- Level 8 → исправить ошибки → коммит (nullability)
- Level 9 → исправить ошибки → коммит (mixed type)
- Level max → финальная проверка
- Каждый уровень = отдельный коммит
- НЕ менять публичные сигнатуры методов (обратная совместимость!)
- Добавлять
@phpstan-*аннотации только как крайняя мера - Предпочитать реальные фиксы типов, а не подавление ошибок
- Прогонять тесты после каждого уровня
- Сейчас ~35 PHP файлов в src/ — масштаб управляемый
- Основные проблемы ожидаются на level 5-6 (missing type hints)
- Level 8+ может потребовать добавления
@phpstan-assert/@phpstan-param
Передавать настройки ClickHouse на уровне отдельного запроса.
Settings— глобальный объект, общий на все запросы- Для изменения надо:
$client->settings()->set(...)→ запрос →$client->settings()->set(...)обратно - Неудобно и не thread-safe (если делить client между goroutines/fibers)
- Добавить
$settingsпараметр в существующие методы (с default =[]):-
Client::select($sql, $bindings = [], $whereInFile = null, $writeToFile = null, array $settings = []) -
Client::write($sql, $bindings = [], $exception = true, array $settings = []) -
Client::selectAsync(...)— аналогично
-
-
Http::select()/Http::write()— пробросить settings в URL params - Settings мержатся: глобальные + per-query (per-query приоритет)
- НЕ ломать обратную совместимость — новый параметр со значением по умолчанию
[] - Тесты: проверить что per-query settings применяются, а глобальные не меняются
// Глобальные настройки
$db->settings()->set('max_execution_time', 30);
// Один тяжёлый запрос с увеличенным таймаутом
$result = $db->select(
'SELECT * FROM huge_table',
[],
null,
null,
['max_execution_time' => 300, 'max_rows_to_read' => 1000000]
);
// Следующий запрос — снова 30 сек
$db->select('SELECT 1');src/Client.php— добавить параметрsrc/Transport/Http.php— merge settingstests/PerQuerySettingsTest.phptests/ClickHouse26/PerQuerySettingsTest.php
| # | Задача | Сложность | Риск ломки API | Приоритет |
|---|---|---|---|---|
| 5 | Per-query settings | Низкая | Нулевой | P0 |
| 3 | Structured exceptions | Низкая | Нулевой | P0 |
| 1 | Native Query Parameters | Средняя | Нулевой (новые методы) | P1 |
| 4 | PHPStan level max | Средняя | Нулевой | P1 |
| 2 | 60+ типов (фаза 1-2) | Средняя | Нулевой | P2 |
| 2 | 60+ типов (фаза 3-4) | Высокая | Нулевой | P3 |
- НЕЛЬЗЯ менять сигнатуры существующих публичных методов
- НЕЛЬЗЯ менять существующие тесты
- НЕЛЬЗЯ добавлять внешние зависимости в
require - Новые параметры — ТОЛЬКО с default значениями
- Каждая фича = отдельная ветка + PR + тесты для CH 21 и CH 26