80 lines
2.4 KiB
PHP
80 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\DTOs;
|
|
|
|
use ReflectionClass;
|
|
use ReflectionNamedType;
|
|
|
|
abstract class CommonDTO
|
|
{
|
|
protected function __construct(array $datas = [])
|
|
{
|
|
// 데이터가 없으면 바로 리턴
|
|
if (empty($datas)) {
|
|
return;
|
|
}
|
|
|
|
// $this는 이 시점에 자식 클래스(AccountDTO)의 인스턴스입니다.
|
|
$reflection = new ReflectionClass($this);
|
|
|
|
foreach ($datas as $key => $value) {
|
|
// 1. 속성이 존재하는지 확인
|
|
if (!$reflection->hasProperty($key)) {
|
|
continue;
|
|
}
|
|
|
|
$property = $reflection->getProperty($key);
|
|
|
|
// public이 아닌 속성도 접근 가능하게 설정 (필요시)
|
|
// $property->setAccessible(true);
|
|
|
|
// 2. 속성의 타입 정보를 가져옴
|
|
$type = $property->getType();
|
|
|
|
// 값을 할당하기 전 정제된 값을 담을 변수
|
|
$assignValue = $value;
|
|
|
|
// 3. 빈 문자열("") 처리
|
|
// HTML 폼에서 온 빈 값은 null로 처리해야 ?int 등에 들어갈 수 있음
|
|
if ($value === '') {
|
|
$assignValue = null;
|
|
}
|
|
// 4. 타입에 따른 강제 형변환 (Casting)
|
|
elseif ($type instanceof ReflectionNamedType) {
|
|
$typeName = $type->getName();
|
|
|
|
// int 타입이고 값이 숫자형일 때
|
|
if ($typeName === 'int' && is_numeric($value)) {
|
|
$assignValue = (int) $value;
|
|
}
|
|
// float 타입이고 값이 숫자형일 때
|
|
elseif ($typeName === 'float' && is_numeric($value)) {
|
|
$assignValue = (float) $value;
|
|
}
|
|
// 필요하다면 bool 처리 등 추가 가능
|
|
}
|
|
|
|
// 5. 값 할당
|
|
$this->{$key} = $assignValue;
|
|
}
|
|
}
|
|
|
|
public function __get(string $name): mixed
|
|
{
|
|
// 1. 속성이 클래스에 실제로 존재하는지 확인
|
|
if (property_exists($this, $name)) {
|
|
// 2. 속성이 존재하면 값을 반환 (PHP 7.4 이상의 타입 속성 덕분에 null 병합 연산자 사용 불필요)
|
|
return $this->{$name};
|
|
}
|
|
// 3. 속성이 존재하지 않으면 오류 발생 (일반적인 Entity/DTO 접근 방식)
|
|
throw new \BadMethodCallException(
|
|
"Undefined property or method: " . static::class . "::{$name}"
|
|
);
|
|
}
|
|
final public function toArray(): array
|
|
{
|
|
// $this가 가진 모든 public 프로퍼티와 그 값을 배열로 반환합니다.
|
|
return get_object_vars($this);
|
|
}
|
|
}
|