Menu
Coddy logo textTech

객체 복제 심층 분석

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에서 각 객체를 복제해야 합니다.

challenge icon

챌린지

쉬움

얕은 복사(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() 메서드를 작성합니다.
  • 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: 복제된 문서 정보 출력

?>
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