Computer >> 컴퓨터 >  >> 프로그래밍 >> PHP

PHP 추상 클래스(Abstrace Class) 완벽 정리: 개념부터 핵심 규칙까지

PHP 5부터 객체 지향 프로그래밍 모델이 도입되었습니다. 이 모델에는 클래스(class), 객체(object), 캡슐화(encapsulation), 다형성(polymorphism), 추상 클래스와 final 클래스, 인터페이스(interface), 상속(inheritance) 등 다양한 개념이 포함되어 있습니다.

이 글에서는 그중에서도 추상 클래스(Abstract Class)가 무엇인지, PHP의 객체 지향 기법과 어떻게 연결되는지 자세히 살펴보겠습니다. 또한 실제 예제 코드를 통해 추상 클래스를 구현하는 방법까지 함께 알아봅니다.

추상 클래스란 무엇인가?

추상 클래스는 클래스 이름 앞에 abstract 키워드를 붙여서 선언합니다. 정의는 매우 명확합니다. 추상 메서드(abstract method)를 하나라도 포함하고 있는 클래스를 추상 클래스라고 부릅니다.

추상 메서드는 메서드의 이름과 매개변수(시그니처)만 선언할 뿐, 실행 코드(몸통, body)를 가질 수 없습니다.

중요한 점은 추상 클래스로는 객체를 직접 생성할 수 없다는 것입니다. 대신 추상 클래스를 상속받은 자식 클래스(child class)가 추상 메서드의 구체적인 내용을 구현해야 하며, 이렇게 만들어진 자식 클래스를 통해서만 객체를 생성하고 사용할 수 있습니다.

PHP 추상 클래스의 핵심 규칙

1. 추상 메서드와 일반 메서드를 함께 가질 수 있다

추상 클래스 안에는 추상 메서드뿐 아니라 일반(구현된) 메서드도 함께 포함될 수 있습니다.

예제:

<?php
    abstract class base {
        abstract function printdata();
        public function getdata() {
            echo "Tutorials Point";
        }
    }
    class child extends base {
        public function printdata() {
            echo "Good morning";
        }
    }
    $obj = new child();
    $obj->getdata();
?>

실행 결과:

Tutorials Point

2. 직접 인스턴스화할 수 없다

추상 클래스는 new 키워드로 객체를 생성하려 하면 치명적 오류(fatal error)가 발생합니다.

예제:

<?php
    abstract class AbstractClass {
        abstract protected function calculate();
        public function adddata() {
            echo "Addition done";
        }
    }
    $obj = new AbstractClass();
    $obj->adddata();
?>

실행 결과:

Fatal error: Uncaught Error: Cannot instantiate abstract class AbstractClass

3. 접근 제어자는 같거나 더 넓은 범위여야 한다

자식 클래스는 부모 클래스에 선언된 모든 추상 메서드를 반드시 재정의해야 하며, 이때 시그니처는 동일하거나 접근 범위가 더 넓어야 합니다.

예를 들어 부모 클래스에서 추상 메서드를 protected로 선언했다면, 자식 클래스에서는 protected 또는 public으로 구현해야 하며 private으로는 구현할 수 없습니다.

예제:

<?php
    abstract class AbstractBaseClass1 {
        abstract public function addValue();
        abstract protected function getValue();
    }
    class ConcreteClass extends AbstractBaseClass1 {
        protected function addValue() {
            return "ConcreteClass";
        }
        public function getValue() {
            return " Child Class";
        }
    }
    $classobj = new ConcreteClass;
    $classobj->addValue();
?>

실행 결과:

Fatal error: Access level to ConcreteClass::addValue() must be public (as in class AbstractBaseClass1)

부모 클래스에서 public으로 선언된 addValue()를 자식 클래스에서 protected로 좁혀 구현했기 때문에 오류가 발생했습니다.

4. 추상 메서드는 몸통(body)을 가질 수 없다

abstract로 선언된 메서드는 시그니처만 정의할 수 있으며, 중괄호 안에 실행 코드를 작성할 수 없습니다. 반면 일반(비추상) 메서드에는 당연히 코드 본문이 존재할 수 있습니다.

예제:

<?php
    abstract class ParentClass {
        abstract protected function printValue() {
            return "Good morning";
        }
    }
    class ClassA extends ParentClass {
        protected function printValue() {
            return "ConcreteClass1";
        }
    }
    $classobj = new ClassA;
    $classobj->printValue();
?>

실행 결과:

PHP Fatal error: Abstract function ParentClass::printValue() cannot contain body

5. 추상 메서드가 하나라도 있으면 클래스 전체를 abstract로 선언해야 한다

클래스 안에 추상 메서드가 하나라도 포함되어 있다면, 해당 클래스는 반드시 abstract로 선언해야 합니다. 그렇지 않으면 PHP는 오류를 발생시킵니다.

예제:

<?php
    class AbstractClass {
        abstract protected function getValue();
        public function printData() {
            echo " Welcome to Tutorials Point";
        }
    }
    $obj = new AbstractClass();
    $obj->printData();
?>

실행 결과:

PHP Fatal error: Class AbstractClass contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (AbstractClass::getValue)

6. 다중 상속(multiple inheritance)을 지원하지 않는다

PHP에서 추상 클래스는 다중 상속을 지원하지 않습니다. 하나의 클래스는 하나의 부모 클래스만 상속받을 수 있습니다.

예제:

<?php
    abstract class SuperClass {
        public abstract function test();
        protected function welcome() {
            echo "Good morning";
        }
    }
    class ClassA extends SuperClass {
        public function test() {
            echo "Hello";
        }
        protected function welcome() {
            echo "Good afternoon";
        }
    }
    class ClassB extends SuperClass {
        public function test() {
            echo "Hello";
        }
        protected function welcome() {
            echo "Good evening";
        }
    }
    class ClassC extends ClassA, ClassB {
        public function test1() {
            $c = new self();
            $c->welcome();
        }
    }
?>

실행 결과:

Error

왜 다중 상속이 불가능할까?

위 코드에서는 SuperClass라는 추상 클래스에 test()welcome() 메서드를 선언하고, 이를 상속받는 구체 클래스(concrete class)인 ClassAClassB를 만들었습니다. 그런 다음 ClassAClassB를 동시에 상속하는 ClassC를 생성하려고 했습니다.

그러나 ClassC의 객체로 welcome() 메서드를 호출하는 순간, 컴파일러 입장에서는 ClassAwelcome()를 호출해야 할지, 아니면 ClassBwelcome()를 호출해야 할지 판단할 수 없습니다. 이런 모호성(ambiguity) 문제를 피하기 위해 PHP는 다중 상속을 지원하지 않습니다.

참고 사항:

  • 추상 클래스는 다른 추상 클래스를 상속(확장)할 수 있습니다.
  • 추상 클래스는 인터페이스(interface)의 구현체를 제공할 수 있습니다.