php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #27555 Unable to modify $_SESSION from __destruct()
Submitted: 2004-03-10 18:42 UTC Modified: 2004-08-02 01:00 UTC
Votes:81
Avg. Score:4.7 ± 0.6
Reproduced:79 of 79 (100.0%)
Same Version:29 (36.7%)
Same OS:31 (39.2%)
From: jaanus at heeringson dot com Assigned: helly (profile)
Status: No Feedback Package: Documentation problem
PHP Version: 5CVS-2004-03-10 (dev) OS: Linux 2.4.24
Private report: No CVE-ID: None
 [2004-03-10 18:42 UTC] jaanus at heeringson dot com
Description:
------------
Unable to add session variables from the __destruct() handler in a class. The $_SESSION variable can be accessed and viewed in the __destruct() handler though.

Reproduce code:
---------------
<pre>
<?php
session_start();

class test{
	public function __destruct(){
		$_SESSION['destructor']='Yes';
	}
}
$class=new test();

if(empty($_SESSION['working'])) {
	$_SESSION['working']='Yes';
	print("New session?\n");
}

print_r($_SESSION);

?>
</pre>

Expected result:
----------------
Array
(
    [destructor] => Yes
    [working] => Yes
)

Actual result:
--------------
Array
(
    [working] => Yes
)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-03-10 19:50 UTC] sniper@php.net
If you put something like "echo 'this happens now';" line in the __destruct() call you will see that it's executed AFTER your print_r() line. This is correct behaviour.

 [2004-03-11 02:35 UTC] jaanus at heeringson dot com
Yes, but that is not the issue here, is it? What this bug is about is the unability to add session variables from __destruct(). Obviously you have to reload the page to se the effect on the real session. The [destructor] => Yes will NEVER appear in $_SESSION.
 [2004-03-11 03:16 UTC] derick@php.net
Destructors are run (when not unset-ing yourself) after the session module finalizes the session so everything done in constructors has no effect. I agree it's not optimal behavior, but I don't think we need to classify it as a bug. It is not documented though so I'm making this a documentation problem.
 [2004-03-11 04:28 UTC] helly@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

The destructor is executed too late in the shutdown sequence. If you want a destructor to modify some $_SESSION
then you need to manually refcount and free all references using unset() before the script terminates.
 [2004-03-11 04:34 UTC] derick@php.net
It's still not documented, leave it as an open doc bug.
 [2004-06-01 17:22 UTC] fschaper at intux dot org
Why not to call the destructors before the modules are shut down? I wrote a short patch for this and it works out fine (That does not mean however that it does not break something ,) ).

http://www.intux.org/download/patches/patch_php_cvs_01_06_04.rar
 [2004-06-15 11:06 UTC] dcaironi at yahoo dot com
I agree with fschaper.
The ability to modify the $_SESSION variable in the destructor could be very useful, for example to have your class automatically serialized in session; this, with a factory pattern (getInstance method, that unserialized the class if exists in session), allow to have a "session object", sort of.

for example

Class Test{

    function __destruct(){
        $_SESSION['test'] = serialize($this);
    }

    static function getInstance(){
        $instance = unserialize($_SESSION['test']);
        if(!isset($instance) || !is_a$instance,"test")){
            $instance = new Test();
        }
        return $instance;
    }
}

Actually, this was possible with php 4.x using register_shutdown_function, that (in fact) allows to simulate the destructor behaviour...
 [2004-06-15 11:07 UTC] dcaironi at yahoo dot com
I agree with fschaper.
The ability to modify the $_SESSION variable in the destructor could be very useful, for example to have your class automatically serialized in session; this, with a factory pattern (getInstance method, that unserialized the class if exists in session), allow to have a "session object", sort of.

for example

Class Test{

    function __destruct(){
        $_SESSION['test'] = serialize($this);
    }

    static function getInstance(){
        $instance = unserialize($_SESSION['test']);
        if(!isset($instance) || !is_a$instance,"test")){
            $instance = new Test();
        }
        return $instance;
    }
}

Actually, this was possible with php 4.x using register_shutdown_function, that (in fact) allows to simulate the destructor behaviour...
 [2004-07-08 05:17 UTC] mikey-spam at mookins dot com
I am on Windows 2000, using PHP5 RC3. Having same problems.

I also believe that the modules should be shutdown after __destruct()

