Ошибка сегментации при выполнении запроса с экземпляром PDO

#php #mysql #pdo #segmentation-fault

#php #mysql #pdo #ошибка сегментации

Вопрос:

При использовании экземпляра PDO для выполнения запроса скрипт выдает ошибку сегментации. Это происходит после проверки того, что объект PDO действительно является экземпляром класса PDO:

 var_dump($db)
  

Что привело к:

 Object(PDO)#16 {
}
  

Он также успешно выполнил бы запрос без ошибки сегментации сразу после создания экземпляра объекта, но не позже в сценарии.

Ответ №1:

Проблема оказалась причудой объектов PHP и разработчика, который пытался быть слишком умным.

В PHP объекты передаются по ссылке (вроде) во все области. Это означает, что дочерняя область может изменять объект в родительской области. Чтобы избежать этого, программа, в которой я работал, сохраняла объекты в хранилище значений, и это хранилище значений КЛОНИРОВАЛО переменную, прежде чем возвращать ее, если это был объект:

     public function getConfig(string $key)
    {
        if ($this->hasConfig($key) === true) {
            if (is_object($this->configValues[$key]) === true) {
                return clone $this->configValues[$key];
            } else {
                return $this->configValues[$key];
            }
        } else {
            return null;
        }
    }
  

clone Ключевое слово (подробно здесь) создает мелкую копию объекта и его свойств, сохраняя при этом все свойства, которые являются ссылками.

Однако, когда объект PDO клонируется, он не поддерживает обработчик потока, который позволяет ему подключаться к базе данных, однако он поддерживает ссылку.

К сожалению, это вызывает ошибку сегментации.

Я подозреваю, что это связано с тем, что выполняется доступ либо к внутренней памяти вне диапазона (защищенной), либо потому, что библиотека, которая фактически позволяет PHP взаимодействовать с MySQL / базами данных с помощью PDO, не позволяет передавать обработчик потока таким образом.

Независимо от причин, если вы клонируете объект PDO, а затем используете его для запроса, это вызовет ошибку сегментации, которая не приводит к ошибкам или исключениям, позволяющим отладить проблему.

Фактический объект базы данных всегда должен передаваться и использоваться.

Я создал этот вопрос и ответ, чтобы записать эту конкретную особенность, поскольку я не смог найти никаких ссылок на это конкретное поведение в Google, когда я изначально пытался отладить проблему.

Такое поведение наблюдалось в PHP 7.2.16, и я не проверял, приведет ли оно к аналогичному поведению в других версиях PHP.

Ожидаемое поведение, если обработчик потока не может быть безопасно клонирован таким образом, заключается в том, что clone ключевое слово генерирует исключение при использовании для объекта PDO.

Редактировать:

Другой фактор, который может способствовать (опять же, это не то, что я тщательно тестировал), заключается в том, что это конкретное соединение использует PDO::MYSQL_ATTR_SSL_CA атрибут для установки файла SSL cert .pem.

Комментарии:

1. Эти === true тесты слишком специфичны. hasConfig и is_object предназначены для возврата логически истинного / ложного значения, в таком тестировании нет необходимости. Это как if ((($x === $y) === true) === true)

2. Я хорошо осведомлен. Метод hasConfig() фактически определен public function hasConfig(string $key): bool . Тем не менее, мои менее опытные коллеги по обзору кода выговаривают мне, если я не слишком конкретен, как это. Это не связано с проблемой, которую я описываю.

3. Если ваши коллеги не знают, что if делает, это очень беспокоит, как будто это описано в первые десять минут использования PHP. Если это артефакт вашей специфической ситуации, который просто загромождает код и способствует развитию вредных привычек. Если вы сталкиваетесь с проблемой объявления этого public , наверняка вы знаете, как работают логические значения. Настоящая проблема === true в том, что иногда вещи возвращают правдивые , но не буквальные true ответы.

4. Нет, они понимают, что if делает, но у них есть === соглашение для обеспечения еще более строгой безопасности типов во всех программах и для удобства чтения. Они установили это до того, как я попал сюда, чтобы с первого взгляда с уверенностью знать, что они вводят безопасность в инструкции if, не было ошибкой. Опять же, это педантизм, который не имеет отношения к вопросу, на который здесь дан ответ.

5. $obj = unserialize(serialize($obj)); — Он ЖЕ глубокий клон (путем преобразования его в строку и обратно), песочница , хотя и не «идеальна» (это своего рода взлом), но работает.