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
Related
I've recently been redesigning an archaic PHP application, which had most of it's code in 1000+ line long PHP files for each page. I first started by refactoring much of the code into classes. I recently have been working on database connections, and began writing a class for it. I decided to throw $mysqli->close() into the destructor (I'm using the OO approach).
Unfortunately I've almost immediately ran in to problems with it. Instead of the MySQLi connection closing when the page finishes rendering (or when there are no more references to the DB object), it just immediately closes. I've tested this through writing a simple test:
$db = new DBConnect(); //My abstraction class
$db->getSQL()->query("SELECT 1"); //Query fails. Error message states connection closed.
My destructor looks like this:
public function __destruct() {
$this->mysqli->close();
}
My constructor looks like this:
public function __construct() {
$this->mysqli=new mysqli(\MainConfig::$database['host'], \MainConfig::$database['user'], \MainConfig::$database['pass'], \MainConfig::$database['db']);
if($this->mysqli->connect_error) {
die('Connect error (' . $this->mysqli->connect_errno . ') ' . $this->mysqli->connect_error); //This is not ever fired.
}
}
I know it's not some other bit of code closing the connection, since if I comment out the $this->mysqli->close() line, then the code works as expected. It seems to me that the destructor fires immediately which is not the desired behavior. Am I misunderstanding how they are intended to work?
I was able to reproduce the behavior you described with the code:
<?php
class DestructorTest {
public function getter() {
print "DestructorTest::getter() called\n";
return new CallableTest();
}
public function __destruct() {
print "DestructorTest destructor called\n";
}
}
class CallableTest {
public function method() {
print "CallableTest::method() called\n";
}
}
(new DestructorTest())->getter()->method();
which prints:
DestructorTest::getter() called
DestructorTest destructor called
CallableTest::method() called
The long and the short of it is: A destructor may be called as soon as there are no references to an object. This can even happen in the middle of a line -- in this case, for instance, after DestructorTest:getter() is called, the DestructorTest object is no longer reachable, so it is destroyed.
My advice:
You don't need to close MySQLi handles. They already have an internal destructor which will close them when they are garbage-collected.
In fact: avoid writing destructor methods in general. (This applies to many programming languages, not just PHP.) They are frequently not called when you expect them to be, and have a tendency to cause strange, hard-to-debug behavior.
If you're going to ignore this and write a destructor anyways, then you need to make sure that you don't inadvertently destroy something which you've "leaked" a reference to outside your class. In the case of your code, you've allowed code outside the class to get a reference to your MySQLi handle, but you're destroying that handle as soon as your object goes away -- even if the handle is still being used outside.
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.
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 a PHP script that registers approximately 20 functions. Ideally it'd be loaded with require_once. I want make it so that even if somehow it does get loaded more than once, it wouldn't try to re-register the functions. I could wrap each declaration in !function_exists, but I'm wondering if there's a faster way. (Or do you think 20 calls to !function_exists is negligible?) I tried using exit but that causes an error. Is it possible to exit w/o throwing an error ?
if ( /* already loaded */ ) {
/* leave gracefully */
}
/* declare ~20 functions */
if (!defined('ALREADY_LOADED')) {
define('ALREADY_LOADED', true);
// rest of your code goes here
}
This checks to see if a constant ALREADY_LOADED is defined, and if it is not, it defines the constant and will do whatever else you want.
After it's been run once, the constant will be defined, and it will not run a second time.
I suggest using a more descriptive constant name than ALREADY_LOADED.
I think using OOP is the most practical way
Can be used as a class with static functions
class SimleClass{
public static function func1($arg){...}
}
use it
SimpeClass::func1($arg);
or sigleton
class SimleClass{
protected static $_instance=null;
private function __construct(){...}
public static function getInstance(){
if(is_null(self::$_instance)
self::$_instance=new SimpleClass();
return self::$_instance;
}
public function func1($arg){...}
}
use it
SimpleClass::getInstance()->func1($arg);
and how to connect it think itself
can use include_once
and can implement the autoloader class
function myClassLoader($className){
include_once "/lib/$className.php";
}
spl_autoload_register(myClassLoader);
=============================================================
for more concrete answer requires more data.
Perhaps your application, you can rearrange to get the more logical structure
If you as an author don't require it more then once, (or use require_once() consistantly) there shouldn't be a problem about re-registering functions.
As for exiting without an error, try die().
I would try not to redeclare functions in first step (here require more than once).
Doing 20x function_exists() does not cost anything, only some time writing and wrapping ;)
Perhaps you could try to use classes/methods instead.
function_exists is no bad.
You can write your php script files in the following manner.
/* file1.php */
if(!defined('FILE1')) {
define('FILE1', 1);
/////////////////////////
// PUT file contents here.
/////////////////////////
}// file.php finished.
Now you can include this file as many time as you want here and there. Nothing will be redefined again.
I'm just becoming dive into php after ages working in vb.net.
I wanna write a logger class that runs as singleon over my webapp, here the code:
class cLog{
private $data = NULL;
static private $instance = NULL;
static public function getInstance(){
if(self::$instance == NULL){
echo "empty!";
self::$instance = new cLog();
}
return self::$instance;
}
private function __construct(){
}
private function __clone(){
}
public function getData(){
return self::getInstance()->data;
}
public function trace($o){
self::getInstance()->data[] = $o;
}
}
What I expect is that, as i switch between pages of my application that make several calls to the cLog::trace() method, the data array increases and it's filled with all traces. But what I get is: everytime i run a page, the $instance is null so the object restarts (as you can see, I put an echo "empty!" line in the instance getter: it shows everytime)
I guess there's something I'm misunderstanding in the php application-lifecycle....
Here there's an usage example:
cLog::getInstance()->trace("hello world");
$logs = cLog::getInstance()->getData();
Thanks
PHP uses a "share nothing" architecture. This means (among other things) that nothing is shared between page loads. Unlike .NET, where the application is started on the first page hit and runs until stopped, just servicing requests as they come. In PHP, every time a page is requested the application is essentially compiled and run from scratch.
The PHP life cycle is from "page start to load" to "page ended load".
Generally speaking, every time you load a new page, everything starts from scratch.
You might be able to do some... interesting... things with session data to get your logger to work the way you want it to.
Good luck!
But what I get is: everytime i run a page, the $instance is null so the object restarts
...
I guess there's something I'm misunderstanding in the php application-lifecycle....
PHP's application-lifecycle mirrors that of HTTP. Each request for a page/URI is stateless. Each request knows nothing about the other requests. This is by design. The behavior you described is PHP acting as it should.
You need to take extra steps to have each request know about what happened in other requests. (PHP's session handling is one way to do this)
Instead of addressing your question on application life cycle in PHP, I would like to make a recommendation on using a prebuilt logging class.
The Zend Framework has Zend_Log which uses the Factory pattern and has a wide variety of Writer objects to log to databases, the filesystem, email, and so forth.
http://framework.zend.com/manual/en/zend.log.writers.html
You can use Zend_Log without needing any other part of the library, so it should be easy to adapt to your current system.