У меня есть такой класс:
class Session {
private Session_Database $db;
public function __construct(){
// Instantiate new Database object
$this->db = new Session_Database();
// Set handler to overide SESSION
session_set_save_handler(
[$this, '_open'],
[$this, '_close'],
[$this, '_read'],
[$this, '_write'],
[$this, '_destroy'],
[$this, '_gc']
);
// Start the session
session_start();
}
/* ... */
public function _close(): bool {
// Close the database connection
$this->db->close();
return true;
}
/* ... */
}
Я вижу эту ошибку в журналах:
Неустранимая ошибка PHP: необнаруженная ошибка: невозможно получить доступ к частной собственности
Session::$db
в [номер строки$this->db->close()
]Трассировка стека:
#0 [внутренняя функция]:Session->_close()
#1 {main}\n добавлено...
Однако когда я тестирую код, проходя через xdebug, он работает так, как ожидалось.
Что происходит?
С помощью быстрого теста я не могу получить никаких ошибок: 3v4l.org/WfN3S
@KIKOSoftware, можете ли вы уточнить, какие комментарии в примечаниях пользователей вы имеете в виду? Я предполагаю, что класс уничтожается еще до того, как _close()
вызывается, но когда я тестирую, на самом деле этого не происходит.
@ChrisHaas Я тоже не могу, но в журнале ошибок появляются эти ошибки.
Хотя это и не очень полезно, глядя на код Symfony, они получают доступ к частным переменным в методе close
своего обработчика PDO. Мне ваш код кажется правильным.
Просто хочу спросить (извините), возможно ли, что вместо этого он жалуется на что-то внутри Session_Database
?
@ChrisHaas разумная мысль, и спасибо, что посмотрели на другую кодовую базу для справки, но нет. В сообщении об ошибке конкретно говорится Session::$db
. Метод Session_Database::close()
является общедоступным, нестатическим и имеет только одну строку: $this->dbh = null;
. Это поле является частным, но оно также должно быть доступно в контексте этого метода.
Этот код, как показано, не выдаст такое сообщение об ошибке. Я предлагаю поработать над созданием минимально воспроизводимого примера, и таким образом вы, скорее всего, найдете источник своей проблемы. Включение фактического сообщения об ошибке в ваш вопрос также может помочь.
@ miken32 спасибо, что рассмотрели мой вопрос. Это периодически возникающая проблема, которую я не могу воспроизвести по своему желанию. Я включил фактическое сообщение об ошибке. Я только добавил форматирование и удалил путь к файлу.
Похоже, это происходит, если память исчерпана во время запроса PDO. Я считаю, что это как-то связано с памятью, используемой буферизованными запросами PDO, и тем, как внутренний код PHP освобождает память после ее исчерпания.
Я могу воспроизвести состояние, с которым вы столкнулись, с помощью следующего кода (примечание: здесь используется register_shutdown_function
. И код session_close, и register_shutdown_function
запускаются после ошибки исчерпания памяти):
<?php
class TestingClass
{
private int $something_private;
public function getThisDone(): void
{
$this->something_private = 0;
}
}
// get a reference to the testing class
$obj = new TestingClass();
register_shutdown_function(fn() => $obj->getThisDone());
// get a pdo connection and run a query that returns a lot of data
$pdoConnection = get_db_read_connection();
$pdoStatement = $pdoConnection->prepare('SELECT * FROM your_table_with_a_lot_of_records LIMIT 100000');
$results = $pdoStatement->fetchAll(PDO::FETCH_CLASS, '\stdClass');
И в результате фатальная ошибка:
Я не могу воспроизвести ошибку, если просто вызываю ошибку нехватки памяти при конкатенации строк, как показано ниже.
// use code above but replace pdo connection and query with this
while(true)
{
$data .= str_repeat('#', PHP_INT_MAX);
}
Я не думаю, что так должно быть. Похоже, это хороший кандидат для отчета об ошибках PHP.
С помощью
session_set_save_handler()
вы делаете определенные методы из вашего класса сеанса вызываемыми, но когда они вызываются, они не вызываются из объекта сеанса. Взгляните на Заметки, предоставленные пользователями.