트레이트 – 17.정적 멤버와 싱글턴 패턴

트레이트는 정적 변수, 정적 프로퍼티와 정적 메소드를 모두 정의할 수 있습니다. 트레이트는 기존의 클래스가 구성하고 있는 상속 관계를 전혀 손상시키지 않으면서, 더욱 심플하게 작성된 코드를 재사용할 수 있으므로, 트레이트에서 지원하는 정적 멤버의 특성을 이용하여 싱글턴 패턴(singleton pattern)과 멀티턴 패턴(multiton pattern)을 구현하게 되면, 이를 더욱 편리하게 클래스에 조합하여 사용할 수 있습니다.

PHP가 객체 지향 언어로서 많은 진전을 이루면서 싱글턴 패턴을 구현할 수 있는 기능들을 지원하고 있습니다.

PHP 5.3에서는 후기 정적 바인딩(late static binding)이 도입되면서 이와 관련하여 static 키워드와 get_called_class 함수를 지원하며, PHP 5.4에서는 트레이트(trait)를 지원하며, PHP 5.5에서는 get_called_class 함수를 대체할 수 있는 static::class를 지원합니다.

정적 변수(Static Variables)

플래트닝 속성(flattening property)에 의해, 동일한 트레이트의 동일한 메소드에서 유래되었다 하더라도 사용 시점에 관계없이 모든 메소드는 서로 독립적입니다. 이러한 트레이트에서 정적 변수를 사용하여 카운터를 구현하고 다양한 위치에서 사용하려고 합니다. 각 카운터는 독립적이어야합니다.

위 예제의 출력 결과에서 보듯이 메소드 내에 정의된 정적 변수는 클래스 상속 계층 별로 별도의 기억 장소가 할당되지만, 같은 계층의 클래스에서 생성된 객체들은 모두 같은 기억 장소에 할당된 정적 변수를 참조합니다.

Note:
PHP 8.1에서 상속된 메소드의 정적 변수의 동작이 변경됩니다. PHP 8.0까지는 정적 변수를 포함하는 메소드가 상속될 때 상속된 메소드는 상위 클래스의 메소드와는 독립된 정적 변수를 사용하였으나, PHP 8.1부터는 상속과 관계없이 메소드 당 하나의 정적 변수만 보유합니다.

관련자료 – PHP RFC: Static variables in inherited methods

이러한 정적 변수의 특성을 이용하면 각 계층의 클래스 객체마다 단 하나의 인스턴스만을 생성할 수 있도록 하는 멀티턴 패턴(multiton pattern)을 아래와 같이 구현할 수 있습니다.

멀티턴 패턴은 싱글턴 패턴의 범주에 속하며, 싱글턴 패턴을 확장시켜 여러 개의 싱글턴 패턴을 일정한 범위 내에서 독자적으로 관리하는 방식입니다.

getInstance 함수로 인스턴스를 생성할 때 인수를 가변적으로 전달하기 위해서는 … 구문을 활용할 수 있습니다. … 토큰으로 전달된 가변 길이 인수(variable-length arrument)는 배열로 변환되어 getInstance 함수의 매개변수(parameter)에 전달됩니다.

… 구문은 PHP 5.6 이상에서 사용할 수 있으며, 트레이트가 도입된 PHP 5.4 이상에서는 … 구문 대신에 func_num_args(), func_get_arg(), func_get_args() 함수를 사용하여 가변 길이 인수(variable-length arrument)를 전달할 수도 있습니다.

정적 프로퍼티(Static Property)

생성된 모든 인스턴스들이 공유하는 공통적인 정보가 필요할 때에 사용되는 것이 정적 프로퍼티입니다. 정적 프로퍼티는 다른 일반 프로퍼티와 달리 각각의 인스턴스에 기억 장소가 할당되는 것이 아니라, 단 한 개의 기억 장소 만이 할당되고 모든 인스턴스에 의하여 공유됩니다. 하지만 프로퍼티의 정보는 각각의 인스턴스가 모두 가지고 있는 것처럼 간주됩니다.

이와 같이 모든 인스턴스에서 공유하는 프로퍼티를 정적 프로퍼티로 선언하므로서, 모든 인스턴스에서 중복되는 기억 장소를 절약하는 효과를 얻을 수 있습니다. 때에 따라서는 동일한 클래스 또는 이를 상속한 클래스를 이용해 몇 개의 인스턴스를 생성하더라도 동일한 데이터로 취급해야 할 프로퍼티가 필요합니다.

위에서 살펴본 정적 변수는 클래스 상속 계층 별로 별도의 기억 장소가 할당되지만, 정적 프로퍼티는 클래스 상속 계층과 상관없이 컴파일할 때 정적 프로퍼티가 정의된 클래스에 기억 장소가 할당되며, 런타임할 때 모든 상속 계층에서 이 기억 장소를 공유합니다.

아래에서 살펴볼 정적 메소드와 함께 정적 프로퍼티의 특성을 이용하면 해당 클래스와 관련된 모든 클래스와 객체에 단 하나의 인스턴스만을 생성할 수 있도록 하는 싱글턴 패턴(singleton pattern)을 구현할 수 있습니다.

또한 정적 메소드에서 클래스 상속 계층을 구별할 수 있는 유일한 값을 구할 수 있거나, 객체를 생성할 때 그 유일한 값을 생성자의 매개변수로 전달할 수 있다면, 각 계층의 클래스 객체마다 단 하나의 인스턴스 만을 생성할 수 있도록 하는 멀티턴 패턴(multiton pattern)을 구현할 수 있습니다.

정적 메소드(Static Method)

트레이트는 컴파일러에서 지원되는 복사·붙여넣기 기능과 거의 유사하며, 지금까지 트레이트에게 적용된 모든 기능은 정적 메소드에도 적용됩니다. 이것은 재사용 가능한 싱글턴 패턴(singleton pattern)을 구현하여 제공할 때 유용합니다.

PHP 5.3, 5.4, 5.5에서 지원하기 시작한 후기 정적 바인딩(late static binding)과 관련된 static 키워드, static::class를 이용하면 재사용 가능한 멀티턴 패턴(multiton pattern)을 구현할 수 있습니다.

답글 남기기