What determines when a class object is destroyed in PHP? - php

Let's say that we have class CFoo. In the following example when is CFoo::__destruct() called?
function MyPHPFunc()
{
$foo = new CFoo();
. . .
// When/where/how does $foo get destroyed/deleted?
}
In this example would the destructor be called when the script exits the scope of MyPHPFunc because $foo would no longer be accessible?

In PHP all values are saved in so called zvals. Those zvals contain the actual data, type information and - this is important for your question - a reference count. Have a look at the following snippet:
$a = new B; // $a points to zval(new B) with refcount=1
$b = $a; // $a, $b point to zval(new B) with refcount=2 (+1)
$c = $b; // $a, $b, $c point to zval(new B) with refcount=3 (+1)
unset($a); // $b, $c point to zval(new B) with refcount=2 (-1)
As soon as the refcount reaches 0 the zval is freed and the object destructor is called.
Here are some examples of the refcount reaching 0:
unseting a variable:
$a = new B; // refcount=1
unset($a); // refcount=0 => __destruct!
But:
$a = new B; // refcount=1
$b = $a; // refcount=2
unset($a); // refcount=1 => no destruct as refcount > 0, even though unset() was called!
leaving function (or method) scope
function a() {
$a = new B; // refcount=1
} // refcount=0 => __destruct! (as $a does not exist anymore)
script execution end
$a = new B; // refcount=1
die(); // refcount=0 => __destruct! (on script execution end all vars are freed)
// doesn't need to be die(), can be just normal execution end
These obviously are not all conditions leading to a reduction of refcount, but the ones you will most commonly meet.
Also I should mention that since PHP 5.3 circular references will be detected, too. So if object $a references object $b and $b references $a and there aren't any further references to $a or $b the refcounts of both will be 1, but they still will be freed (and __destructed). In this case though the order of destruction is undefined behavior.

PHP 5 introduces a destructor concept similar to that of other
object-oriented languages, such as C++. 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.
- PHP Manual
If you want to see the process in action, you can run this code here.
<?php
class A
{
public function __construct() { var_dump('Creating: '. get_class($this)); }
public function __destruct() { var_dump('Removing: '. get_class($this)); }
}
class B extends A {}
$A = new A();
/*
* When this block is called later on
*/
function create_b()
{
$B = new B();
} // At this point the function scope ends, and since $B is not referenced anymore it's removed.
var_dump('B is next');
create_b(); // Run above block, create, then destroy be
var_dump('B is now gone');
// At this point the PHP file parser ends, $A is destroyed since it's not used anymore

The information is in the manual, albeit somewhat cryptic:
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. 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.
Meaning: The destructor will be called when the object gets destroyed (= e.g. unset()), or when the script shuts down.
Additional useful info:
Like constructors, parent destructors will not be called implicitly by the engine. In order to run a parent destructor, one would have to explicitly call parent::__destruct() in the destructor body.
The destructor will be called even if script execution is stopped using exit(). Calling exit() in a destructor will prevent the remaining shutdown routines from executing.

the best way to know is to test.
however the simple answer is that __destruct is called during garbage cleanup. coarse that does not help anyone as garbage cleanup is an ongoing process that cleans up local variables when there is no scope that can call them.
however here is some sample code, and the result which fully explains what happens when exiting scope internally to the script.
<?php
class testingdestructor {
public function __construct($num) {
$this->num = $num;
}
public function __destruct() {
echo "I am number {$this->num}\n";
}
}
class testing2{
public function __construct($num) {
$this->classtest = new testingdestructor($num);
}
public function __destruct() {
echo "I am not a number\n";
}
}
$iam1 = new testingdestructor(1);
$iam4 = new testing2(4);
function testfunction() {
$iam2 = new testingdestructor(2);
}
testfunction();
$iam3 = new testingdestructor(3);
unset($iam1);
the output of this strange set of classes function and vars is this
I am number 2
I am number 1
I am number 3
I am not a number
I am number 4
this shows us that the end of the function calls the __destruct, as does unset, and that at least in practice that end of script cleanup is done in reverse order created.

if create instance of a class and use the object.after finishing all your tasks if u call the destructor and again use the same object in the next line to perform some other task u will be no longer able to use. That means ur destructor is called successfully

Related

How is an object returned from a function?

