Модель работы
CDO — это не ORM и не новый слой базы данных. Это PDO, который уже умеет безопасно привязывать значения и говорить на диалекте вашего конкретного драйвера. Удержите эту идею — и каждый метод встанет на своё место.
Одна идея
Значение никогда не касается строки SQL. Оно едет рядом с ней, как привязка.
Всё, что добавляет CDO, — следствие этого. Qb не строит целый запрос — он
строит фрагмент плюс его привязки. Методы DML не склеивают ваши данные — они
превращают ключи в :плейсхолдеры и передают значения типизированному
связывателю. Вы композируете фрагменты; библиотека держит значения отдельно всю
дорогу вниз.
Две половины, встречающиеся на execute
У CDO две независимые половины, соединяющиеся только в момент выполнения:
Qb (неизменяемый) CDO (наследует PDO)
───────────── ────────────────
Qb::eq('id', 5) → insert / update / delete / upsert
├─ query: "id = :iqb0" │
└─ binds: [:iqb0 => 5] └─ CDOStatement.bindTypedValue()
└─ подбирает PDO::PARAM_* по типу PHPQbпорождает строкуgetQuery()и списокgetBinds(). Он чистый — без соединения, без выполнения, полностью тестируемый сам по себе.CDOвладеет соединением и диалектом драйвера. Когда вы вызываетеupdate()илиdelete(), он сшивает ваш фрагментQbв запрос и привязывает каждое значение с нужным типом черезCDOStatement.
Следствия (что вытекает из идеи)
Qbнеизменяем. Каждая фабрика возвращает новый экземпляр;and/or/clipобъединяют без мутации. (СемействоaddAnd/addOr— явное изменяемое исключение, см. построение условий.)- Плейсхолдеры именуются автоматически.
Qbчеканит:iqb0,:iqb1, …, поэтому вы редко что-то называете. Когда хотите общее или читаемое имя — передайтеCDOBindвместо сырого скаляра. nullозначает разное в разных методах. ВQb::eqон становитсяIS NULL; вinsert/upsertзначениеnullполностью выбрасывается из списка колонок.- Типы выводятся, а не предполагаются.
intпривязывается какPARAM_INT,bool— какPARAM_BOOL, массив — как JSON,DateTimeInterface— какY-m-d H:i:s. Вы не кастуете; связыватель читаетgettype(). См. Привязку параметров.
CDO по-прежнему PDO
class CDO extends PDO. Это наследование намеренно: методы-удобства покрывают
запись, но чтение — это чистый PDO. Здесь нет select() или findAll() — вы
сами делаете prepare() / query() и fetch(), используя фрагмент Qb для
WHERE. Транзакции, курсоры и любой атрибут PDO работают без изменений.
Когда за чем тянуться
Запись строк → insert / upsert / update / delete из CDO. Чтение строк →
PDO prepare + Qb::…->getQuery() + getBinds(). Построение условия в изоляции
(даже чтобы юнит-тестировать его) → один Qb, соединение не нужно.
Чем CDO намеренно не является
- Не ORM — нет сущностей, нет identity map, нет ленивых связей. На вход — массивы и обычные объекты, на выход — массивы.
- Не инструмент схемы — нет миграций и помощников DDL. Таблицы вы создаёте сами.
- Не полноценный конструктор SELECT —
Qbстроит фрагменты видаWHERE(иCASE), а не джойны, проекции или сортировки.
Знать границу — в этом весь смысл: CDO убирает рискованную повторяющуюся часть доступа к данным — привязку и диалект — и оставляет остальное PDO и SQL, который вы уже знаете.
Дальше
- Построение условий — композиция
Qbна практике - Определение драйвера — как работает половина с диалектом
- Привязка параметров — как работает половина со значениями