시작 오늘 분석할 코드
User 부모 클래스를 Guest 자식 클래스가 extends로 상속받는다. 두 클래스 모두 print_hello라는 메서드를 갖고 있다. 객체를 생성하고 print_hello()를 호출하면 부모 버전이 아니라 자식 버전이 실행된다 — 이것이 오버라이딩이다.
class User { private $name = null; public function print_hello() { print $this->name . " 님, 안녕하세요!<BR>"; } } class Guest extends User { private $name = "게스트"; public function print_hello() { // 오버라이딩 — 같은 이름, 다른 내용 print $this->name . "님, 반갑습니다!<BR>"; } } $newuser = new Guest(); $newuser->print_hello(); // → "게스트님, 반갑습니다!" (자식 버전 실행)
실제 출력 미리보기
게스트님, 반갑습니다!
→ new Guest()로 생성했으므로 런타임에 Guest::print_hello()가 선택됨. User::print_hello()는 실행되지 않는다.
용어 핵심 용어 정리
extendsPHP 상속 키워드. 자식 클래스가 부모의 멤버변수와 메서드를 물려받는다
부모 클래스상속을 제공하는 클래스. Super class / Base class 라고도 불린다
자식 클래스부모를 상속받는 클래스. Sub class / Child class / Derived class 라고도 불린다
오버라이딩자식 클래스가 부모에서 물려받은 메서드를 같은 이름으로 재정의하는 것
private자기 클래스에서만 접근 가능. 자식 클래스에서도 직접 접근 불가
$this현재 객체 자신. new Guest()로 생성하면 $this는 Guest 객체를 가리킨다
상속 체인A extends B extends C처럼 여러 단계로 상속이 연결되는 구조
is-a 관계"Guest is a User" — 자식은 부모의 일종이라는 객체지향 설계 원칙
protected자신과 자식 클래스 모두 접근 가능한 접근제어자. private처럼 외부 직접 접근은 불가하되, 상속 체인 내부에서는 공유된다.
parent::자식에서 부모의 오버라이딩된 메서드를 명시 호출하는 문법. parent::print_hello()처럼 쓴다.
1 extends — 부모의 기능을 물려받는 이유
코드를 반복 작성하지 않기 위해 상속을 쓴다
같은 기능을 여러 클래스에서 반복 작성하면 코드 중복이 생기고 유지보수가 어려워진다. extends로 상속받으면 부모에 있는 모든 public/protected 메서드와 변수를 자식 클래스가 자동으로 갖게 된다. 자식 클래스는 추가하거나 바꿔야 할 부분만 작성하면 된다.
class User { public function login() { /* 로그인 처리 */ } public function logout() { /* 로그아웃 처리 */ } } class Admin extends User { // login(), logout() 상속받아 그대로 사용 public function deleteUser() { /* 관리자만의 추가 기능 */ } } class Guest extends User { // login(), logout() 상속받아 사용 public function print_hello() { /* 게스트 인사말 변경 */ } }
※ "부모가 공통 기능, 자식이 특수화된 기능" — 이 구조가 상속을 쓰는 핵심 이유다.
2 오버라이딩 — 같은 이름으로 내용을 바꾸는 이유
물려받은 메서드를 그대로 쓰기 싫을 때
부모의 print_hello는 "안녕하세요"를 출력하지만, Guest는 "반갑습니다"를 출력해야 한다. 메서드 이름을 바꾸면 부모와 다른 이름이 되어서 외부 코드가 수정되어야 한다. 같은 이름을 유지하면서 내용만 바꾸는 것이 오버라이딩의 목적이다. 외부에서 항상 print_hello()를 호출하면 되고, 어떤 객체냐에 따라 자동으로 다른 동작이 나온다.
오버라이딩 없이 다른 이름 사용
print_hello_guest()
호출하는 쪽이 객체 타입을 알고 다른 메서드를 써야 함. 유지보수 어려움.
오버라이딩으로 같은 이름 유지
print_hello()
어떤 객체든 같은 이름 호출. 런타임에 자동으로 적합한 버전 선택.
오버라이딩이 만드는 힘 — 다형성(Polymorphism)
- 같은 메서드 이름으로 객체 타입에 따라 다른 동작을 만드는 것을 다형성이라 한다
- 호출하는 쪽은 어떤 자식 객체인지 몰라도
print_hello()만 부르면 된다
- Guest2, Admin 등 새 클래스가 추가돼도 외부 코드는 수정 불필요 — 확장에 열려 있다
3 private과 상속 — 왜 $name이 각자 다른가
private은 자식 클래스에 상속되지 않는다
User의 private $name = null은 User 클래스 안에서만 접근 가능하다. Guest가 extends로 User를 상속받아도 User의 private 변수에는 접근할 수 없다. 그래서 Guest는 자신만의 private $name = "게스트"를 별도로 선언한다. 이 두 $name은 완전히 별개의 변수다.
class User { private $name = null; // User::$name — User 클래스만 접근 가능 } class Guest extends User { private $name = "게스트"; // Guest::$name — User::$name과 완전히 별개. "게스트"로 초기화됨 public function print_hello() { print $this->name; // Guest의 $name = "게스트" 출력 } }
⚠ 자식에서 부모의 변수에 접근하려면 private 대신 protected를 써야 한다. protected는 자식 클래스에서도 접근 가능하다.
4 객체 생성과 상속 체인 동작
new Guest()를 실행하면 어떤 순서로 동작하나
new Guest()를 실행하면 Guest 객체가 생성된다. Guest가 User를 상속받았으므로 User의 public/protected 메서드들도 함께 사용 가능 상태가 된다. 단, print_hello()는 Guest에서 오버라이딩했으므로 Guest 버전이 실행된다.
1
new Guest() 실행Guest 객체 생성. Guest::$name = "게스트" 초기화
2
상속받은 메서드 포함User의 public 메서드들이 Guest 객체에서도 사용 가능 상태
3
print_hello() 호출Guest에 오버라이딩된 print_hello()가 있으므로 Guest 버전 선택
4
실행 결과"게스트님, 반갑습니다!" 출력. User::print_hello()는 실행되지 않음
new Guest()
→
상속 포함
→
print_hello 호출
→
Guest 버전 실행
5 상속을 받았을 때 사용 가능한 메서드 목록
자식은 부모의 것과 자신의 것 모두 사용 가능하다
자식 클래스가 extends로 부모를 상속받으면, 부모의 public/protected 메서드는 자식 객체에서도 바로 호출할 수 있다. 자식이 같은 이름으로 오버라이딩한 메서드가 있으면 자식 버전을 우선 실행하고, 없으면 부모 버전을 실행한다.
| 메서드 |
User에 정의? |
Guest에 정의? |
Guest 객체에서 호출 시 |
print_hello() |
✅ 있음 |
✅ 오버라이딩 |
Guest 버전 실행 |
| 부모 전용 메서드(예: login()) |
✅ 있음 |
❌ 없음 |
부모 버전 그대로 실행 |
| Guest 전용 메서드 |
❌ 없음 |
✅ 있음 |
Guest 버전 실행 |
6 protected — 자식 클래스와 공유되는 접근제어자
private이 너무 제한적일 때 protected를 쓴다
이 예제에서 User의 private $name = null을 Guest가 직접 사용하려 하면 접근 오류가 난다. protected로 변경하면 자식 클래스에서도 $this->name으로 접근 가능하다. 외부(클래스 밖)에서는 여전히 직접 접근 불가하므로 데이터 보호는 유지된다.
class User { protected $name = null; // protected — 자식 클래스에서 접근 가능 public function print_hello() { print $this->name . "님, 안녕하세요!"; } } class Guest extends User { public function setName($n) { $this->name = $n; // protected이므로 자식에서 접근 가능 } }
| 접근제어자 |
클래스 내부 |
자식 클래스 |
외부 |
public |
✅ |
✅ |
✅ |
protected |
✅ |
✅ |
❌ |
private |
✅ |
❌ |
❌ |
⚠ 이 예제의 코드는 의도적으로 private을 사용해서 자식이 별도 변수를 선언하도록 만들었다. 실제로 자식 클래스가 부모의 변수를 읽고 써야 한다면 protected로 선언하는 것이 올바른 패턴이다.
7 자주 하는 실수
| 실수 |
증상 |
해결 |
| 오버라이딩인 줄 몰랐는데 메서드가 바뀜 |
부모 메서드인데 자식 버전 결과 나옴 |
extends 받은 클래스에서 같은 이름 메서드를 재선언하면 오버라이딩 발생 |
| 자식에서 부모의 private 변수 $this->로 접근 |
null 또는 undefined notice |
부모 private는 자식 접근 불가. protected로 변경하거나 getter 사용 |
| extends 뒤에 여러 클래스 나열 |
Parse error — 다중 상속 불가 |
PHP는 단일 상속만 허용. 추가 기능은 trait(use)로 해결 |
| 부모 메서드를 오버라이딩 후 부모 로직도 필요함 |
기존 기능이 사라짐 |
자식 메서드 안에서 parent::print_hello()로 부모 버전 명시 호출 |
| new User()로 생성 후 Guest 오버라이딩 기대 |
User 버전 메서드 실행됨 |
오버라이딩된 버전을 쓰려면 new Guest()로 생성해야 함 |
핵심 한 줄 요약
extends부모 클래스의 public/protected 메서드·변수를 자식이 물려받는다
오버라이딩자식에서 같은 이름의 메서드를 재정의 — 런타임에 자식 버전이 우선 실행됨
private과 상속private은 자식에서 접근 불가 — 자식이 같은 이름으로 선언하면 독립 변수
다중 상속 불가PHP는 extends로 부모 1개만 지정 가능 — 추가 기능은 trait으로 해결
parent::오버라이딩 후 부모 버전도 실행하고 싶을 때 parent::메서드명()으로 명시 호출
protected자식에서 접근 가능, 외부에서는 불가 — 상속 체인 내부 공유가 필요할 때 private 대신 사용
Tags
#PHP 상속 #PHP 오버라이딩 #extends #부모 클래스 #자식 클래스 #PHP OOP #메서드 재정의 #PHP 클래스 상속 #Guest 클래스 #PHP 객체지향 #private protected #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
PHP 상속, PHP 오버라이딩, extends, 부모 클래스, 자식 클래스, PHP OOP, 메서드 재정의, PHP 클래스 상속, PHP 객체지향, private protected
댓글