I have seen several answers on object destruction order, and all point out that order is not guaranteed. Since I cannot control the order, I would like to invoke a function after all objects have been destroyed.
register_shutdown_function is invoked prior to object destruction, thus not an option. I have looked at tricks like set_error_handler using the object so it is invoked "late", but that is not sufficient.
Some background on the problem, this is a complex CMS with dozens of separate files for routes (view) layer. There is a common boot include, but not a common one run at shutdown. I am using APCu object caching through a common inherited base class, and need to make sure an object is purged. It is possible that for any two instances of the same object created during a page load, one might want to purge itself, and the other might want to cache itself. Obviously purge trumps all else, so I need to call apc_delete on a global set of cache keys to purge one all __destruct()'ion is complete.
As I said in my comment above, the mixed state of multiple object instances sounds like a design flaw. I think you always want all instances of an object to be the latest, or at least not touch the cache if they aren't. I would think your caching and/or object loading layer could handle this.
To answer your underlying question, I wrote a script to test PHP's shutdown sequence:
<?php /* Adapted from https://evertpot.com/160/ */
ob_start(
function($buffer) {
return $buffer . "output buffer flushed\n";
}
);
$empty = function() {
return true;
};
$close = function() {
echo "session close\n";
return true;
};
$write = function() {
echo "session write\n";
return true;
};
session_set_save_handler($empty, $close, $empty, $write, $empty, $empty);
session_start();
register_shutdown_function(
function() {
echo "register_shutdown_function\n";
}
);
class MyClass {
function __destruct() {
echo "object destructor\n";
}
}
$myObject = new MyClass;
The output:
register_shutdown_function
object destructor
output buffer flushed
session write
session close
It seems the flush of output buffering and session write/close are 2 places where you know all of your objects have been destroyed. (This also assumes you're not using the newer form of session_set_save_handler that can register itself as a shutdown function.)
Did you try to call the function in the __destruct() function? PHP calls this function after destroy all the objects, so it may help.
Related
I have a code like this:
class Server {
private $stopper;
public function setStopper() { $this->stopper = TRUE; }
public function startServer() {
$consumer = new Consumer();
$consumer->onConsume(function($data) {
global $consumer;
// some processing
if( ?? ) { // how to access stopper here??
$consumer->stop();
// also how to access stopServer() here??
}
});
$consumer->consume();
}
public function stopServer() { ... }
}
This code is in a file that should run forever unless the setStopper() is called. So far I have set_time_limit to stop the code after a while. But I need to implement setStopper way so I can stop the server whenever needed, not "after a while".
I need this because, the onConsume is connected to a streaming API and runs the anonymous call back whenever new data is available and I don't want kill the php app on timeout due to some lock issues. I want to gracefully stop the server.
Can anyone please tell how to access the stopper or stopServer inside the callback? Can I use following syntax?
...(function($data) use ($this) {...
I also thought of storing the class value inside callback, but the setStopper is called dynamically and the value might not be updated!
Is there a better way to handle this situation?
Follow Up: php - Dynamically update Singleton class' value
You can create a Closure around the $consumer object as well as the lexical object $this (if you're using PHP < 5.4, you need to rename $this to something else, because you cannot use($this)):
$self = $this;
// You may not need to do this, I cannot remember off-hand whether
// closures have access to private variables or not
$stopper = $this->stopper;
$consumer->onConsume(function($data) use($consumer, $self, $stopper) {
if( $stopper ) {
$consumer->stop();
$self->stopServer();
}
});
See Example #3 on the linked to manual page.
I should also note here for completeness that if this is a long-lived process, then the objects being referenced inside the closure will hang around long after the function exits. For instance:
function makeAdder($x) {
return function($n) use($x) {
return $x + $n;
};
}
$adder = makeAdder(5);
echo $adder(2); // Output 7
echo $adder(5); // Output 10
echo $adder(4); // Output 9
This is a classic example of a closure. Normally, once the makeAdder function returns its inner variable $x will fall out of scope and be ready for garbage collection. Since it is however bound inside the anonymous function's scope, it will hang around indefinitely (until the script's termination) or the reference to the containing scope is also released (i.e. via unset($adder)). This means that once your function is called, extra references to $consumer, $this and $stopper will hang around until the class instance itself is destroyed.
Not being aware of this can lead to some serious performance issues.
the same problem here i use output buffers from ob_start/ob_end_flush
and one function i have should be dynamic (however parameters i push into should insert them in an array for later use for parsing buffers using $buffer)
in the parser associated to ob_start at a time i have these lines of code from one array full of data :
if(!empty($this->__b2))
array_filter ($this->__b2,function($var)use(**&$buffer**){
$buffer = preg_replace("/<\/body>/i", $var.'</body>', $buffer);
});
I use a only one class singleton ,and i use "::" a lot.
How you see in my case
array_filter was out of order without &$buffer
I have two methods:
public function a()
{
$db = new Database();
$db->query ('....');
// $db->close();
}
public function b()
{
$db = new Database();
$db->query ('....');
// $db->close();
}
they called in order:
$obj->a();
$obj->b();
I intentionally commented the close() methods. This Database class has a destruct method:
class Database
{
public function __destruct()
{
$this->close();
}
public function close()
{
}
}
I want automatic close database connections between method calls. To do so, the 100% sure way is to call the Database::close method, but I want to do it automatic and be done when method its over. Is this safe way? Because I dont know when garbage collector actually deletes that $db object. What if its still exits when b() runs? Theoretically, garbage collector do the cleaning ups when he feels like...
EDIT
the database closing is just an example! I want to do something else, but this was a good example, dont focus on the closing itself!!
It is not a good idea to close DB connections after each method call.
Usually people create and keep one connection for all script lifetime.
Of course,I assume there is one DB in your project.
You idea is a bad design example. I would recommend you to review you architecture design.
In my experience, you generally should not close/destroy an object that is reusable until you are finished with it completely, although there are some exceptions.
If you know that you will be calling the process multiple times, then you should not destroy the object until after the last call has been made. An exception to this would be if inside the object, you are working with another object or large amounts of data which need to be forcibly free'd on completion of each loop, then you should destroy only that object which is consuming or potentially consuming a large amount of resources once you have finished that cycle.
As far as the __destruct() function, you should put all the code in there needed to destroy the object. Calling another function from within that object is what we programmers call a cyclic reference where you have the memory of one space pointing back to itself and can cause the garbage collection to fail.
The highest level of control you have over freeing memory from within PHP is to use the unset() command on the object you wish to have destroyed. Using unset() on an object pointer to a class will call that classes __destruct() function.
Executing unset() on an object tells the GAC to give a higher priority when resources are required to cleanup those objects referenced using that command. This is what makes this useful when using memory intensive loops, or poorly written classes within your objects.
What is the exact order of object deconstruction?
From testing, I have an idea: FIFO for the current scope.
class test1
{
public function __destruct()
{
echo "test1\n";
}
}
class test2
{
public function __destruct()
{
echo "test2\n";
}
}
$a = new test1();
$b = new test2();
Which produces the same results time and time again:
test1
test2
The PHP manual is vague (emphasis mine to highlight uncertainty): "The destructor method will be called as soon as there are no other references to a particular object or in any order during the shutdown sequence."
What is the exact order of deconstruction? Can anyone describe in details the implementation of destruction order that PHP uses? And, if this order is not consistent between all the PHP versions, can anyone pinpoint which PHP versions change in this order?
First of all, a bit on general object destruction order is covered here: https://stackoverflow.com/a/8565887/385378
In this answer I will only concern myself with what happens when objects are still alive during the request shutdown, i.e. if they were not previously destroyed through the refcounting mechanism or the circular garbage collector.
The PHP request shutdown is handled in the php_request_shutdown function. The first step during the shutdown is calling the registered shutdown functions and subsequently freeing them. This can obviously also result in objects being destructed if one of the shutdown functions was holding the last reference to some object (or if the shutdown function itself was an object, e.g. a closure).
After the shutdown functions have run the next step is the one interesting to you: PHP will run zend_call_destructors, which then invokes shutdown_destructors. This function will (try to) call all destructors in three steps:
First PHP will try to destroy the objects in the global symbol table. The way in which this happens is rather interesting, so I reproduced the code below:
int symbols;
do {
symbols = zend_hash_num_elements(&EG(symbol_table));
zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor TSRMLS_CC);
} while (symbols != zend_hash_num_elements(&EG(symbol_table)));
The zend_hash_reverse_apply function will walk the symbol table backwards, i.e. start with the variable that was created last and going towards the variable that was created first. While walking it will destroy all objects with refcount 1. This iteration is performed until no further objects are destroyed with it.
So what this basically does is a) remove all unused objects in the global symbol table b) if there are new unused objects, remove them too c) and so on. This way of destruction is used so objects can depend on other objects in the destructor. This usually works fine, unless the objects in the global scope have complicated (e.g. circular) interrelations.
The destruction of the global symbol table differs significantly from the destruction of all other symbol tables. Normally symbol tables are destructed by walking them forward and just dropping the refcount on all objects. For the global symbol table on the other hand PHP uses a smarter algorithm that tries to respect object dependencies.
The second step is calling all remaining destructors:
zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC);
This will walk all objects (in order of creation) and call their destructor. Note that this only calls the "dtor" handler, but not the "free" handler. This distinction is internally important and basically means that PHP will only call __destruct, but will not actually destroy the object (or even change its refcount). So if other objects reference the dtored object, it will still be available (even though the destructor was already called). They will be using some kind of "half-destroyed" object, in a sense (see example below).
In case the execution is stopped while calling the destructors (e.g. due to a die) the remaining destructors are not called. Instead PHP will mark the objects are already destructed:
zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC);
The important lesson here is that in PHP a destructor is not necessarily called. The cases when this happens are rather rare, but it can happen. Furthermore this means that after this point no more destructors will be called, so the remainder of the (rather complicated) shutdown procedure does not matter anymore. At some point during the shutdown all the objects will be freed, but as the destructors have already been called this is not noticeable for userland.
I should point out that this is the shutdown order as it currently is. This has changed in the past and may change in the future. It's not something you should rely on.
Example for using an already destructed object
Here is an example showing that it is sometimes possible to use an object that already had its destructor called:
<?php
class A {
public $state = 'not destructed';
public function __destruct() { $this->state = 'destructed'; }
}
class B {
protected $a;
public function __construct(A $a) { $this->a = $a; }
public function __destruct() { var_dump($this->a->state); }
}
$a = new A;
$b = new B($a);
// prevent early destruction by binding to an error handler (one of the last things that is freed)
set_error_handler(function() use($b) {});
The above script will output destructed.
What is the exact order of deconstruction? Can anyone describe in detail the implementation of destruction order that PHP uses? And, if this order is not consistent between any and all PHP versions, can anyone pinpoint which PHP versions this order changes in?
I can answer three of these for you, in a somewhat roundabout way.
The exact order of destruction is not always clear, but is always consistent given a single script and PHP version. That is, the same script running with the same parameters that creates objects in the same order will basically always get the same destruction order as long as it runs on the same PHP version.
The shutdown process -- the thing that triggers object destruction when script execution has stopped -- has changed in the recent past, at least twice in a way that impacted the destruction order indirectly. One of these two introduced bugs in some old code I had to maintain.
The big one was back in 5.1. Prior to 5.1, the user's session was written to disk at the very start of the shutdown sequence, before object destruction. This meant that session handlers could access anything that was left over object-wise, like, say, custom database access objects. In 5.1, sessions were written after one sweep of object destruction. In order to retain the previous behavior, you had to manually register a shutdown function (which are run in order of definition at the start of shutdown before destruction) in order to successfully write session data if the write routines needed a (global) object.
It is not clear if the 5.1 change was intended or was a bug. I've seen both claimed.
The next change was in 5.3, with the introduction of the new garbage collection system. While the order of operations at shutdown remained the same, the precise order of destruction could now change based on ref counting and other delightful horrors.
NikiC's answer has details on the current (at time of writing) internal implementation of the shutdown process.
Once again, this is not guaranteed anywhere, and the documentation very expressly tells you to never assume a destruction order.
For anyone interested - as at PHP 8.0:
class A {
function __destruct() {
print get_class();
}
}
class B {
private $child;
function __construct() {
$this->child = new A();
}
function __destruct() {
print get_class();
}
}
class C {
private $child;
function __construct() {
$this->child = new B();
}
function __destruct() {
print get_class();
}
}
new C;
results in output of
CBA
ie. the containing object destructor fires before the contained object destructor.
To reverse the order if desired ie. to ABC, change the destructor in all but A (innermost class) to be:
function __destruct() {
unset($this->child);
print get_class();
}
Most resources on PHP never touch memory management because the language itself is pretty good at doing this for you. However, in PHP you often end up dealing with external resources which aren't memory -- database handles, sessions, database transactions, etc. These external resources could be managed most cleanly using some form of RAII object.
I initially thought that PHP used a garbage collection scheme similar to the JVM or the CLR, where the concept of a destructor does not exist. (Remember: Everyone thinks about garbage collection the wrong way -- finalizers are not destructors!) There's the special __destruct method, but I thought that was a "finalizer" similar to a Java or C# finalizer. For this reason, you cannot use RAII on the JVM or the CLR (C#'s using blocks get you about 95% of the way there, but that's a bit different...).
However, Google seems to indicate that PHP supports the RAII pattern, though I cannot find verification of this in the PHP docs. Does the language support this and is putting the cleanup logic in __destruct sufficient for accomplishing RAII tasks?
This is nearly the same question as Is destructor in PHP predictable? and the answer is the same. PHP uses refcounting, and it promises that the destructor will be called immediately as soon as the refcount goes to zero (generally when the object goes out of scope). So if you create an object and take care not to leak it out of scope, RAII is viable.
PHP uses reference counting, so when you're done with a variable it gets cleaned up immediately. (Unless you create cycles.) That frees up resources promptly so you generally don't need to worry about explicit resource management beyond being careful to not create memory cycles.
If you did want to implement any particular strategy, you can do it by making sure that the resource is only used by one variable. Whenever that variable is pointed away from the resource, the resource should be immediately freed up.
The following class ReturnHandler provides automatic invocation of a handler when ReturnHandler's instance goes out of scope. You can have several returns in your function (myfunc) without the need to think of releasing the resource before each of them.
/**
* Automatically calls a handler before returning from a function. Usage:
*
* function myfunc()
* {
* $resource = new Resource();
* $rh = new ReturnHandler( function() use ($resource) { $resource->release(); } );
* // ...
* if(...) {
* return; // look, ma, automatic clean up!
* }
* }
*/
class ReturnHandler
{
private $return_handler;
public function __construct( $return_handler )
{
$this->return_handler = $return_handler;
}
public function __destruct()
{
$handler = $this->return_handler;
$handler();
}
}
Here's a test for it:
class ReturnHandlerTest extends PHPUnit_Framework_TestCase
{
private static function trigger_return_handler(&$var)
{
$rh = new ReturnHandler(function() use (&$var) { $var++; } );
}
public function test()
{
$a = 0;
$this->assertEquals(0, $a);
self::trigger_return_handler($a);
$this->assertEquals(1, $a);
}
}
Slightly offtopic: you can do a using-like pattern with lambdas. Like this:
function WithFile($Name, $Func)
{
$File = fopen($Name, 'r');
$r = $Func($File);
fclose($File);
return $r;
}
And then use it like this
$FileHeader = WithFile('myfile', function($File) {return fread($File, 16);});
Perfectly deterministic. That said, were there a terser syntax for lambdas...
Please give me some real life examples when you had to use __destruct in your classes.
Ok, since my last answer apparently didn't hit the mark, let me try this again. There are plenty of resources and examples on the internet for this topic. Doing a bit of searching and browsing other framework's code and you'll see some pretty good examples...
Don't forget that just because PHP will close resources on termination for you doesn't mean that it's bad to explictly close them when you no longer need them (or good to not close them)... It depends on the use case (is it being used right up to the end, or is there one call early on and then not needed again for the rest of execution)...
Now, we know that __destruct is called when the object is destroyed. Logically, what happens if the object is destroyed? Well, it means it's no longer available. So if it has resources open, doesn't it make sense to close those resources as it's being destroyed? Sure, in the average web page, the page is going to terminate shortly after, so letting PHP close them usually isn't terrible. However, what happens if for some reason the script is long-running? Then you have a resource leak. So why not just close everything when you no longer need it (or considering the scope of the destructor, when it's no longer available)?
Here's some examples in real world frameworks:
Lithium's lithium\net\Socket class
Kohana's Memcached Driver
Joomla's FTP Implementation
Zend Frameworks's SMTP Mail Transport Class
CodeIgniter's TTemplate Class
A Tidy Filter Helper for Cake
A Google-Groups Thread about using Destructors For the Symfony Session Class
The interesting thing is that Kohana keeps track of the tags, so that it can delete by "namespace" later (instead of just clearing the cache). So it uses the destructor to flush those changes to the hard storage.
The CodeIgniter class also does something interesting in that it adds debugging output to the output stream in the destructor. I'm not saying this is good, but it's an example of yet another use...
I personally use destructors whenever I have long running processes on my master controller. In the constructor, I check for a pid file. If that file exists (And its process is still running), I throw an exception. If not, I create a file with the current processes id. Then, in the destructor I remove that file. So it's more about cleaning up after itself than just freeing resources...
There is another handy use to generate HTML page
class HTMLgenerator {
function __construct() {
echo "<html><body>";
}
function __destruct() {
echo "</body></html>";
}
}
With this class, you can write
$html = new HTMLgenerator();
echo "Hello, world!";
And the result is
<html><body>Hello, world!</body></html>
For example:
<?php
class Session
{
protected $data = array();
public function __construct()
{
// load session data from database or file
}
// get and set functions
public function __destruct()
{
// store session data in database or file
}
};
This is a good why to use destruct. You prevents reading and writing to a session source all the time and do this only at the start and at the end.
I create a php page what will generate a movie information jpg file. This page will have to gather a few information and run inkscape to convert template (an svg file) to a png before converting to jpg. The svg contain relative links to other image which must be a file. So my page download necessary files into a temporary folder, convert the svg file. At the end, the temporary folder must be deleted.
I put the temporary folder deletion into the destructor. Before there can be many reason the page ends unexpected and the only think I can be sure is that destructor will be call when page exit.
Hope this helps.
A destructor is extremely useful if you use a custom database connector/wrapper.
In the constructor, you can pass the connection information. Because you can use a destructor (rather than a finalizer, etc.,) you can rely on that to close the connection for you. It's more of a convenience, but it certainly is useful.
For example, when PHP decides to explicitly "free" the object (i.e., it is no longer used,) it will call the destructor at that time. This is more useful in the scenario I describe as you're not waiting for the garbage collector to run and call the finalizer.
$0.02
Ian
<?php
class Database
{
private $connection;
private $cache = array();
function __construct([$params])
{
//Connection here
}
//Query
public function query(Query $Query)
{
if($this->is_cached($Query->checksum))
{
return $this->get_cache($Query->checksum);
}
//...
}
public function __destruct()
{
unset($this->connection);
$this->WriteCache();
unset($this->cache);
shutdown_log($this,'Destruction Completed');
}
}
?>
theres an example that should make you understand.
If you use handles returned by fopen() for say, logging, you can use __destruct() to make sure fclose() is called on our resources when your class is destroyed.
You are right, __destruct is mostly unnecessary for the short running php scripts. Database connections, file handles and so on close on script exit or sometimes even earlier if variables run out of scope.
One example i can think of is writing logs to the database. Since we didn't want to fire one query per log entry that gets created somewhere in the script we wrote the "write to db" part in the __destruct of the logging class so when the script ends everything gets inserted into the database at one.
Another example: If you allow a user to upload files the destructor is sometimes a nice places to delete the temp file (in case something goes wrong in the script it at least get cleaned up)
But even for filehandles it can be useful. I've worked on a application that did use the old fopen etc. calls wrapped in objects and when using those on large filetrees php would run out of filehandles sooner or later, so cleaning up while the script was running was not only nice but necessary.
I use APC caching for large numbers of "low level" objects, that otherwise would use excessive memory; and I have a cacheCollection object that handles the reading and writing of those "low level" objects to and from APC during execution of the script. When the script terminates, the objects must be cleared down from APC, so I use the cacheCollection __destruct method to perform that function.
I have used __destruct() in a logging class that wrapped a database connection:
<?php
class anyWrap
{
private $obj,$calls,$log,$hooks;
function anyWrap($obj, $logfile = NULL)
{
if(is_null($logfile))
{
$this->log = dirname(__FILE__) . "/../logs/wrapLog.txt";
}
$this->hooks = array();
$this->dbCalls = 0;
$this->obj = $obj;
}
public function __set($attri, $val) {
$this->obj->$attri = $val;
}
public function __get($attri) {
return $this->obj->$attri;
}
public function __hook($method)
{
$this->hooks[] = $method;
}
public function __call($name,$args)
{
$this->calls++;
if(in_array($name,$this->hooks))
{
file_put_contents($this->log,var_export($args,TRUE)."\r\n",FILE_APPEND);
}
return call_user_func_array(array($this->obj,$name),$args);
}
//On destruction log diagnostics
public function __destruct()
{
unset($this->dbReal);
file_put_contents($this->log,$this->calls."\r\n",FILE_APPEND);
}
}
The script hooks into the database calls and logs the prepare statements, then when the script has run to an end (I don't always know when) it will finally log the number of calls to the database to the file. This way I can see how many times certain functions has been called on the database and plan my optimization accordingly.
If you are creating a view using a PHP script in a MySQL database, you must drop that view at the end of the script. Because if not, the next time that script is executed view will not be created, as there is already a view of similar name in the database. For this purpose you can use destructor.
Here's a rather unusual use case for destructors that I think libraries such as pest are using to combine method chaining with functions or in other words, to achieve fluent interface for functions, Which goes like this:
<?php
class TestCase {
private $message;
private $closure;
private $endingMessage;
public function __construct($message, $closure) {
$this->message = $message;
$this->closure = $closure;
}
public function addEndingMessage($message) {
$this->endingMessage = $message;
return $this;
}
private function getClosure() {
return $this->closure;
}
public function __destruct() {
echo $this->message . ' - ';
$this->getClosure()();
echo $this->endingMessage ? ' - ' . $this->endingMessage : '';
echo "\r\n";
}
}
function it($message, $closure) {
return new TestCase($message, $closure);
}
it('ok nice', function() {
echo 'what to do next?';
});//outputs: ok nice - what to do next?
it('ok fine', function() {
echo 'what should I do?';
})->addEndingMessage('THE END');//outputs: ok fine - what should I do? - THE END