#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));
— Он ЖЕ глубокий клон (путем преобразования его в строку и обратно), песочница , хотя и не «идеальна» (это своего рода взлом), но работает.