role 접근 시 __get을 거치지 않고 직접 접근합니다. protected ?string $role = null; public ?string $name = null; public ?string $phone = null; public ?string $email = null; public ?string $history = null; public ?int $account_balance = null; public ?int $coupon_balance = null; public ?int $point_balance = null; public ?string $status = null; public function __construct(array $datas = []) { // 1. [전처리] role이 배열로 들어왔다면 문자열로 변환하여 $datas 덮어쓰기 if (isset($datas['role']) && is_array($datas['role'])) { $datas['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $datas['role']); } // 2. 변환된 $datas를 가지고 부모(CommonDTO) 생성자 호출 // 이제 'role'은 문자열이므로 부모 클래스의 Reflection 로직이나 타입 검사를 통과합니다. parent::__construct($datas); } /** * role 속성을 읽을 때 자동으로 배열로 변환해서 반환 */ public function __get(string $name) { // role을 요청했고, 실제 데이터가 문자열로 존재한다면 배열로 변환 if ($name === 'role') { if (is_string($this->role)) { return explode(DEFAULTS["DELIMITER_ROLE"], $this->role); } return []; // null이거나 값이 없으면 빈 배열 반환 } // 부모에게 위임 (혹시 CommonDTO에도 __get이 있다면) // CommonDTO에 __get이 없다면 이 줄은 에러가 날 수 있으므로, // 보통은 아래처럼 처리하거나 속성을 리턴해야 합니다. return $this->{$name} ?? null; } // role 값을 설정할 때도 배열을 받을 수 있게 하려면 __set도 필요할 수 있습니다. // (선택 사항) public function setRole(array $roles) { $this->role = implode(DEFAULTS["DELIMITER_ROLE"], $roles); } }