Коротко — причин может быть несколько. Часто это не «PHP вдруг забыл про PDO», а одна из проблем: переменная вне области видимости, объект уничтожается/теряется, исчерпаны ресурсы БД или ошибка драйвера. Чтобы точно понять, надо увидеть код, но ниже — список наиболее вероятных причин и что проверить/сделать прямо сейчас.
Что проверить первым делом
1. Посмотрите реальные сообщения об ошибке (php‑fpm/nginx/Apache error log и/или лог приложений). Включите отображение исключений:
- Установите режим ошибок PDO: $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
- Оберните вызов в try/catch и логируйте $e->getMessage() и $e->getCode().
2. Подтвердите, что внутри функции/метода переменная с PDO действительно инициализирована:
- Внутри функции сделайте var_dump($pdo) или var_dump($this->pdo) и die() — увидите, существует ли объект.
- Если используете замыкание — убедитесь, что PDO подключён через use($pdo).
3. Проверьте область видимости/передачу:
- Если вы обращаетесь к глобальной переменной внутри функции, нужно либо использовать global $pdo;, либо (лучше) передавать PDO в функцию/метод как аргумент или хранить в $this->pdo.
- Если метод статический, а подключение в экземпляре — статический метод не увидит $this->pdo.
4. Утечка/закрытие соединений или ресурсные лимиты:
- Возможно создаются новые соединения при каждом добавлении и вы достигаете лимита на число соединений у БД. Проверяйте статус соединений на сервере БД (например, SHOW PROCESSLIST для MySQL).
- Если используете persistent connections (PDO::ATTR_PERSISTENT), попробуйте временно выключить/включить — поведение отличается.
- Для SQLite — частая причина: блокировка БД (database is locked) при попытке многократной записи/конкурентных писем.
5. Неправильное использование PDOStatement:
- Если вы возвращаете PDOStatement из функции, но PDO объект уничтожается (вышел из области видимости), это может вызвать проблемы при выполнении дальнейших операций. Держите PDO живым пока нужны результаты.
- Закрывайте курсоры: $stmt->closeCursor() если нужно освободить ресурсы.
6. Версии PHP/драйвера:
- В PHP 8.х могли поменяться некоторые поведения, особенно в комбинации с расширениями (pdo_mysql/pdo_sqlite). Посмотрите changelog, особенно если используете нестандартный драйвер.
Примеры исправлений
- Лучший паттерн — передавать PDO в конструктор модели и пользоваться $this->pdo:
public function __construct(PDO $pdo) { $this->pdo = $pdo; }
- Если функция — замыкание, импортируйте PDO:
$fn = function() use ($pdo) { $pdo->prepare(...); };
Диагностический чеклист (быстро выполнить)
- Включить ERRMODE_EXCEPTION и логировать исключение.
- var_dump($pdo) внутри проблемной функции.
- Проверить, не переписывается ли переменная $pdo в теле функции.
- Проверить логи БД на ошибки (locks, too many connections, etc).
- Временно заменить PDO на ручное прямое подключение в той же функции — если работает, значит проблема в передаче/жизни объекта.
Если хотите — пришлите фрагменты кода:
- где вы создаёте/инициализируете PDO,
- как вызывается проблемная функция (или её код),
- конфигурацию PDO (особенно ATTR_PERSISTENT),
и я подскажу конкретно, где ошибка и как её исправить.