more information about object that was destroyed

rgb192
rgb192 used Ask the Experts™
on
problem:
I am learning about destructor method
and there are many ways to destroy object (unset, end of file)
and I echo
'in destructor method'

I look at long output file and do not understand which object destroyed




$obj=new className();
unset($obj);

can we echo anything about $obj in destructor
$obj which was created in __LINE__(line of creation) is destroyed


could we get more information using reflection class


an easy answer would be outside the class

echo '<br>information about object about to be destroyed'
var_dump($obj);
unset($obj);


but this answer does not cover example where object is destroyed at end of file




I am looking to learn instead of a quick fix to problem
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2011
Top Expert 2016

Commented:
Here is a code snippet showing what a destructor can do:
<?php // demo/temp_rgb192.php
error_reporting(E_ALL);

class Thing
{
    protected $info;

    public function __construct()
    {
        $this->info = 'Hello World';
    }

    public function __destruct()
    {
        error_log('DESTRUCTOR CALLED IN ' . __CLASS__ . ' AT ' . __LINE__);
    }
}

// CREATE AN INSTANCE OF THE CLASS
$obj = new Thing;

// SHOW THE OBJECT INSTANCE OF THE CLASS
var_dump($obj);

// UNSET THE OBJECT
unset($obj);

Open in new window

First instance of the error log was created by unset()
[01-May-2014 17:21:12 America/Chicago] DESTRUCTOR CALLED IN Thing AT 15

Open in new window

Next, I removed the unset() so that the destructor is called by the script terminator.  Same message (except for the timetamp).
[01-May-2014 17:23:44 America/Chicago] DESTRUCTOR CALLED IN Thing AT 15

Open in new window

Could you get more information from Reflection?  Possibly.  A more reasonable approach would be for you to tell us what you want to know and why.  Then we may be able to help you find the information.

Author

Commented:
<?php // demo/temp_rgb192.php
error_reporting(E_ALL);

class Thing
{
    protected $info;

    public function __construct()
    {
        $this->info = 'Hello World';
    }

    public function __destruct()
    {
        //error_log('DESTRUCTOR CALLED IN ' . __CLASS__ . ' AT ' . __LINE__);
        echo'DESTRUCTOR CALLED IN ' . __CLASS__ . ' AT ' . __LINE__;
    }
}

// CREATE AN INSTANCE OF THE CLASS
$obj = new Thing;

// SHOW THE OBJECT INSTANCE OF THE CLASS
var_dump($obj);

// UNSET THE OBJECT
unset($obj);

Open in new window


object(Thing)#1 (1) { ["info":protected]=> string(11) "Hello World" } DESTRUCTOR CALLED IN Thing AT 16

line 16 is the echo (i changed the error_log) which in inside the class

if possible I was looking for something about $obj in the class
where was it created (line number of creation outside the class)
'we are destructing an object named $obj which was created in line 21'

because in my learning I stopped looking at echo statements because they are confusing and using only on ide
Most Valuable Expert 2011
Top Expert 2016

Commented:
Sorry - I don't know how to do that.  Maybe Reflection can help, but Reflection seems to be about reverse-engineering, so I have never explored it in my work -- I already know what my code does and do not have to reverse-engineer it.  So the issue has never come up for me.
Rowby Goren Makes an Impact on Screen and Online

Learn about longtime user Rowby Goren and his great contributions to the site. We explore his method for posing questions that are likely to yield a solution, and take a look at how his career transformed from a Hollywood writer to a website entrepreneur.

Author

Commented:
    public function __get($var)
    {
        if (isset($this->$var))
        {
            echo '<h1>MAGIC METHOD __GET() CALLED FOR ' . "<i>$var</i>" . ': ' . $this->$var . '</h1>';
        }
        else
        {
            echo '<h1>MAGIC METHOD __GET() CALLED FOR UNDEFINED: ' . "<i>$var</i>" . '</h1>';
        }
    }

Open in new window


from another expert comment in  question about get

but destructor does not take argument
Greetings rgb192, , you say - "if possible I was looking for something about $obj in the class"

the Class Definition, is NOT the working memory created "Object" (the $obj in your code), so the "object" and the  "Class Definition" do have a relationship, but in the workings of PHP code they ARE NOT the same thing.

In the "Class Definition" of written code for that Class, if you want to access the current "object" reference of the PHP memory that's running that particular "object", you use the $this  variable.

But the code inside a Class Definition, has no meaning for line numbers and areas of code OUTSIDE the class.

you can have something like -

public function __destruct()
    {
        echo '__destruct for '.__CLASS__.', as object - ';
        var_dump($this);
    }

for a possible "learning" code write, as this would show the class Name and the property values in that Object (not the class).
However, the real reason that a  __destruct() method in available, is - - so IF there are "Open" references (database, connections) or "large memory Arrays", that should be CLOSED or released, then put them in the __destruct()

public function __destruct()
    {
    $this->mysqli->close();
    unset($this->large_memory_array);
    }

= = = = =
the use of the refection class, can give you some information, about sections and pieces of the "Class" and or current "Object", here is a list of the infos you can get -
http://php.net/manual/en/book.reflection.php

