PHP에서 객체의 복사본을 어떻게 만듭니 까?


168

PHP에서 객체는 참조로 전달되는 것으로 보입니다. 할당 연산자조차도 객체의 복사본을 생성하지 않는 것 같습니다.

다음은 간단하고 입증 된 증거입니다.

<?php

class A {
    public $b;
}


function set_b($obj) { $obj->b = "after"; }

$a = new A();
$a->b = "before";
$c = $a; //i would especially expect this to create a copy.

set_b($a);

print $a->b; //i would expect this to show 'before'
print $c->b; //i would ESPECIALLY expect this to show 'before'

?>

두 경우 모두 '후'를 받고 있습니다

따라서 참조가 아닌 값으로 $ aset_b () 에 전달하는 방법은 무엇입니까?


2
실제로이 동작을 원하는 경우는 거의 없습니다. 따라서 자신이 자주 사용하는 것을 찾으면 코드 작성 방식에 더 근본적인 문제가 있습니까?
troelskn 08.

1
아니요, 아직 사용할 필요가 없습니다.
Nick Stinemates

(object) ((array) $objectA)clone $objectA나 보다 나은 성능으로 원하는 결과를 얻을 수 있습니다 new stdClass.
Binyamin

답변:


284

PHP 5+에서 객체는 참조로 전달됩니다. PHP 4에서는 값으로 전달됩니다 (따라서 런타임이 참조로 전달되어 더 이상 사용되지 않습니다).

PHP5에서 'clone'연산자를 사용하여 객체를 복사 할 수 있습니다 :

$objectB = clone $objectA;

또한 질문에 언급 한 모든 것이 아니라 참조로 전달되는 객체 일뿐입니다 ...


이 내용을 읽는 사람에게만 추가하면 복제가 원본 객체를 계속 참조하게됩니다. 복제 된 객체를 사용하여 MySQL 쿼리를 실행하면 선형적인 방식으로 실행되지 않을 수 있으므로 이로 인해 예기치 않은 결과가 발생할 수 있습니다.
Ælex

20
일반적인 오해를 바로 잡기 위해 (PHP 문서조차 잘못되었다고 생각합니다!) PHP 5의 객체는 "참조로 전달되지 않습니다". Java에서와 같이 추가 간접 수준이 있습니다. 변수는 "객체 포인터"를 가리키고 객체를 가리 킵니다. 따라서 두 변수가 동일한 값을 참조 하지 않고도 동일한 객체 가리킬 수 있습니다 . 이것은이 예제에서 볼 수 있습니다 : $a = new stdClass; $b =& $a; $a = 42; var_export($b);여기 변수에$b 대한 참조가 있습니다 $a ; 당신이 교체하면 =&정상으로 =, 그것은이다 하지 참조, 여전히 원래 개체를 가리 킵니다.
IMSoP 2016 년

참조에 의한 런타임 패스는 스펙이 아닌 함수의 구현에 따라 함수 호출의 영향을 미치기 때문에 나쁜 생각입니다. 값을 전달하는 것이 기본값 인 것과는 아무런 관련이 없습니다.
Oswald

1
@Alex 댓글에 대해 자세히 설명해 주시겠습니까? (여기 또는 다른 곳에서) 요점은 약간 불분명합니다.
Chris Middleton

@ChrisMiddleton C 또는 C ++의 용어를 생각해보십시오. 범위가 없거나 해제 된 개체에 대한 참조를 복제 한 경우 복제 된 참조가 무효화됩니다. 따라서 복제를 통해 참조를 보유한 원본 객체에 발생한 상황에 따라 정의되지 않은 동작 이 발생할있습니다 .
Ælex

103

대답은 일반적으로 Java 서적에서 찾을 수 있습니다.

  1. 복제 : 복제 방법을 재정의하지 않으면 기본 동작은 단순 복사입니다. 객체에 기본 멤버 변수 만있는 경우에는 문제가 없습니다. 그러나 멤버 변수로 다른 객체가있는 유형이없는 언어에서는 두통입니다.

  2. 직렬화 / 직렬화

$new_object = unserialize(serialize($your_object))

이것은 객체의 복잡성에 따라 큰 비용으로 딥 카피를 달성합니다.


4
+1 훌륭하고 훌륭하며 PHP로 DEEP 사본을 만드는 아주 쉬운 방법입니다. 대신 PHP clone 키워드가 제공하는 표준 얕은 사본에 대해 물어보고 기본 멤버 변수 만 복사한다고 말했습니다 .PHP 배열 / 문자열이 기본 멤버 변수로 간주되므로 복사됩니다. 맞습니까?
Marco Demaio

