Difference between clone object and normal object - php

In PHP How it differs when I create cloned object in a variable and new object created using a variable with the same class
For example
$a = new classA();
$b = clone $a;
$c = new classA();
What is the difference between $b and $c ?

You should look at the following example
<?php
class classA {
public $x=0;
}
$a = new classA();
$a->x = 20;
echo $a->x."<br />";
$b = clone $a;
$a->x = 30;
echo $a->x."<br />";
echo $b->x."<br />"; // 20 because x was 20 before cloning $a to $b
$a->x = 50;
echo $a->x."<br />"; // changed to 50
echo $b->x."<br />"; // stil 20, $a
$c = new classA();
echo $c->x;
Using cloning make, you have property x in object $b the same as in object $a because cloning simple copies object. And when creating new object, you will have new object and property value will be 0.
Cloning is simple copying object because by default for objects:
$a = $b;
PHP won't do copying (as for simple types) but will point to exact place in memory.
So for simple types you use:
$a = 5;
$b = $a;
if you want to make a copy, but for objects you need to use clone:
$a = new classA();
$a->x = 20;
$b = clone $a;
to have the same effect.
You should look in manual at Object and references and Cloning to understand those things.

Related

Are PHP zvals mutable?

I've been reading about memory management in PHP and learned that variables in PHP copy the reference to zvals as long as you don't do a write operation (copy on write paradigm).
https://www.phpinternalsbook.com/php5/zvals/memory_management.html#reference-counting-and-copy-on-write
However, it does not describe what happens when you reassign a value to an already copied zval.
Here's what the book says:
$a = 1; // $a = zval_1(value=1, refcount=1)
$b = $a; // $a = $b = zval_1(value=1, refcount=2)
$c = $b; // $a = $b = $c = zval_1(value=1, refcount=3)
$a++; // $b = $c = zval_1(value=1, refcount=2)
// $a = zval_2(value=2, refcount=1)
Now, if you do another $a++, will it change the value in zval,
$a++; // $a = zval_2(value=3, refcount=1)
or will it create a new zval once again?
$a++; // $a = zval_3(value=3, refcount=1)
Following the logic of the PHP Language Reference, I guess it should be more likely option #1 as long as refcount = 1 (you would not manipulate another variable).

Do static and global modifiers for variables implement a non-modifiable reference?

Source
The PHP doc says
PHP implements the static and global modifier for variables in terms
of references.
<?php
function test_global_ref() {
global $obj;
$new = new stdClass;
$obj = &$new;
}
function test_global_noref() {
global $obj;
$new = new stdClass;
$obj = $new;
}
test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);
?>
Since the program yields NULL as the first output, is this to say that the implemented reference is non-modifiable(hence the reference to &$new is nullified somehow)? The doc says the implementation results in an unexpected behaviour. Is there a logical explanation to this?
This is not about global or static, this is about the concept of reference.
Think about the following codes:
$a = "a"; $b = "b";
$r = &$a;
var_dump($a, $b, $r); # a, b, a
$r = &$b;
var_dump($a, $b, $r); # a, b, b
It's easy to understand, but the important thing is the statement $r = &$b; means copy the reference of $b to $r, so both $b and $r refer to the same value.
Next if you do:
$r = $a;
var_dump($a, $b, $r); # a, a, a
The statement $r = $a; means copy the value of $a to $r, so the value of $r changes from "b" to "a". Since both $b and $r refer to the same value, the value of $b also becomes "a".
Finally if you do:
$r = "r";
var_dump($a, $b, $r); # a, r, r
Still only the value of $b to $r is changed, $a keeps its original value.
Back to your question, your first function is almost equivalent to:
function test_global_ref(&$r) {
$b = "b";
$r = &$b;
}
$a = "a";
test_global_ref($a);
I changed the variable names and values to those corresponding to the above example, hope this is easier to understand. So the global variable $a is passed to the function as a reference $r, when you copy the reference of $b to $r, the global variable $a won't be influenced.

