PHP对象分配与克隆

时间:2013-06-03 09:46:37

标签: php object

我知道这是php文档中的内容,但我对这个问题感到困惑。

来自php文档:     

$instance = new SimpleClass();
$assigned   =  $instance;
$reference  =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

以上示例将输出:

NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
 string(30) "$assigned will have this value"
}

好的,所以我看到$assigned 幸存原始对象($instance)被分配到null,所以显然$assigned不是引用但是$ instance的副本。

那么

之间有什么区别
 $assigned = $instance 

 $assigned = clone $instance

8 个答案:

答案 0 :(得分:18)

对象是内存中的抽象数据。变量始终将引用保存到内存中的此数据。想象一下,$foo = new Bar在内存中的某处创建了Bar的对象实例,为其分配了一些ID #42,而$foo现在将此#42作为此对象的引用。通过引用将此引用分配给其他变量,或者通常与任何其他值相同。许多变量可以保存此引用的副本,但都指向同一个对象。

clone显式创建对象本身的副本,而不仅仅是指向对象的引用。

$foo = new Bar;   // $foo holds a reference to an instance of Bar
$bar = $foo;      // $bar holds a copy of the reference to the instance of Bar
$baz =& $foo;     // $baz references the same reference to the instance of Bar as $foo

不要混淆"参考"如=&中"引用"如对象标识符

$blarg = clone $foo;  // the instance of Bar that $foo referenced was copied
                      // into a new instance of Bar and $blarg now holds a reference
                      // to that new instance

答案 1 :(得分:8)

之间的区别
 $assigned = $instance 

 $assigned = clone $instance

是在第一种情况下,您分配已存在对象的引用,在第二种情况下,您创建一个新对象并将其分配给变量。

此外,当您使用 clone 关键字时,您可以使用magic方法__clone(),它可以更好地控制对象克隆。来自php手册:

  

克隆完成后,如果定义了__clone()方法,则将调用新创建的对象的__clone()方法,以允许任何需要更改的必要属性。

来自manual

  

PHP引用是一个别名,它允许两个不同的变量写入相同的值。从PHP 5开始,对象变量不再包含对象本身作为值。它只包含一个对象标识符,允许对象访问者查找实际对象。当一个对象通过参数发送,返回或分配给另一个变量时,不同的变量不是别名:它们包含标识符的副本,它指向同一个对象。

让我举个实例

$dateA = new \Datetime('2017-04-04');

$dateB = $dateA; // $dateB references exactly the same object as $dateA

$dateB->modify('+1 day');

var_dump($dateA->format('Y-m-d')); //string(10) "2017-04-05" 
var_dump($dateB->format('Y-m-d')); //string(10) "2017-04-05"


// $dateA is still modified by the code above so it has 2017-04-05
$dateC = clone $dateA; // we clone $dateA so it's a new object

$dateC->modify('+1 day');

var_dump($dateA->format('Y-m-d')); // string(10) "2017-04-05" 
var_dump($dateC->format('Y-m-d')); // string(10) "2017-04-06"

//日期时间的侧边注释我建议使用DatetimeImmutable而不是Datetime

答案 2 :(得分:2)

 $assigned = $instance 

上面会将$ instance分配给$ assigned,最基本的赋值。

 $assigned = clone $instance 

这是对象克隆。将对象$ instance的副本分配给$ assigned。

没有克隆,$ assigned和$ instance具有相同的对象ID,这意味着它们指向同一个对象。

答案 3 :(得分:2)

PHP不像管理其他数据类型那样管理对象。字符串(或整数,布尔值,浮点数或数组)直接存储在变量中。当变量的值分配给另一个变量时,该值将被复制 1 到新变量中。

例如:

$x = array('a');
$y = $x;
// $x and $y are different and unrelated variables; they do not share anything
$y[] = 'b';
print_r($y);
// Array
// (
//     [0] => a
//     [1] => b
// )
print_r($x);
// Array
// (
//     [0] => a
// )

PHP如何处理对象分配?

另一方面,对象由PHP使用唯一标识符处理。将对象分配给变量时,标识符存储在变量中,而不是实际对象中。

当变量的值分配给另一个变量时,将复制标识符,而不是对象本身。这使得两个变量指向同一个对象。

使用您的示例,变量$instance$assigned的值相等,它们都包含同一对象的标识符。另一方面,$reference是一个引用,即变量$assigned的别名(不同的名称)。这就是语句$instance = null;清除变量$reference$assigned的内容的原因,但它不会影响变量$instance以及其标识符存储在其中的对象它

在将$reference设置为null之前,可以使用$instance$assignedreference中的任何一个来访问在SimpleClass上创建的$instance = new SimpleClass(); $assigned = $instance; $instance->var = '$assigned will have this value'; echo($instance->var); // It prints: // $assigned will have this value // $assigned is also modified because it is the same object echo($assigned->var); // It prints: // $assigned will have this value 对象你的例子的第一行。 F.e:

$assigned = clone $instance

在文档中阅读有关PHP objects and references的更多信息。

$assigned = clone $instance; 时会发生什么?

clone operator创建其操作数的副本。它创建一个新对象,并通过将原始对象的属性值分配给它们来初始化其所有属性。这意味着如果克隆对象包含对象作为属性,则通过简单赋值而不是通过克隆来复制这些属性。 2

$assigned

在此声明之后,$instance包含的值与$instance不同,因为它们现在存储不同对象的ID。作为不同的对象,$assigned的更改不再影响$instance = new SimpleClass(); $instance->var = '$instance has this value'; $assigned = clone $instance; echo($assigned->var); // It prints: // $instance has this value $assigned->var = '$assigned has a different value'; echo($assigned->var); // It prints: // $assigned has a different value // $instance is not modified echo($instance->var); // It prints: // $instance has this value

__clone()

1 这不完全正确。出于优化目的,在修改数组(写入时复制)之前不会复制数组。但是,这是一个实现细节,为了讨论的目的,可以考虑除了对象在分配给新变量时复制的所有值。

2 这也被称为"浅"克隆。为了得到一个深刻的" clone(一个不与原始文件共享任何内容的真实副本),具有对象作为属性的克隆对象的类必须实现__clone()魔术方法并克隆原始对象的属性。此外,这些属性的类必须实现dplyr等等。

答案 4 :(得分:1)

好吧,基本上这些变量只不过是指向对象所在的内存空间的指针。如果将指针值存储在另一个指针中,然后重置原始指针,那么它们曾经指向的内存区域都不会发生任何事情。

答案 5 :(得分:0)

保持简短&这里很简单:

此处$reference类似于对象$instance的别名。而最初$assignment$reference指向对象$instance的数据空间。

$instance指向的值发生变化时,它会随处更改。

但在$instance = null时,我们在这里$instance指向null,因为$reference是别名所以:

  

$ reference - > $ instance - >空....

$assignment仍保留指向由$instance创建的对象的数据空间的指针,但现在$instance不再需要相同的内容。

答案 6 :(得分:0)

这是克隆和分配之间的区别:

class MyClass {
  public $color;
  public $amount;
}

$obj = new MyClass();
$obj->color = 'red';
$obj->amount = 5;
$copy = clone $obj;
$assign = $obj;
$obj->amount = 7;
print_r($copy);//it will print : MyClass Object ( [color] => red [amount] => 5 ) 
print_r($assign);//it will print : MyClass Object ( [color] => red [amount] => 7 ) 

答案 7 :(得分:-2)

它只是创建一个全新的对象,它保留了被复制对象的属性。它执行深层复制:

$assigned = $instance; 

将对象从一个对象复制到另一个时,它会生成一个浅的副本:

$assigned = clone $instance;