협업을 하며 코딩을 할땐 유지보수가 용이하게끔, 코드파악이 쉽게끔 그리고 작성한 코드가 작성자의 의도대로 사용되는 것이 중요하다.
이번 글에서 다룰 내용은 작성한 코드를 동료들이 사용할때 작성자의 의도대로 사용할수 있게끔 유도하는 방법 이다.
간단히 코드를 작성하기위해 아래와 같은 상황이 있다고 가정해보자.
여러 API 클라이언트를 관리해야 하는 상황에서 헤더의 host, access_token 을 제외한 나머지 값들은 모두 공통이다. 그래서 여러 API 클라이언트의 기반이 되는 BaseApiClient.php 추상 클래스를 상속 받아 각 API 클라이언트를 구현한 상황.
BaseApiClient.php
abstract class BaseApiClient
{
protected const HOST = self::HOST;
protected const ACCESS_TOKEN = self::ACCESS_TOKEN;
public function getHost()
{
// 참조: https://www.php.net/manual/en/language.oop5.late-static-bindings.php
return static::HOST; // Late Static Bindings
}
}
class ApiClientA extends BaseApiClient
{
}
$aClient = new ApiClientA();
echo $aClient->getHost(); // 에러 발생
위와 같이 작성한 경우 IDE 에서 Cannot declare self-referencing constant 라는 에러를 보여준다.
자기 참조 constant 를 할수 없다는것인데 런타임시 에러가 발생한다. 자식 클래스에서 const 를 재선언해서 사용해야 하기 때문에 BaseApiClient 를 상속 받은 클래스에서 const 선언을 하게끔 유도가 가능하다. (주석으로 설명을 덧붙여주면 좋을거같다.)
BaseApiClient.php 를 상속 받은 자식 클래스를 만들어 HOST, ACCESS_TOKEN 값을 재선언.
abstract class BaseApiClient
{
protected const HOST = self::HOST;
protected const ACCESS_TOKEN = self::ACCESS_TOKEN;
public function getHost()
{
return static::HOST;
}
}
class ApiClientA extends BaseApiClient
{
protected const HOST = 'https://api.a.com';
protected const ACCESS_TOKEN = 'a-token';
}
$aClient = new ApiClientA();
echo $aClient->getHost(); // 결과: https://api.a.com
하지만 가끔 이 방식이 작동하지 않고 에러가 발생한다는 경우도 있어 주의가 필요하긴 하다.
(예전부터 있던 오래된 버그라 함. 8.1 버전에서 bug fix 가 이루어졌다곤 하는데.. 추후 PHP 버전업시 또 어떻게 될지 모르니 주의하자)
This is fixed in PHP 8.1 in that the "namespace" no longer makes a difference, and no error is thrown in either case. The reason was a bug in the compile-time evaluator, which failed to replace self::OTHER during compilation if a namespace was used. However, as said above, whether or not an error gets thrown in this case is unspecified, and the behavior may change in the future.
그래서 좀더 안전한 방법은 다음과 같지 않을까? 주석 대신 Exception Message 를 통해 명확히 작성자의 의도를 전달할수도 있다.
abstract class BaseApiClient
{
protected const HOST = null;
protected const ACCESS_TOKEN = null;
public function getHost()
{
if (static::HOST === null) {
throw new \Exception('HOST is not defined');
}
return static::HOST;
}
}
class ApiClientA extends BaseApiClient
{
protected const HOST = 'https://api.a.com';
protected const ACCESS_TOKEN = 'a-token';
}
참고자료
'IT > php' 카테고리의 다른 글
[PHP] ?: 와 ?? 연산자의 차이점 (0) | 2024.09.12 |
---|---|
[PHP] Carbon 사용시 주의점 (0) | 2023.02.02 |