1

I try set session var in __destruct() method. Method __destruct() is running, but session var not set. While, session in __contruct() or other methods (e.g. test()) working as expected.

public function test()
{
    $_SESSION['MyVarTest'] = rand(200,300); ← working correctly
}

public function __destruct()
{
    echo 'called';
    $_SESSION['MyVar'] = rand(1,100); ← not working
}

Updated version. Now i try native PHP Session and Symfony component, and both not working in __destruct() method.

<?php

namespace Project\Modules\Cart\Storage;

use Illuminate\Support\Collection;

class Session
{

    /**
     * @var \Symfony\Component\HttpFoundation\Session\Session
     */
    protected $session;

    protected $cart;

    public function __construct()
    {
        $this->cart  = new Collection();

        $this->session = app('session');
        print_r($_SESSION);

    }

    public function test()
    {
        $this->session->set('json', rand(1,100));  ← working correctly
        $_SESSION['json'] = rand(1,100);  ← working correctly
        return $this->cart->toJson();
    }

    public function __destruct()
    {
        echo 'called';
         $_SESSION['MyVar'] = rand(1,100); ← not working

        $this->session->set('cart', serialize($this->cart->toArray()));  ← not working
    }

}
Stanislav
  • 923
  • 1
  • 11
  • 28
  • So show us how you test all this. – u_mulder Aug 26 '16 at 14:42
  • How do you know `__destruct()` is being called for sure? – Darragh Enright Aug 26 '16 at 14:47
  • Yes, the example is far from complete. One question I can think of: How do you stop the script? The best would be a complete example, we can run. – KIKO Software Aug 26 '16 at 14:49
  • `var_dump($this->session)` in `__destruct` – u_mulder Aug 26 '16 at 14:51
  • You should probably include more of your code as well - you have only shown a couple of methods from your class. I tried replicating your with some similar code - in my example I found that after I created and then `unset()` the object, `__destruct()` was called and a session key set. – Darragh Enright Aug 26 '16 at 14:51
  • Example: https://3v4l.org/5FCFF – Darragh Enright Aug 26 '16 at 14:52
  • @u_mulder: updated. __destruct() is called, show echo's - its showing that code running (i trying comment echo's). – Stanislav Aug 26 '16 at 14:55
  • @DarraghEnright, I found out that session is already closed in __destruct() method. But i'm dont close the session anywere... If I add session_start() in __destruct() method - it work correctly. But I dont like this solution. – Stanislav Aug 26 '16 at 15:32

1 Answers1

4

Symfony sessions are using custom session handlers. (via session_set_save_handler)

Custom session handlers cause PHP to register a shutdown function (i.e. register_shutdown_function), invoking session_register_shutdown, which adds another shutdown handler (so it will be executed last), calling session_write_close, effectively closing your session then.

After that function has been called, no further writes will be stored. [as the session handler won't be called anymore afterwards.]

And as destructors (of objects not cleaned up yet) run only after the shutdown functions were invoked, this session write will fail.

The only solution to avoid this is either not using a custom session handler (not an option for you I guess), restarting the session manually (as long as order of destruction does not destroy the class first), or explicitly destroying all the references to this object in shutdown handlers or before.

bwoebi
  • 23,637
  • 5
  • 58
  • 79
  • Sorry, but I dont understand, what I should doing for resolve my problem. Can you help me? – Stanislav Aug 26 '16 at 16:56
  • Well, you cannot really _fix_ that behavior. You have to work around it. Either just avoid setting $_SESSION in __destruct, or ensure that the affected objects are destroyed before the last shutdown function (e.g. by explicit unset()'ing). What exactly needs to be done in your application depends on your code. You'll have to figure that out yourself. – bwoebi Aug 26 '16 at 18:07
  • I truly understand that this behavior creates Symfony's Session component? – Stanislav Aug 26 '16 at 18:32
  • Because, when using native PHP this problem is absent: https://3v4l.org/5FCFF. I'm right? – Stanislav Aug 26 '16 at 18:38
  • @Stanislav That example is flawed. The $_SESSION superglobal still exists, changes to it just won't be present in the next request. But yes, with native PHP the problem is absent, as long as `session_set_save_handler()` is not being called. – bwoebi Aug 26 '16 at 18:41
  • Ok, I think I understand. Thanks my friend! – Stanislav Aug 26 '16 at 19:07