25

我知道这包含在 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 的副本。$instancenull$assigned

那么两者有什么区别

 $assigned = $instance 

 $assigned = clone $instance
4

8 回答 8

24

对象是内存中的抽象数据。变量始终在内存中保存对此数据的引用。想象一下,在内存$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

只是不要将 "reference"=&object identifier中的 "reference" 混淆。

$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
于 2013-06-03T09:52:35.967 回答
12

和...之间的不同

 $assigned = $instance 

 $assigned = clone $instance

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

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

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

手册

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

编辑:内部类型

// create 2 integer variables $a and $b

$a = 1;
$b = 1;

// create a new $c variable and assign the *value* of $a to that variable
$c = $a;

// create a new $d variable and assign a reference to $b variable
$d = &$b;

// increment $b, $c and $d variables
$b++; 
$c++;
$d++;

echo $a; // 1
echo $b; // 3
echo $c; // 2
echo $d; // 3

因为当我们增加它的值时,$d 引用了 $b,它也会改变 $b 的值。

内部对象(如字符串、int、float 等)之间的区别在于它们是按值传递的,而对象默认情况下是通过引用传递的

注意:您不能将克隆与内部对象一起使用。

于 2013-06-03T09:52:52.343 回答
4

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$assignedreferenceSimpleClass

$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

在文档中阅读有关PHP 对象和引用的更多信息。

什么时候发生$assigned = clone $instance

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

$assigned = clone $instance;

在此语句之后,$assigned包含不同的值,$instance因为它们现在存储不同对象的 ID。作为不同的对象, 的变化$instance不再影响$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

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

2这也称为“浅层”克隆。为了获得“深度”克隆(与原始对象不共享任何内容的真正副本),具有对象作为属性的克隆对象的类必须实现__clone()魔术方法并克隆原始对象的属性。此外,这些属性的类必须实现__clone()等等。

于 2017-07-17T20:19:58.353 回答
1

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

于 2013-06-03T09:49:36.103 回答
1
 $assigned = $instance 

上面将 $instance 分配给 $assigned,这是最基本的分配。

 $assigned = clone $instance 

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

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

于 2013-06-03T09:51:28.697 回答
1

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

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 ) 
于 2020-12-06T05:52:14.033 回答
0

在这里保持简短和简单:

$reference就像 object 的别名$instance。而最初$assignment$reference指向对象的数据空间$instance

并且当所指向的值发生变化时,$instance它将在任何地方发生变化。

但是当$instance = null, 在这里我们使$instanceto 指向null并且因为$reference是一个别名所以:

$reference -> $instance -> null....

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

于 2015-01-10T14:30:51.947 回答
-2

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

$assigned = $instance; 

当您将一个对象从一个对象复制到另一个对象时,它会进行浅拷贝:

$assigned = clone $instance;
于 2017-07-17T13:42:00.010 回答