I am wondering if this is going to be fixed or is it not being classified as a bug? helly@php.net seems to think it's expected behaviour but I never thought it would be which is why I am here after googling about it.
__destruct() is a user definable method. All aspects of user programs should have all the resources available to them from the start of the script right through to the end.

Refcounting of whatever it was that they suggested is not an option, in fact, I don't even know what that is.

-Mikey
 [2004-07-25 21:11 UTC] helly@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip


 [2004-08-02 01:00 UTC] phpdoc at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2005-07-07 07:47 UTC] aristotle at brettia dot com
I have a legitimate reason for wanting __destruct methods to be called before the session module is finalized.

I have a session wrapper class that uses an internal array to keep session data separate from $_SESSION until the destruction of the class.  The class' __destruct method is supposed to copy its internal array back to $_SESSION so that it can be saved.  This is not possible with the current order.
 [2005-07-07 09:12 UTC] richard dot quadling at bandvulc dot co dot uk
As classes are instatiated by a user, their destructing should be within the users control OR at least before the script terminates and module "tidying-up" takes place. I think this is actually a PHP bug.
 [2005-07-24 08:24 UTC] jasper at bryant-greene dot name
This is definitely a bug, and needs to be fixed. As has been mentioned before, all user-definable methods need to have all resources available to them, including the session module, mysqli module, etc.

Rather than just saying "the destructor is called too late in the shutdown process" and leaving it at that, why not fix it?
 [2005-10-04 23:59 UTC] iquito at gmx dot ch
I agree, this behaviour makes no sense at all and has to be classified as a bug. Of what use is a shutdown-function, if everything has already been shut down beforehand? Especially the connection to the database is normally very important for everything.

I use the register_shutdown-function to destruct all my classes in the correct order at the end of the script, so I don't have to rely on PHP to kill them in the correct order. This makes a lot of sense if you don't know where your script will end exactly.
 [2005-10-05 10:24 UTC] richard dot quadling at bandvulc dot co dot uk
One of the real issues here is that the destruction of objects created by the user is not in a logically sequence.

Having to manually free objects is sort of correct as relying on automated clearing/garbage collection can only, at best, guess the order in which things should be destroyed.

So, assuming somehow there was a way to determine the order of destruction, what happens when you have object interdependance.

Say, linking SESSION and DB. DB needs session details to know what the user is, but SESSION needs DB to update status of user.

If you DON'T use __desrtuct() at all and use normal methods you HAVE to decide which goes first (which is a better choice than letting the system guess), but requires more work.

I don't think there is an easy solution.

Richard.
 [2005-11-09 17:35 UTC] phpbugs at dubr dot com
Why is this being considered a documentation bug? It clearly 
is a PHP bug and needs to be fixed.
 [2005-11-20 16:43 UTC] lists at cyberlot dot net
How about
register_shutdown_function

This is affected also, This isn't something you can just "Document" away.

Basically your saying any user made or php made object is useless during the shutdown phase of php.

php5 is supposed to bring object programming close to php and this steps all over it.

Every single object related function, class, extension has now been made useless/impossible to call during shutdown be in within a session or in a use defined shutdown function.
 [2005-11-29 11:36 UTC] php at mike2k dot com
This is still a bug. I just upgraded to PHP 5.1.1, using a custom session handler with mysqli, and this is a problem.

It appears this is a workaround, albeit I don't think this should be required to function as it did before. I use procedural code, and not object oriented code, so having __destruct handlers do not help me.

register_shutdown_function('session_write_close');

Here's my [very simple] session handler. Note db_query() is a simple wrapper for mysqli_query() and handles all the connection details internally.

function session_close() {
  return true;
}

function session_die($id) {
  db_query("DELETE FROM session WHERE ID='$id'");
  return true;
}

function session_gc($maxlifetime) {
  return true;
}

function session_open($path,$name) {
  return true;
}

function session_read($id) {
  $dchk = db_query("SELECT data FROM session WHERE ID='$id'");
  if(db_numrows($dchk) == 1) {
    if(!isset($_SESSION['row'])) { $_SESSION['row'] = 1; }
    list($data) = db_rows($dchk);
    return base64_decode($data);
  } else {
    return "";
  }
  db_free($dchk);
  return true;
}

function session_write($id,$data) {
  global $visitor;
  $data = base64_encode($data);
  if(!isset($_SESSION['row'])) {
    db_query("INSERT IGNORE INTO session (ID,data,accessed) VALUES('$id','$data',UNIX_TIMESTAMP(NOW()))");
  } else {
   db_query("UPDATE session SET data='$data',accessed=UNIX_TIMESTAMP(NOW()) WHERE ID='$id'");
  }
  return true;
}