I don't understand how it's possible to return an object from a function. Since objects are passed and returned by reference, If I created an object in a function, I'd expect such object to be destroyed after the function finishes executing. So such returned object reference should be referring to non-existing(destroyed) object. But my object created within a function is successfully returned. How come??
class O{
public $ppty = "ppty value";
}
function f1(){
$o1 = new O();
return $o1;
}
var_dump(f1());
**Result:**
object(O)[15]
public 'ppty' => string 'ppty value' (length=10)
A variable "holding" an object is actually holding a reference to the object. The object exists somewhere in memory, the variable referring to the object just holds the memory address (oversimplified). That's the reference. When returning that reference or passing it somewhere or assigning it to another variable, a copy of that reference is made (meaning the memory address value is copied; e.g. you return the value 0xDEADBEAF from your function; again, oversimplified). Those references are counted as a property of the object; only when the reference count reaches 0 (no variable is holding a reference to the object anymore), is the object garbage collected.
Consider the following example:
$var = 'test';
$ref = &$var;
unset($ref);
echo $var; // Echoes "test".
The unset is only removing the reference of $var to $ref, not destroying the original variable that $ref refers to. This is similar to your example of objects being references, and the garbage collection only removes the variable's reference to the object, but the object still exists in memory.
See http://php.net/manual/en/language.references.unset.php for more details.
When a function or scope of application is finished the local variables that are no longer accessible will be deleted. However, when you create object from a class the scenario is different. They won't be deleted automatically, there is a garbage collector in php that is constantly searching for objects that are no longer accessible and if it finds any it will delete them.
So when you return object reference from function it won't be deleted. If you won't store the reference in any variable GC will delete it later.
For more information about Garbage collector in php please read this link:
http://php.net/manual/en/features.gc.refcounting-basics.php
In PHP all values are stored in zvals. Those zvals contain the actual data and type information. checkout out the following example.
<?php
class O{
public $ppty = "ppty value";
}
$a = new 0; // $a is pointing to zval(class 0) with refcount 1
$b = $a; // $a and $b are pointing to zval(class 0) with refcount 2
$c = $b; // $a, $b and $c are pointing to zval(class 0) with refcount 3
unset($a) // new $b and $c are pointing to zval(class 0) with refcount 2
// until the refcount is greater then the 0 the destructor will not called
?>
now take a look at the following example
<?php
$a = new 0; // $a is pointing to zval(class 0) with refcount 1
unset($a) // here refcount is 0 and destruct will be called
?>
Now come to your example
<?php
function f1(){
$o1 = new O(); // refcount = 1
return $o1;
}
// now you are returning the object in function f1 and so,
// $o1 is gone after the function scope but the func f1 is now pointing the its reference.
var_dump(f1())
**Result:**
object(O)[15]
public 'ppty' => string 'ppty value' (length=10)
// once the process is finished then it will call the destruct.

Re-declaration of the same static variable inside a function

I have such a function, and I declare the same static variable twice with different values. Then, I called the function, but the result surprised me.
function question(){
static $a=1;
$a++;
echo $a; // output:?
static $a=10;
$a++;
echo $a; // output:?
}
I thought the outputs would be: 2 11, but the outputs was: 11 12. Why?
If you declare and initialize the same static variable more than once inside a function, then the variable will take the value of the last declaration (static declarations are resolved in compile-time.)
In this case, the static variable of $a will take the value of 10 in the compile time, ignoring the value of 1 in the previous same declaration.
Static works the same way as it does in a class.
The variable is shared across all instances of a function.
so if you initialize same static variable many time then it will always take latest value.
A static variable exists only in the declared local function scope, but it does not lose its value when program execution leaves this scope.
The use of Static keyword is itself such that it will not lose track of the current count.
So In your case, function execution stops at $a = 10; $a++;
Hence you have 11 and 12 as output.
If you want output to be 2 and 11; keep only one declaration static like below.
function question(){
$a=1;
$a++;
echo $a; // output:?
static $a=10;
$a++;
echo $a; // output:?
}

Passing a function by reference

Is it possible to pass a function by reference? So everytime the reference variable is called the function will be called aswell. Take a look at my code.
<?php
class Documents {
private static $docs = array(
'She went to the toilet and on her way back, opened the wrong door',
'She had found something that would mean she\'d never be poor again - but there was a catch',
'It was just for one night',
'He watched, helpless, as the door closed behind her'
);
public static function get() {
return self::$docs[array_rand(self::$docs)];
}
}
class Printer {
public static $content;
}
Printer::$content = &Documents::get();
echo Printer::$content;
echo "\n" . Printer::$content;
echo "\n" . Printer::$content;
Right now it'll print 3 similar lines but i would like it to call Documents::get() everytime Printer::$content is printed because Printer::$content = **&**Documents::get(); it is by reference.
No, you cannot have a variable which you treat as a variable which nonetheless runs code behind the scenes. If you write $foo, that's using the value of a variable. Only of you write $foo() are you explicitly executing a function.
Having said that, there are some situations in which object methods will be called implicitly. For instance, if $foo is an object and you use it in a string context:
echo $foo;
This will (try to) implicitly call $foo->__toString().
Please do not get the idea to somehow abuse this implied method call to do anything fancy. If you want to call functions, call functions. You can even return functions from other functions, so there's no lack of possibility to pass around functions. You will have to call them explicitly with () however.
There are variable functions:
php > function foo($bar) { echo $bar; }
php > $baz = 'foo';
php > $baz('qux');
qux
But you cannot have PHP automatically execute that "referenced" function when the variable is simply accessed, e.g:
php > $baz;
php >
As you can see, the foo function was not called, and no output was performed. Without the () to signify a function call, that variable is like any other - it's just a string whose contents happen to be the same as a particular functions. It's the () that makes the string "executable".
Note that variable functions, while useful in some limited circumstances, should be avoided as they can lead to spaghetti code and difficult-to-debug bugs.
You can use the magic method __get().
class Printer {
public function __get($name)
{
switch($name) {
case "content":
return Documents::get();
break;
default:
return $this->$name;
break;
}
}
}
But this cannot be done in static context. So you would have to have an instance of Printer. (Perhaps use a singleton?)

