什么是php中的对象克隆?

2022-08-30 12:02:53

有人可以解释我吗?

  • 什么是php中的对象克隆?

  • 我什么时候应该在php中使用克隆关键字?


答案 1

对象克隆是创建对象副本的操作。正如 Cody 所指出的,PHP 中的克隆是通过制作对象的浅层副本来完成的。这意味着克隆对象的内部对象不会被克隆,除非您通过定义 magic 方法显式指示对象也克隆这些内部对象。__clone()

如果不使用该方法,则新对象的内部对象将是对内存中与克隆的原始对象的内部对象相同的 objecs 的引用。__clone

请考虑以下示例:

// in this exampe the internal member $_internalObject of both objects
// reference the same instance of stdClass in memory.
class CloneableClass
{
    private $_internalObject;

    public function __construct()
    {
        // instantiate the internal member
        $this->_internalObject = new stdClass();
    }
}

$classA = new CloneableClass();
$classB = clone $classA;


// in this exampe the internal member $_internalObject of both objects
// DON'T reference the same instance of stdClass in memory, but are inividual instances
class CloneableClass
{
    private $_internalObject;

    public function __construct()
    {
        // instantiate the internal member
        $this->_internalObject = new stdClass();
    }

    // on clone, make a deep copy of this object by cloning internal member;
    public function __clone()
    {
        $this->_internalObject = clone $this->_internalObject;
    }
}

$classA = new CloneableClass();
$classB = clone $classA;

例如,克隆的用例是您不希望外部对象弄乱对象的内部状态的情况。

假设您有一个具有内部对象 Address 的类 User。

class Address
{
    private $_street;
    private $_streetIndex;
    private $_city;
    // etc...

    public function __construct( $street, $streetIndex, $city /* etc.. */ )
    {
        /* assign to internal values */
    }
}

class User
{
    // will hold instance of Address
    private $_address;

    public function __construct()
    {
        $this->_address = new Address( 'somestreet', '1', 'somecity' /* etc */ );
    }

    public function getAddress()
    {
        return clone $this->_address;
    }
}

为了参数起见,假设您不希望外部对象弄乱用户对象的内部地址,但您确实希望能够为它们提供 Address 对象的副本。上面的例子说明了这一点。该方法将地址对象的克隆返回到调用对象。这意味着,如果调用对象更改了 Address 对象,则用户的内部地址将不会更改。如果您没有提供克隆,则外部对象将能够更改用户的内部地址,因为默认情况下会提供引用,而不是克隆。getAddress

希望这一切都有意义。

PS.:
请注意,如果 Address 也有内部对象,则必须确保 Address 在克隆时(根据我这篇文章的第二个示例)通过定义地址来制作自己的深度副本。否则,您将因试图弄清楚为什么您的数据被搞砸而头疼。__clone()


答案 2

克隆用于创建对象的真实副本。将对象分配给另一个变量不会创建副本 - 相反,它会创建对与对象相同的内存位置的引用:

<?php

$o= new stdclass;
$o->a= 'b';
$o->b= 'c';

$o2= $o;
$o2->a= 'd';

var_dump($o);
var_dump($o2);

$o3= clone $o;
$o3->a= 'e';
var_dump($o);
var_dump($o3);

?>

此示例代码将输出以下内容:

object(stdClass)#1 (2) {
  ["a"]=>
  string(1) "d"
  ["b"]=>
  string(1) "c"
}
object(stdClass)#1 (2) {
  ["a"]=>
  string(1) "d"
  ["b"]=>
  string(1) "c"
}
object(stdClass)#1 (2) {
  ["a"]=>
  string(1) "d"
  ["b"]=>
  string(1) "c"
}
object(stdClass)#2 (2) {
  ["a"]=>
  string(1) "e"
  ["b"]=>
  string(1) "c"
}

推荐