(fyi: I have a cronjob that does garbage collection based on the "accessed" column)

I still think this is a bug, I don't see why this was changed.
 [2006-01-19 00:51 UTC] graeme at druknet dot bt
This is certainly entering the realms of a bug now with 5.1.2. If I unset an object which has destruct that tries to update the session variable then the output is truncated. Proper headers are not set.

If I don't unset then I get the following unhelpful error message:

Warning: Unknown: Your script possibly relies on a session side-effect which existed until PHP 4.2.3. Please be advised that the session extension does not consider global variables as a source of data, unless register_globals is enabled. You can disable this functionality and this warning by setting session.bug_compat_42 or session.bug_compat_warn to off, respectively. in Unknown on line 0
 [2006-09-22 18:39 UTC] slawo at csuk-solutions dot net
I strugled for hours today looking for the souce of the problems within our current application, finally I noticed that some objects did not apear in the sessions variable as they should.
Finaly the conclusion is we relied on an inconsistent behavior in PHP.
Linux Mandrake 10 php 5.1
Will this bug be seen to soon?

This is not a bug, this is a feature...
 [2006-10-13 09:20 UTC] spidgorny at gmail dot com
I'm writing because of Status: No feedback.
In my opinion this is not strictly a bug, but a very unconvenient undocumented feature. The best is to fix it, because in some cases it would be nice to save to the session some of the properties of the class in the destructor.
Otherwise it must be documented in a way that it's flashing and really stands-out, because this behaviour is unlogical.

P.S. Spent few days to debug it out in a large application.
 [2006-12-06 22:50 UTC] php at kieran dot ca
This bug seems to be affecting the DOM functions as well.

<code>
class someNode extends DOMNode{

    function __destruct() {

        echo "now I have ".$this->attributes->length." attribute(s)";

    }

}

$x = new someNode('nodename');

$x->setAttribute('bob','frank');

echo "I have ".$x->attributes->length." attributes"; // outputs "I have 1 attribute(s)"

unset($x); // outputs "now I have  attribute(s)" 
</code>

This behaviour also seems to affect the __construct function as well.
 [2008-03-07 21:23 UTC] ondraster at gmail dot com
This bug (unwanted feature maybe?) is really annoying. For example I want, when __destroy, write to session last visited address.

This bug (feature) has been submitted in year 2004 and still has no fix or there has not been any reason why are all modules unloaded before __destroy is called? When running __destroy, script is still running so there's no reason why this function shouldn't have all resources.

I don't know, why this is classified as Documentation problem, when it is clearly BUG!
 [2008-03-07 21:54 UTC] ondraster at gmail dot com
Sorry for my last comment, I had bad PHP version in httpd.conf. I feel ashamed...
 [2009-10-20 19:44 UTC] gabriel at gabrielharrison dot co dot uk
Hi,

I can not find anything in the documentation about this. Was it added or was the feature changed in newer versions?

Thanks,

Gabriel
 [2010-04-03 16:49 UTC] bjoern at heyser dot ac
I'am also interested in infomation to the issue.

I use php 5.2 an run into the same issues when I write a session wrapper class.

Will the "(unwanted) feature" becomes removed or is there any sense for calling destructors after php modules are shutdown..

A further issue I think is the current working directory that isn't available in destructors as well as in custom registered shutdown functions.

best regards, björn

(sorry for my english)
 [2010-05-29 23:40 UTC] acetox94 at gmx dot de
What about destroying the object with unset? This should call the __destruct()-Function before the session ends..
 [2012-07-07 01:37 UTC] jonimane at gmail dot com
I have the same problem.

I am trying to set an SESSION variable in a destructor method, but it didnt work.

And what about feedback?
 [2015-08-08 10:19 UTC] sebikeller at myfucking dot email
Simple, **but annoying** workaround:

register_shutdown_function(function(){
	session_write_close();
});
 [2015-08-08 11:50 UTC] sebikeller at myfucking dot email
Seems like function registered via register_shutdown_function gets called before __destruct most of the time.
Works only if you destroy your object before the registered function gets called…
 [2016-12-17 22:56 UTC] nino dot skopac at gmail dot com
This has been fixed in PHP7 and PHP7.1 (I've tested it on both).
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Dec 04 19:01:32 2024 UTC