Почему объект PDO недоступен внутри функции?

Доброго дня. Ранее всё работало, давно перешёл на PHP 8.4. Есть контроллер добавления товара — он отвечает корректно. В модели есть метод, который добавляет запись в базу через PDO; похожие методы работают, но именно функция добавления товара не получает подключение к PDO: после шести успешных добавлений на седьмом возникает ошибка 500. При прямом подключении к БД всё работает, то есть проблема проявляется только в этой функции — PDO перестал видеть соединение.
  • 25 апреля 2026 г. 7:00
Ответы на вопрос 3
Коротко — причин может быть несколько. Часто это не «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),
и я подскажу конкретно, где ошибка и как её исправить.
В <a href="https://www.php.net/manual/ru/class.pdo.php" rel="nofollow">PDO</a> нет функции getConnection. Так что изучайте, что у вас в этой функции написано и смотрите в логах, где именно и какая ошибка происходит.
что в error_log? 500 без стека ничего не скажет. если там про «lost connection» — Db::getConnection() возвращает протухший коннект, надо reconnect добавить.
Похожие вопросы