3
이것을 선택하는 사람은 : "얕은"사본 ( $a = clone $b, 마술 __clone()방법을 사용하지 않음 )은 $b용어 로 객체의 각 속성을보고 동일한 클래스의 새 멤버에서 동일한 속성에 할당하는 것과 같습니다. =. 객체 인 속성은 cloned를 얻 거나 배열 내부의 객체를 얻지 못합니다 . 참조로 묶인 변수도 마찬가지입니다. 다른 모든 것은 단지 값일 뿐이며 다른 할당과 마찬가지로 복사됩니다.
IMSoP 2016 년

3
완전한! json_decode (json_encode ($ obj)); 하지 클론 / 개인 보호 특성 및 방법 ... 때 unserialize (직렬화되지 복제 방법 너무 ...
zloctb

대박! 마침내 PhpStorm의 오류를 제거했습니다. Call to method __clone from invalid context:)
numediaweb

처럼 그 일을 할 때 친구는 PHP 구문 분석 오류가 있습니다 : $new_date = (clone $date_start)->subDays(1);그것은 실패 ()내가 다른 오류를 제거하는 경우. 문제는 정확히 동일한 PHP 7.2.3을 사용하고 광산이 잘 작동한다는 것입니다. 어떤 아이디어? .. 어디에서나 검색
emotality

21

이전 의견에 따르면 멤버 변수로 다른 객체가 있으면 다음을 수행하십시오.

class MyClass {
  private $someObject;

  public function __construct() {
    $this->someObject = new SomeClass();
  }

  public function __clone() {
    $this->someObject = clone $this->someObject;
  }

}

이제 복제를 할 수 있습니다 :

$bar = new MyClass();
$foo = clone $bar;


4

명확히하기 위해 PHP는 copy on write를 사용하므로 기본적으로 모든 것이 수정 될 때까지는 참조이지만 객체의 경우 허용 된 답변과 같이 clone 및 __clone () 마술 메서드를 사용해야합니다.


1

이 코드는 메소드를 복제하는 데 도움이됩니다.

class Foo{

    private $run=10;
    public $foo=array(2,array(2,8));
    public function hoo(){return 5;}


    public function __clone(){

        $this->boo=function(){$this->hoo();};

    }
}
$obj=new Foo;

$news=  clone $obj;
var_dump($news->hoo());

이 코드는 약간 쓸모가 없습니다. __clone 메소드를 제거하더라도 작동합니다. :)
amik

1

나는 약간의 테스트를하고 있었고 이것을 얻었다.

class A {
  public $property;
}

function set_property($obj) {
  $obj->property = "after";
  var_dump($obj);
}

$a = new A();
$a->property = "before";

// Creates a new Object from $a. Like "new A();"
$b = new $a;
// Makes a Copy of var $a, not referenced.
$c = clone $a;

set_property($a);
// object(A)#1 (1) { ["property"]=> string(5) "after" }

var_dump($a); // Because function set_property get by reference
// object(A)#1 (1) { ["property"]=> string(5) "after" }
var_dump($b);
// object(A)#2 (1) { ["property"]=> NULL }
var_dump($c);
// object(A)#3 (1) { ["property"]=> string(6) "before" }

// Now creates a new obj A and passes to the function by clone (will copied)
$d = new A();
$d->property = "before";

set_property(clone $d); // A new variable was created from $d, and not made a reference
// object(A)#5 (1) { ["property"]=> string(5) "after" }

var_dump($d);
// object(A)#4 (1) { ["property"]=> string(6) "before" }

?>

1

이 예에서는 iPhone 클래스를 만들고 복제 하여 정확한 클래스를 만듭니다.

class iPhone {

public $name;
public $email;

    public function __construct($n, $e) {

       $this->name = $n;
       $this->email = $e;

    }
}


$main = new iPhone('Dark', 'm@m.com');
$copy = clone $main;


// if you want to print both objects, just write this    

echo "<pre>"; print_r($main);  echo "</pre>";
echo "<pre>"; print_r($copy);  echo "</pre>";

-1

다른 인스턴스에서 객체의 속성을 완전히 복사하려면이 기술을 사용하는 것이 좋습니다.

JSON으로 직렬화 한 다음 Object로 다시 직렬화 해제하십시오.


7
흠 나는 지옥처럼 피할 것이다.
Jimmy Kane
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.