상속
상속은 PHP: 클래스에서 잠깐 살펴보았듯, 계를 표현합니다. 예를 들어 동물이라는 최상위 클래스를 상속받은 사람, 강아지, 고양이 등이 있을 수 있습니다. 상속이라는 개념을 사용하면 확장에 유용하고 추상 클래스나 인터페이스를 함께 사용하면 다양한 서드파티 클래스들을 받아서 이를 처리할 수 있게됩니다. 상속이라는 개념은 객체지향에서 중요한 개념이며 반드시 알아야 하는 사항이기도 합니다. 이는 PHP 뿐만 아니라 자바나 C++ 등 다른 언어에서도 중요합니다.
extends
상속을 사용하는 법 자체와 extends
키워드는 PHP: 클래스에서 알아보았으니 조금은 다른 주제에 대해 이야기해보자면, 상속과 함께 사용할 수 있는 개념인 생성자, 가시성, Final 키워드에 대한 것입니다. 개별의 주제는 각각 조금씩 다르지만 상속이라는 개념에서 공통적으로 사용하기 때문에 해당 파트에 넣게 되었습니다.
상속으로 발생하는 효과
상속으로 발생할 수 있는 효과를 알아보자면 면저 this
가 가르키는 스코프의 변화와 부모 클래스 타입에 대한 자식 클래스의 인스턴스 할당입니다. 상속을 사용하면 기본적으로 자식 클래스의 인스턴스는 부모 클래스 타입에 할당될 수 있습니다. 이러한 특성이 라이브러리가 서드파티 클래스를 조금 더 유연하게 사용될 수 있도록 해줍니다.
this
this
는 기본적으로 현재 객체를 말합니다만, 이러한 this
를 통해 메서드를 호출하는 경우 자식 클래스에 재정의가 되어있다면 자식 클래스의 메서드를 가르키지만, 그렇지 않다면 부모 클래스의 메서드를 호출하게 됩니다. 상속의 기본적인 특징 중 하나입니다.
class A
{
public function foo()
{
var_dump(__METHOD__);
}
}
class C extends A
{
}
$c = new C();
$c->foo(); // -> A::foo
부모 클래스 타입에 자식 클래스의 인스턴스를 넘기기
제목 그대로 부모 클래스의 타입에 자식 클래스의 인스턴스를 넘길 수 있습니다. 이는 함수 및 메서드에서 사용하는 경우가 많으며 객체지향 프로그래밍을 한다면 필수적으로 활용해야 할 요소이며, 설계적 측면에서도 중요한 의미를 갖습니다. 이것이 가능한 것으로 조금 더 일반화 된 형태로 특정 자식 클래스등을 처리할 수 있습니다.
function foo(B $b)
{
return $b->foo();
}
$c = new C();
var_dump(foo($c));
생성자
생성자는 객체를 생성할 때 상태를 초기화할 수 있는 방법을 제공합니다. __construct()
메서드를 사용하여 정의할 수 있으며, 예를 들어 아래와 같은 코드는 message
라는 값을 생성시 받아 상태를 초기화합니다. 생성자가 정의되지 않은 클래스의 경우 기본 생성자가 대신 그 역할을 수행합니다. 암묵적으로 생성됩니다.
class B
{
public $message;
public function __construct($message)
{
$this->message = $message;
}
}
$b = new B('Hello, world');
var_dump($b->message); // -> Hello, world
소멸자
소멸자는 C++ 에서 주로 사용하지만, 모던 언어에서는 지원하지 않는 경우가 대부분입니다. PHP 에서는 소멸자 또한 제공할 수 있습니다. 소멸자는 객체가 소멸할 때 호출됩니다. 객체 소멸시 리소스를 해제한다거나 할 때 사용할 수 있을 것입니다. 사용법 자체는 생성자와 동일하며, 대신 메서드의 이름이 __destruct()
이라는 점이 다릅니다.
class A
{
public function __destruct()
{
var_dump(__METHOD__); // -> A::__destruct
}
}
상속에서의 생성자와 소멸자
상속에서 생성자와 소멸자는 부가 효과가 있는데, 자식 클래스의 생성자가 별로도 정의되어 있지 않은 상황에서 자식 클래스의 인스턴스를 생성하면 부모 클래스의 생성자가 같이 호출됩니다.
class A
{
public function __construct()
{
var_dump(__METHOD__);
}
}
class C extends A
{
}
$c = new C(); // -> A::__construct
그러나 자식 클래스에 생성자나 소멸자가 있는 경우, parent
문맥 키워드를 통해 부모 클래스의 생성자를 명시적으로 호출해주어야 합니다.
class C extends A
{
public function __construct()
{
parent::__construct();
}
public function __destruct()
{
parent::__destruct();
}
}
가시성
가시성은 프로퍼티나 메서드에 대해 외부에서 접근할 수 있는 권리에 대한 이야기입니다. public, private, protected
이렇게 3가지가 있으며 각각 의미하는 바가 다릅니다.
public
클래스 파트를 이야기하면서 프로퍼티나 메서드에 계속 사용했던 가시성입니다. 상속 관계를 포함한 외부에서 접근할 수 있도록 선언합니다. 주로 사용자에게 제공되는 메서드를 public
키워드를 사용하여 정의합니다.
class A
{
public $public = 'public';
}
$a = new A();
var_dump($a->public); // -> public
protected
가시성 파트를 상속에 섞어서 이야기하고 있는 이유입니다. 상속 관계에서 접근할 수 있고 외부에서는 접근할 수 없도록 만듭니다.
class A
{
protected $protected = 'protected';
}
class B extends A
{
public function __construct()
{
var_dump($this->protected); // -> protected
}
}
private
상속관계를 포함한 외부에서 접근할 수 없도록 만듭니다. 클래스 내부에서만 사용할 수 있도록 합니다.
class A
{
private $private = 'private';
public function __construct($private)
{
$this->private = $private;
}
}
Final
클래스 선언시 final
키워드를 함께 적으면 해당 클래스를 또 다른 클래스가 상속받을 수 없습니다. 메서드에 적으면 재정의 할 수 없다는 것을 의미합니다.
상속할 수 없는 클래스
final class A
{
}
// class B extends A
// {
// }
재정의 할 수 없는 메서드
class A
{
final public function foo()
{
var_dump('Hello, world');
}
}
class B extends A
{
// public function foo()
// {
// }
}
더 읽을거리
PHP: 추상화 (추상 클래스, 인터페이스, 트레이트)
https://www.inflearn.com/course/php7-reboot