객체 복제 심층 분석
Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 91개 중 61번째.
이 과정의 앞부분에서 __clone 매직 메서드에 대해 배웠습니다. 이제 객체가 다른 객체를 속성으로 포함할 때 얕은 복제와 깊은 복제 사이의 중요한 차이점을 살펴보겠습니다.
기본적으로 PHP는 클로닝 시 얕은 복사(shallow copy)를 수행합니다. 스칼라 값은 복제되지만, 객체 속성은 동일한 객체에 대한 참조로 유지됩니다:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
출력:
Alice - London$clone->name을 변경해도 원본에는 영향을 주지 않았지만, 주소의 도시(city)를 변경하는 것은 영향을 주었음을 확인하세요! 두 객체 모두 동일한 Address 인스턴스를 공유합니다.
중첩된 객체도 복제되는 깊은 복사(deep copy)를 생성하려면, __clone을 구현하세요:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
출력:
Paris이제 각 Person은 자신만의 독립적인 Address를 가집니다. 객체에 여러 개의 중첩된 객체가 포함되어 있는 경우, 원본과 복사본 사이의 진정한 독립성을 달성하려면 __clone에서 각 객체를 복제해야 합니다.
챌린지
쉬움얕은 복사(shallow cloning)와 깊은 복사(deep cloning)의 차이점을 보여주는 문서 관리 시스템을 구축해 봅시다. 작성자 정보를 포함하는 문서를 만들고, 문서를 복제할 때 완전히 독립적인 사본이 생성되도록 해야 합니다.
코드는 다음 세 개의 파일로 구성됩니다:
Author.php— 문서의 작성자를 나타내는Author클래스를 생성합니다. 생성자 프로모션(constructor promotion)을 사용하여 public$name(string)과 public$email(string)을 정의하세요.Document.php— 작성자 정보를 포함하는Document클래스를 생성합니다. Author 파일을 포함(include)하세요. 이 클래스는 다음을 수행해야 합니다:- 생성자 프로모션을 사용하여 public
$title(string)과 public$author(Author)를 정의합니다. - 깊은 복사를 수행하기 위해
__clone()매직 메서드를 구현합니다. 문서를 복제할 때 작성자도 함께 복제되어야 하며, 복제된 문서의 작성자를 변경해도 원본에 영향을 주지 않아야 합니다. "[title] by [author name] ([author email])"형식을 반환하는getInfo()메서드를 작성합니다.
- 생성자 프로모션을 사용하여 public
main.php— Document 파일을 포함하세요. 세 개의 입력값(문서 제목, 작성자 이름, 작성자 이메일)을 받게 됩니다.제공된 입력값을 사용하여
Author를 포함한Document를 생성합니다. 문서를 복제한 후, 복제된 문서의 작성자 이름 뒤에" (Copy)"를 추가하고, 복제된 문서의 제목 앞에"Copy of "를 추가하여 수정합니다.다음 두 줄을 출력하세요:
- 원본 문서의 정보
- 복제된 문서의 정보
깊은 복사가 올바르게 구현되었다면, 복제된 문서의 작성자를 수정하더라도 원본 문서의 작성자는 변경되지 않은 상태로 유지되어야 합니다.
이 챌린지는 깊은 복사가 왜 중요한지 보여줍니다. __clone()을 적절히 구현하지 않으면 두 문서가 동일한 Author 객체를 공유하게 되어, 한쪽을 변경하면 다른 쪽에도 영향을 미치게 됩니다.
치트 시트
기본적으로 PHP는 객체를 복제할 때 얕은 복사(shallow copy)를 수행합니다. 스칼라 값은 복제되지만, 객체 속성은 동일한 객체에 대한 참조로 남습니다.
얕은 복제의 예:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
// 출력: Alice - London
$clone->name을 변경해도 원본에는 영향을 미치지 않지만, 중첩된 address 객체를 변경하면 두 객체가 동일한 Address 인스턴스를 공유하기 때문에 원본도 변경됩니다.
중첩된 객체도 함께 복제되는 깊은 복사(deep copy)를 생성하려면 __clone 매직 메서드를 구현하세요:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
// 출력: Paris
객체에 여러 개의 중첩된 객체가 포함된 경우, 원본과 복사본 사이의 완전한 독립성을 달성하려면 __clone에서 각 객체를 복제해야 합니다.
직접 해보기
<?php
require_once 'Document.php';
// 입력 읽기
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: 제공된 이름과 이메일로 Author 생성
// TODO: 제공된 제목과 Author로 Document 생성
// TODO: 문서 복제
// TODO: 복제본의 작성자 이름 뒤에 " (Copy)"를 추가하여 수정
// TODO: 복제본의 제목 앞에 "Copy of "를 추가하여 수정
// TODO: 원본 문서 정보 출력
// TODO: 복제된 문서 정보 출력
?>이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8매직 메서드
매직 메서드 소개__toString 및 __debugInfo__get, __set, __isset, __unset__call 및 __callStatic__clone 및 객체 복제__serialize 및 __unserialize요약 - 커스텀 컬렉션