Запись в Zend_Session_Namespace при уничтожении

Я заметил несколько неожиданное поведение при использовании __destruct для записи данных с использованием Zend_Session_Namespace в PHP 5.3:

public function __destruct(){
    $this->getSession()->data = $this->data;
}
// ....
private function getSession()
{
    if (! self::$zendSession) {
        // this next line is fine because the object is a singleton
        self::$zendSession = new Zend_Session_Namespace(self::SESSION_NAMESPACE);
    }
    return(self::$zendSession);
}

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

Я предполагаю, что это как-то связано с этой ошибкой: http://bugs.php.net/29032 ( ошибка кажется мне немного старой), и на первый взгляд исправление выглядит хорошо (зарегистрируйте __destruct как функцию выключения, которая вызывается до того, как $_SESSION станет недоступной), но разве деструктор не будет вызываться дважды (один раз через register_shutdown_function и один раз автоматически?

Конечно, запись нечетного бита данных объекта в сеанс при завершении работы — это проблема, которая была решена? Что люди делают, когда это требуется?

(OSX 10.6.6, Apache 2.2.15 (Unix), PHP 5.3.3, Zend Framework 1.7.2)


person sennett    schedule 24.02.2011    source источник
comment
Есть дополнительные сложности, связанные с zend_controller_action->_redirect(), но я не хотел делать пост слишком неудобным для понимания. По сути, я заметил, что если есть цепочка запросов, использование zend_controller_action->_redirect() для перехода к следующему приводит к выходу деструктора на строке, где он ссылается на Zend_Session_Namespace. Для последнего запроса в цепочке (где zend_controller_action->_redirect() не вызывается, деструктор завершается нормально, и данные записываются в session.   -  person sennett    schedule 24.02.2011


Ответы (1)


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

Обходной путь register_shutdown_function в порядке. Чтобы избежать повторного запуска кода, вы должны переместить код завершения сеанса в другую функцию, которую вы регистрируете. В любом случае вызов __destruct() вручную для объекта, который все еще существует, кажется немного уродливым;)

person Long Ears    schedule 24.02.2011
comment
Большое спасибо. Я зарегистрирую функцию (не __destruct), которая записывает данные сеанса как функцию завершения работы. Я понимаю, что вы говорите о курице и яйце. Я попытался создать экземпляр нового объекта Zend_Session_Namespace вместо того, чтобы извлекать экземпляр из переменной класса, что, как я полагаю, приведет к вызову деструктора позже в процедуре завершения работы? Это не имело никакого значения, поэтому я предполагаю, что поведение связано с самой $_SESSION. Спасибо за помощь - проголосовал бы, но недостаточно репутации :) - person sennett; 24.02.2011
comment
К сожалению, то же самое произошло и с функцией выключения. Я думаю, что это не столько проблема с использованием деструктора таким образом (поскольку он отлично работает, когда новый запрос не инициируется, как описано выше), а больше проблема с перенаправлением, и тем, как Zend инициирует новый HTTP-запрос, и способ, которым это обрабатывает PHP (в настоящее время изучаю это - php.net/manual /en/features.connection-handling.php). Это означает, что хотя ответ был правильным, я задал неправильный вопрос! - person sennett; 24.02.2011
comment
@sennett action-›_redirect() использует помощник перенаправителя, который по умолчанию сначала закрывает сеанс. Вы можете вызвать setCloseSessionOnExit(false) помощника, чтобы предотвратить это. - person Long Ears; 24.02.2011
comment
Спасибо, приятель, это то, что я искал - я не ожидал такого поведения от Zend. Почему это происходит? Для других людей: я использовал старую версию Zend Framework. Я использовал $this->_redirector->setGotoUrl($forwardTo,array('exit' => false)); из контроллера вместо setCloseSessionOnExit(false). - person sennett; 25.02.2011