Пакет · cdo

Привязка параметров

Каждое значение, которое пишет CDO, проходит через CDOStatement::bindTypedValue(), выбирающий константу PDO::PARAM_* по типу PHP значения. Именно это позволяет передавать bool, int, массив или DateTime и получать корректный SQL без кастов — вот как именно он решает.

Переключатель типов

bindTypedValue($parameter, $value) читает gettype($value) и диспетчеризует:

Тип PHP Тип PDO Преобразование
null PARAM_NULL
bool PARAM_BOOL
int PARAM_INT
array PARAM_STR сначала json_encode($value)
object PARAM_STR сериализуется через valObject() (ниже)
float, string, прочее PARAM_STR привязывается как есть

Это работает для значений колонок insert/upsert, значений SET в update и каждой привязки Qb — единый согласованный путь.

Почему важны булевы и целые

Привязка bool как PARAM_BOOL, а int как PARAM_INT (а не позволять всему скатываться к строке) держит PostgreSQL довольным boolean-колонками и позволяет числовым сравнениям корректно использовать индексы. Это разница между WHERE active = true и драйвером, давящимся на '1'.

Массивы становятся JSON

Значение-массив проходит json_encode перед привязкой, поэтому колонка JSON/JSONB получает валидный JSON без лишней работы:

php
$cdo->update('products',
  ['attributes' => ['color' => 'red', 'size' => 'M']],
  Qb::eq('id', 42)
);
// attributes привязано как '{"color":"red","size":"M"}'

Сериализация объектов (valObject)

Когда значение — объект, valObject() преобразует его в скаляр, проверяя интерфейсы в таком порядке — побеждает первое совпадение:

Приоритет Интерфейс / тип Преобразование
1 JsonSerializable $value->jsonSerialize()
2 Stringable (string) $value
3 DateTimeInterface $value->format('Y-m-d H:i:s')
4 BackedEnum $value->value
5 что угодно ещё serialize($value) (сериализация PHP)
php
$cdo->insert('events', [
  'occurred_at' => new DateTimeImmutable('2026-07-01 12:00:00'), // → '2026-07-01 12:00:00'
  'status'      => Status::Active,   // BackedEnum → его ->value
  'payload'     => $dtoImplementingJsonSerializable, // → jsonSerialize()
]);

У порядка есть последствия

Поскольку JsonSerializable проверяется первым, объект, являющийся одновременно JsonSerializable и DateTimeInterface, кодируется в JSON, а не форматируется как дата-время. А запасной вариант приоритета 5 — это PHP serialize(), что редко нужно колонке. Реализуйте Stringable или JsonSerializable на своих объектах-значениях, чтобы они попадали на намеренную ветку, а не на запасной serialize.

Явная привязка и переигрывание

CDOStatement также предоставляет более низкоуровневое управление:

  • bindValue($param, $value, $type = PDO::PARAM_STR) — привязать с явным PDO-типом, минуя определение. Каждая привязка (типизированная или явная) записывается.
  • getBindings() — записанные тройки [param, value, type].
  • updateStm(PDOStatement $stmt) — подставить свежеподготовленный statement и переиграть на нём каждую записанную привязку. Именно это делает statement переживающим переподключение: значения заново применяются дословно к новому дескриптору.

Чтение обратно

Привязка — это забота пути записи. Когда вы читаете унаследованными методами PDO, значения возвращаются такими, как их отдаёт драйвер — JSON-колонка это строка, которую вы сами json_decode, дата-время это строка. CDO не обращает valObject() при чтении.

Связанное