PHP object property in variable

I want to create dynamic object property as variable in php.
For example
$b = '';
if($b != '') $b = "->b";
$a = new stdClass();
$a. $b->c;
My Target Output is
If(b == '') $a->c;
else $a->b->c;
For $b->c to work, you have to make $b an object of stdClass class. But since you made $b as a string using $b = "->b";, the former statement $b->c would throw error.
So the workaround is - make b as a property of object $a and assign an object of class stdClass to this member property. The following block of code would make this concept more clearer.
$b = '';
$a = new stdClass();
if($b != ''){
$a->b = new stdClass();
$a->b->c = 'something';
}else{
$a->c = 'something else';
}
Later, you can have the desired target output like this:
if($b == '') echo $a->c;
else echo $a->b->c;

Reference Counting in php - how does it work?

I am trying to understand this article "PHP Manual -> Features -> Garbage Collection"
unfortunately few things are unclear for me.
1.
To avoid having to call the checking of garbage cycles with every
possible decrease of a refcount, the algorithm instead puts all
possible roots (zvals) in the "root buffer".
but what in case
<?php
$a = new \stdClass(); (1)
$a = new \stdClass();
Then I guess the first object become "lost" zval like
no_symbol : (refcount=1, is_ref=1) = stdObject
Will such "lost" zvals be added into root buffer or not? There is no handler for them.
2.
Variables created in function scope, what happened with them?
Ex:
<?php
function test($a = 'abc') {
$c = 123;
return 1;
}
test();
echo 'end';
What happened with $a and $c when gc starts?
These variables still have refcount set to 1.
Will they still be removed? if yes then why and how (what is happening under the cover?)
3.
How can it help for cyclic references?
Ex
<?php
$a = array('abc');
$a[] =& $a;
unset($a);
where
(refcount=1, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='abc',
1 => (refcount=1, is_ref=1)=...
)
1) The original object is replaced with the new one, and thus memory is freed instantly.
echo memory_get_usage().'<br/>';
$a = new stdClass();
echo memory_get_usage().'<br/>';
$a = new stdClass();
echo memory_get_usage().'<br/>';
2) They are gc'ed the second the function completes executing:
echo memory_get_usage().'<br/>';
function test($a = 'abc') {
$c = 123;
return 1;
}
echo memory_get_usage().'<br/>';
test();
echo memory_get_usage().'<br/>';
3) unsetting $a will leave the referenced variable in memory. You need to set the value to NULL first, and then unset.
echo memory_get_usage().'<br/>';
$a = array('abc');
echo memory_get_usage().'<br/>';
$a[] =& $a;
echo memory_get_usage().'<br/>';
$a = null;
unset($a);
echo memory_get_usage().'<br/>';

Object Copying and Evaluating $b = $a

My question is $b the same as $a in the output? Am I just passing a reference to $a when using ($b = $a) and not making a copy of the object?
$a = new DateTime('2014-01-15');
$i = new DateInterval('P1D');
print $a->format('Y-m-d') . PHP_EOL; // 2014-01-15
$b = $a;
print $a->add($i)->format('Y-m-d') . PHP_EOL; // 2014-01-16
print $b->format('Y-m-d') . PHP_EOL; // 2014-01-16
Note the use of clone:
$a = new DateTime('2014-01-15');
$i = new DateInterval('P1D');
print $a->format('Y-m-d') . PHP_EOL; // 2014-01-15
$b = clone $a; // Here we clone the object
print $a->add($i)->format('Y-m-d') . PHP_EOL; // 2014-01-16
print $b->format('Y-m-d') . PHP_EOL; // 2014-01-15
Further explanation from the docs: if your object holds a reference to another object which it uses and when you replicate the parent object you want to create a new instance of this other object so that the replica has its own separate copy. It sounds like just setting $a = $b will have the same initialization of the object, meaning if one changes the other does. The variable $b becomes a sort of symbolic link to the initialized object held in $a.

Categories