look at all of the methods under  "ReflectionClass — The ReflectionClass class"  such as -
ReflectionClass::getShortName — Gets short name

But almost all of these reflection methods will tell you about the "Class Code Definition" and little if any about any object instance. I have found little use for the reflection class, because I always seem to have the written class code to see and get more information, than using some method to get it. I really see no good reason for a Class tutorial for beginners to show any about the new and confusing "ReflectionClass"

Author

Commented:
Class Definition, is NOT the working memory created "Object" (the $obj in your code)

In the "Class Definition" of written code for that Class, if you want to access the current "object" reference of the PHP memory that's running that particular "object", you use the $this  variable.

so maybe var_dump($this);
yes, , you might also do a foreach()  on the $this  to get all of the properties (public, protected , private) and the values in JUST ONE object instance, not the Class.

foreach ($this as $key => $value) { }

but since the $value might be an array, or another Object , you may not can use echo to display it, unless you do another  foreach() on them.

something else I use the __destruct() for, is to insure that any useful info-data in the "Object" that has been added while using that object, is Saved to a file or DB Table -
function __destruct() {
  if($this->changed) {
    $aryBoth = array($this->arryCosts, $this->arryExpenses);
    file_put_contents('/home/domain/data/finance_FDB'.$this->id, serialize($aryBoth));
    }
 }

Open in new window

not sure about how to get the Line number where the unset($obj)  happens, when __destruct()  is used, that's a process OUTSIDE of the Class code definition.
But for learning you could place an  ID "name" in your Class that you set on __construct()
class learn { public $ID;

public function __construct($id) {
  $this->ID = $id;
  }

public function __destruct() {
  echo '__destruct()  for class ' . __CLASS__ . ' in object ID as ' .$this->ID;
  }
}

$var1 = new learn("var1");
unset($var1);
// the above should output=  __destruct()  for class learn in object ID as var1
sleep(3);

Open in new window

Most Valuable Expert 2011
Top Expert 2016
Commented:
Just for grins, I scanned my demonstration library for all occurrences of __destruct and out of more than 2,000 scripts, I found 12 such instances -- and 10 of them were in code provided for other purposes.  Not a "heavy user" of __destruct()!  One of the uses was to demonstrate how the destructor could be used to close a file.  Another was in this class, where the destructor can be used to catch the "end of script" condition and produce the readout of any of the timers that are still running.

<?php // demo/class_Stopwatch.php
error_reporting(E_ALL);


// DEMONSTRATE A SCRIPT TIMER FOR ALL OR PART OF A SCRIPT PHP 5+
// MAN PAGE http://php.net/manual/en/function.microtime.php


class StopWatch
{
    protected $a; // START TIME
    protected $s; // STATUS - IF RUNNING
    protected $z; // STOP TIME

    public function __construct()
    {
        $this->a = array();
        $this->s = array();
        $this->z = array();
    }

    // A METHOD TO PROVIDE A FINAL READOUT, IF NEEDED
    public function __destruct()
    {
        $ret = $this->readout();
        if (!$ret) return FALSE;
        echo
          __CLASS__
        . '::'
        . __FUNCTION__
        . '() '
        ;
        echo "<b>$ret</b>";
        echo PHP_EOL;
    }

    // A METHOD TO REMOVE A TIMER
    public function reset($name='TIMER')
    {
        // RESET ALL TIMERS
        if ($name == 'TIMER')
        {
            $this->__construct();
        }
        else
        {
            unset($this->a[$name]);
            unset($this->s[$name]);
            unset($this->z[$name]);
        }
    }

    // A METHOD TO CAPTURE THE START TIME
    public function start($name='TIMER')
    {
        $this->a[$name] = microtime(TRUE);
        $this->z[$name] = $this->a[$name];
        $this->s[$name] = 'RUNNING';
    }

    // A METHOD TO CAPTURE THE END TIME
    public function stop($name='TIMER')
    {
        $ret = NULL;

        // STOP ALL THE TIMERS
        if ($name == 'TIMER')
        {
            foreach ($this->a as $name => $start_time)
            {
                // IF THIS TIMER IS STILL RUNNING, STOP IT
                if ($this->s[$name])
                {
                    $this->s[$name] = FALSE;
                    $this->z[$name] = microtime(TRUE);
                }
            }
        }

        // STOP ONLY ONE OF THE TIMERS
        else
        {
            if ($this->s[$name])
            {
                $this->s[$name] = FALSE;
                $this->z[$name] = microtime(TRUE);
            }
            else
            {
                $ret .= "ERROR: CALL TO STOP() METHOD: '$name' IS NOT RUNNING";
            }
        }

        // RETURN AN ERROR MESSAGE, IF ANY
        return $ret;
    }

