language-oop5-abstract
클래스 추상화
PHP에는 추상 클래스, 추상 메서드, 추상 프로퍼티가 있어요. 추상으로 정의된 클래스는 인스턴스를 만들 수 없고, 추상 메서드나 추상 프로퍼티를 하나라도 포함하는 클래스는 반드시 추상이어야 해요.
추상 메서드는 시그니처와 그것이 public인지 protected인지만 선언할 뿐, 구현은 정의할 수 없어요. 추상 프로퍼티는 get이나 set 동작에 대한 요구사항을 선언할 수 있고, 두 동작 중 하나에 대해서만 구현을 제공할 수 있어요.
추상 클래스를 상속할 때는 부모 클래스 선언에서 추상으로 표시된 모든 메서드를 자식 클래스가 정의해야 해요. 그 과정에서 평소의 상속 규칙과 시그니처 호환성 규칙을 그대로 따르게 돼요.
PHP 8.4부터 추상 클래스는 public 또는 protected 추상 프로퍼티를 선언할 수 있어요. protected 추상 프로퍼티는 protected 또는 public 범위에서 읽고 쓸 수 있는 프로퍼티로 충족될 수 있어요.
추상 프로퍼티는 일반 프로퍼티로 채울 수도 있고, 요구된 동작에 맞춰 훅(hook)이 정의된 프로퍼티로 채울 수도 있어요.
예제 #1 추상 메서드 예제
<?php
abstract class AbstractClass
{
// Force extending class to define this method
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// Common method
public function printOut()
{
print $this->getValue() . "\n";
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue()
{
return "ConcreteClass1";
}
public function prefixValue($prefix)
{
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue()
{
return "ConcreteClass2";
}
public function prefixValue($prefix)
{
return "{$prefix}ConcreteClass2";
}
}
$class1 = new ConcreteClass1();
$class1->printOut();
echo $class1->prefixValue('FOO_'), "\n";
$class2 = new ConcreteClass2();
$class2->printOut();
echo $class2->prefixValue('FOO_'), "\n";
?>
위 예제는 다음과 같이 출력돼요:
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2
예제 #2 추상 메서드 예제
추상 메서드는 필수 인자만 정의하면 되고, 자식 클래스는 부모 시그니처에 없는 선택적 매개변수를 추가로 정의할 수 있어요.
<?php
abstract class AbstractClass
{
// An abstract method only needs to define the required arguments
abstract protected function prefixName($name);
}
class ConcreteClass extends AbstractClass
{
// A child class may define optional parameters which are not present in the parent's signature
public function prefixName($name, $separator = ".")
{
if ($name == "Pacman") {
$prefix = "Mr";
} elseif ($name == "Pacwoman") {
$prefix = "Mrs";
} else {
$prefix = "";
}
return "{$prefix}{$separator} {$name}";
}
}
$class = new ConcreteClass();
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>
위 예제는 다음과 같이 출력돼요:
Mr. Pacman
Mrs. Pacwoman
예제 #3 추상 프로퍼티 예제
<?php
abstract class A
{
// Extending classes must have a publicly-gettable property
abstract public string $readable {
get;
}
// Extending classes must have a protected- or public-writeable property
abstract protected string $writeable {
set;
}
// Extending classes must have a protected or public symmetric property
abstract protected string $both {
get;
set;
}
}
class C extends A
{
// This satisfies the requirement and also makes it settable, which is valid
public string $readable;
// This would NOT satisfy the requirement, as it is not publicly readable
protected string $readable;
// This satisfies the requirement exactly, so is sufficient.
// It may only be written to, and only from protected scope
protected string $writeable {
set => $value;
}
// This expands the visibility from protected to public, which is fine
public string $both;
}
?>
예제 #4 훅이 있는 추상 프로퍼티 예제
<?php
abstract class A
{
// This provides a default (but overridable) set implementation,
// and requires child classes to provide a get implementation
abstract public string $foo {
get;
set {
$this->foo = $value;
}
}
}
?>
추상 클래스의 추상 프로퍼티는 어떤 훅이든 구현을 제공할 수 있지만, get이나 set 중 하나 이상은 선언만 하고 정의하지 않은 채 남겨두어야 해요(바로 위 예제처럼).