Return a method with variable list of arguments as reference in PHP

I'm trying to return a value from a method as a reference in PHP5.3. I may be going at this the completely wrong way, but I am bringing an older project up to speed with some of the newer 5.3+ features.
Below is an example I whipped up to explain what is happening:
class Foo
{
static $foobar = 5;
function &bar()
{
return self::$foobar;
}
}
// Doesn't work
//$test1 = &call_user_func_array(array("Foo","bar"),array());
// Doesn't work
//$test1 = &call_user_func_array("Foo::bar",array());
// Doesn't work
//$f = new Foo; $test1 = &call_user_func_array(array($f,"bar"),array());
// WORKS
//$test1 = &Foo::bar();
//Doesn't work
//$function = "Foo::bar";
//$test1 = &$function();
// WORKS
$f = new Foo; $test1 = &$f->bar();
$test2 = Foo::bar();
var_dump($test1);
var_dump($test2);
$test1 = 10;
echo "----------<br />";
var_dump($test1);
var_dump($test2);
var_dump(Foo::bar()); //returns 10 when working, 5 when not working
The very last Foo::bar() should return a 10, since $test1 should be a reference to Foo::$foobar when everything works.
I realize that this example also uses some funky legacy PHP calling Foo::bar and the method bar() not being specified as static, but still being able to be invoked via ::
Any help would be greatly appreciated as the only fix I have so far is to just setup a switch on the argument list, and call the method directly based upon how many arguments exist.
This is just assigning $test1 to the value of $foobar (which is 5)
$test1 = &$f->bar();
This is just overwriting the value contained in $test1 with 10
$test1 = 10;
If you want to update the value within Foo, use
$f->foobar = 10;
Doesn't it already work in PHP 5.2.5: http://codepad.org/uMEIK210 (note the 10 as final result)?
I suppose, you would like to see the 10 three times.
For that (that $test2 is also a reference to the class field) you need to specify the & on both sides:
function &bar() and $test2 =& Foo::bar();
See the docs:
Note: Unlike parameter passing, here you have to use & in both places - to indicate that you want to return by reference, not a copy, and to indicate that reference binding, rather than usual assignment, should be done for $myValue.
So you just need to edit one line to get the (probably) desired 3 x 10:
$test2 =& Foo::bar();
Final hint
Do not use PHP references
First of all, try declaring the function static. Also the call should be a normal call. prefixed by ampersand as already answered.
class Foo
{
static $foobar = 5;
public static function &bar()
{
return self::$foobar;
}
}
The call:
$test1 =& Foo::bar();
Also, I can't see a valid reason for referencing a static variable. A static variable is a variable that doesn't change value between calls. It basically is a "global" var enclosed in a namespace. You only need read access from outside the class, the write should be done internally, as per the encapsulation principle. No need for the reference, really..

Is there differences between call_user_func() and $var()?

Is there any differences between call_user_func() and its syntactic sugar version...
// Global function
$a = 'max';
echo call_user_func($a, 1, 2); // 2
echo $a(1, 2); // 2
// Class method
class A {
public function b() {
return __CLASS__;
}
static function c() {
return 'I am static!';
}
}
$a = new A;
$b = 'b';
echo call_user_func(array($a, $b)); // A
echo $a->$b(); // A
// Static class method
$c = 'c';
echo call_user_func(array('A', $c)); // I am static!
echo a::$c(); // I am static!
codepad.
Both output the same, but I was recently hinted (10k+ rep only) that they are not equivalent.
So, what, if any, are the differences?
First difference I can think of is that call_user_func() runs method as a callback.
This means you can use a closure, eg
echo call_user_func(function($a, $b) {
return max($a, $b);
}, 1, 2);
This would be more of an implementation difference versus a usage or performance (execution) one though.
I honestly can't find much of a difference between the two. They basically do the same thing, but the only differences I can find is that call_user_func takes over 2× longer to complete than variable functions (calling an empty function).
Another thing is that the error handlers are different, if you use a non-existent callback function, the variable function would output a fatal error and halt the script while call_user_func would output a warning but continue the script.
Also when passing parameters through the function, using variable functions provides a little more detail in the error in relation to line numbers:
function asdf($a, $b) {
return(1);
}
call_user_func('asdf', 1):
Warning: Missing argument 2 for asdf()
in G:\test.php on line 3
-
$a='asdf'; $a($a, 1):
Warning: Missing argument 2 for
asdf(), called in G:\test.php on line
10 and defined in G:\test.php on line 3
These errors are collected from Command-Line Interface (CLI) tests, the display of errors obviously depends on your configuration.

Categories