    // A METHOD TO READ OUT THE TIMER(S)
    public function readout($name='TIMER', $dec=3, $m=1000, $t = 'ms', $eol=PHP_EOL)
    {
        $str = NULL;

        // GET READOUTS FOR ALL THE TIMERS
        if ($name == 'TIMER')
        {
            foreach ($this->a as $name => $start_time)
            {
                $str .= $name;

                // IF THIS TIMER IS STILL RUNNING UPDATE THE END TIME
                if ($this->s[$name])
                {
                    $this->z[$name] = microtime(TRUE);
                    $str .= " RUNNING ";
                }
                else
                {
                    $str .= " STOPPED ";
                }

                // RETURN A DISPLAY STRING
                $lapse_time = $this->z[$name] - $start_time;
                $lapse_msec = $lapse_time * $m;
                $lapse_echo = number_format($lapse_msec, $dec);
                $str .= " $lapse_echo $t";
                $str .= $eol;
            }
            return $str;
        }

        // GET A READOUT FOR ONLY ONE TIMER
        else
        {
            $str .= $name;

            // IF THIS TIME IS STILL RUNNING, UPDATE THE END TIME
            if ($this->s[$name])
            {
                $this->z[$name] = microtime(TRUE);
                $str .= " RUNNING ";
            }
            else
            {
                $str .= " STOPPED ";
            }

            // RETURN A DISPLAY STRING
            $lapse_time = $this->z[$name] - $this->a[$name];
            $lapse_msec = $lapse_time * $m;
            $lapse_echo = number_format($lapse_msec, $dec);
            $str .= " $lapse_echo $t";
            $str .= $eol;
            return $str;
        }
    }
}



// DEMONSTRATE THE USE -- INSTANTIATE THE STOPWATCH OBJECT
$sw  = new Stopwatch;

// SET A STOPWATCH NAME THAT REFLECTS THE PARTS OF THE SCRIPT WE WANT TO TIME
$g_timer = 'GOOGLE TIMER';

// START A TIMER TO GET ELAPSED TIME FOR A CALL TO GOOGLE
$sw->start($g_timer);

// PERFORM SOME ACTIVITY THAT YOU WANT TO TIME (READS GOOGLE WEB PAGE)
$page = 'https://www.google.com';
$html = file_get_contents($page);

// GET A READOUT OF THE TIMER WHILE IT IS STILL RUNNING
echo nl2br($sw->readout($g_timer));
echo "<br/>" . PHP_EOL;

// PERFORM SOME OTHER ACTIVITY (READS GOOGLE WEB PAGE AGAIN)
$page = 'https://www.google.com';
$html = file_get_contents($page);

// STOP THE TIMER AND GET A READOUT WITH SHORT DECIMALS
$x = $sw->stop($g_timer);
echo nl2br($sw->readout($g_timer, 1));
echo "<br/>" . PHP_EOL;




// START A SECOND TIMER
$y_timer = 'YAHOO TIMER';
$sw->start($y_timer);

// PERFORM SOME OTHER ACTIVITY THAT YOU WANT TO TIME
$page = 'http://yahoo.com/';
$html = file_get_contents($page);

// REPORT THE STOPWATCHES CONTENT (ONE IS STOPPED AND ONE IS STILL RUNNING)
echo nl2br($sw->readout());
echo "<br/>" . PHP_EOL;

// SHOW THE OBJECT
echo "<pre>";
var_dump($sw);
echo "</pre>";

// STOP ALL OF THE STOPWATCHES
$sw->stop();

// REPORT THE STOPWATCHES CONTENT AGAIN
echo nl2br($sw->readout());
echo "<br/>" . PHP_EOL;

// SHOW THE OBJECT
echo "<pre>";
var_dump($sw);
echo "</pre>";



// TRY TO STOP A TIMER THAT IS NOT RUNNING
$x = $sw->stop($g_timer);
var_dump($x);
echo "<br/>" . PHP_EOL;
echo "<br/>" . PHP_EOL;



// START THIS TIMER OVER AGAIN
$sw->start($y_timer);

// PERFORM SOME OTHER ACTIVITY THAT YOU WANT TO TIME
$page = 'http://weather.yahoo.com/';
$html = file_get_contents($page);

// REPORT THE STOPWATCHES CONTENT
echo nl2br($sw->readout());
echo "<br/>" . PHP_EOL;

// SHOW THE OBJECT
echo "<pre>";
var_dump($sw);
echo "</pre>";



// REMOVE ONE OF THE STOPWATCHES
$sw->reset($g_timer);

// REPORT THE STOPWATCHES CONTENT
echo nl2br($sw->readout());
echo "<br/>" . PHP_EOL;

// SHOW THE OBJECT
echo "<pre>";
var_dump($sw);
echo "</pre>";



// REMOVE ALL OF THE STOPWATCHES
$sw->reset();
echo "ALL STOPWATCHES HAVE BEEN REMOVED";

// REPORT THE STOPWATCHES CONTENT (SHOWS NOTHING)
echo nl2br($sw->readout());

// SHOW THE OBJECT
echo "<pre>";
var_dump($sw);
echo "</pre>";

// SHOW THE DESTRUCTOR IN ACTION
$sw->start('Foo');
echo "<pre>";
unset($sw);
echo "</pre>";

Open in new window

Author

Commented:
thanks

values in JUST ONE object instance, not the Class.

foreach ($this as $key => $value) { }

$obj->id provides information about destructed object

I think Ray's example was for me. Now I understand the code sample better.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial