로그인 회원가입
모두인포
전체IT경제사회생활스포츠시사여행연애

PHP에서 생성자(__construct)

lmkfox · 2025-08-27 · 조회 0
PHP에서 생성자(__construct)
1) 생성자란? - 객체가 new로 만들어질 때 가장 먼저 호출되는 초기화 메소드입니다. - 시그니처: public function __construct(/* ... */) { /* 초기화 */ } - 반환값이 없습니다. 값을 반환하려고 하면 오류입니다(필요하면 예외를 던져 인스턴스 생성을 막을 수 있음). class User { private int $id; private string $name; public function __construct(int $id, string $name) { if ($id <= 0) throw new InvalidArgumentException('id > 0'); $this->id = $id; $this->name = $name; } } $u = new User(1, 'Kim'); 2) 생성자 프로퍼티 승격(PHP 8.0+) 생성자 매개변수에 가시성 + 타입을 붙이면 선언과 대입이 한 번에 됩니다. class Point { public function __construct( private int $x, private int $y, ) {} public function x(): int { return $this->x; } public function y(): int { return $this->y; } } $p = new Point(10, 20); - 승격과 검증 로직을 함께 쓰려면 본문에서 가드하면 됩니다(승격된 프로퍼티는 본문 진입 전에 이미 대입됨). class Email { public function __construct(public string $value) { if (!filter_var($this->value, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException('invalid email'); } } } 3) readonly 프로퍼티(PHP 8.1+) - 생성자에서만 대입 가능, 그 이후 불변. final class Money { public function __construct( public readonly int $amount, public readonly string $currency ) {} } 4) 타입드 프로퍼티 초기화 규칙 - 타입이 달린 프로퍼티는 초기화 전에 접근하면 오류가 납니다. - 기본값은 상수 표현식만 가능(함수 호출/new 불가) → 이런 초기화는 생성자에서 처리. class Session { private string $token; // 반드시 생성자에서 채워야 함 public function __construct() { $this->token = bin2hex(random_bytes(16)); } } 5) 상속과  parent::__construct() - 자식이 생성자를 재정의하면, 부모 생성자는 자동 호출되지 않습니다. 필요하면 직접 호출하세요. class Base { public function __construct(protected PDO $db) {} } class Repo extends Base { public function __construct(PDO $db, private string $table) { parent::__construct($db); // 반드시 명시 호출 } } - self vs static은 생성자 내부보다는 팩토리 메소드에서 차이가 큼(아래 #7 참조). 6) 오버로딩은 없고, 선택지는 3가지 PHP엔 메소드 **오버로딩(같은 이름 다른 시그니처)**이 없습니다. 대안: - 기본값과 nullable/union 타입 사용 - 이름 있는 정적 팩토리(fromString(), fromArray() 등) 제공 - 가변 인자 ...$args로 직접 분기(가독성 떨어질 수 있음) class Color { private function __construct(private int $r, private int $g, private int $b) {} public static function fromRGB(int $r, int $g, int $b): self { return new self($r,$g,$b); } public static function fromHex(string $hex): self { $hex = ltrim($hex, '#'); return new self(hexdec(substr($hex,0,2)), hexdec(substr($hex,2,2)), hexdec(substr($hex,4,2))); } } 7) private 생성자와 팩토리 패턴 - 직접 인스턴스화 금지하고, 정적 팩토리만 허용하고 싶을 때. final class Token { private function __construct(private string $value) {} public static function random(): self { return new self(bin2hex(random_bytes(16))); } public static function fromString(string $v): self { return new self($v); } } - 상속 고려 시 팩토리에서 new static()을 쓰면 늦은 정적 바인딩으로 하위 타입 반환이 유연합니다. 8) DI 친화적 생성자 - 외부 자원(Pdo, 클라이언트, 서비스 등)은 생성자 주입이 가장 단순하고 테스트하기 좋습니다. - 테스트에서 가짜 구현(인터페이스) 주입이 쉬워집니다. interface Clock { public function now(): DateTimeImmutable; } final class SystemClock implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable(); } } final class Greeter { public function __construct(private Clock $clock) {} public function greet(string $name): string { $h = (int)$this->clock->now()->format('G'); return ($h < 12 ? 'Good morning' : 'Hello').", $name"; } } 9) 호출 편의: 기본값·이름 있는 인자·가변 인자 class ReportQuery { public function __construct( private DateTimeImmutable $from, private DateTimeImmutable $to, private int $limit = 100 ) {} } $q = new ReportQuery( from: new DateTimeImmutable('2025-08-01'), to: new DateTimeImmutable('2025-08-31'), limit: 1000 ); 10) 예외와 트랜잭션적 초기화 - 생성자에서 불변식 위반은 즉시 예외로 막으세요(잘못된 객체가 태어나지 않도록). - 여러 외부 작업을 한다면 실패 시 부분 상태가 남지 않게 설계(가능하면 생성자에서 무거운 I/O는 피하고, 별도 init()/connect() 메소드로 분리). class Account { public function __construct(private int $id, private int $balance = 0) { if ($id <= 0) throw new InvalidArgumentException('id > 0'); if ($balance < 0) throw new InvalidArgumentException('balance >= 0'); } } try { $a = new Account(-1); } catch (InvalidArgumentException $e) { /* 처리 */ } 11) 트레이트와 생성자 - 트레이트도 __construct를 가질 수 있습니다. 클래스와 충돌하면 클래스 쪽이 우선. - 필요하다면 별칭으로 살려서 수동 호출합니다. trait T { public function __construct(private string $x) {} } class C { use T { __construct as private tConstruct; } public function __construct() { $this->tConstruct('v'); } } 12) 익명 클래스/열거형과 생성자 - 익명 클래스도 생성자를 가질 수 있습니다. $o = new class(10) { public function __construct(public int $n) {} }; - Enum은 생성자가 제한적입니다(케이스 정의와 함께 백킹/메소드 제공). 일반 객체처럼 자유로운 상태 주입은 아님. 13) 생성자 우회/직렬화 관련 - unserialize()는 생성자를 호출하지 않습니다. 복원 시 초기화가 필요하면 __wakeup()/__unserialize() 활용. - 리플렉션의 newInstanceWithoutConstructor()로 생성자 없이 객체 만들기가 가능하지만 특수 상황에서만 사용하세요(테스트/프록시 등). 14) 안티패턴과 주의점 - 무거운 I/O(DB 연결, 원격 호출)를 생성자에서 직접 수행 → 실패/지연 시 인스턴스화 자체가 깨짐. 가벼운 검증까지만 하고 실행은 별도 메소드로 분리 권장. - 생성자에서 오버라이드 가능한 메소드 호출 → 자식에서 덮어쓴 메소드가 부분 초기화 상태로 실행돼 버그 유발. - 불변 설계에서 public 프로퍼티 노출 → 불변식 붕괴. readonly/메소드로 노출. - 동적 프로퍼티 사용(PHP 8.2+ 비권장). 반드시 명시 선언. 15) 한 장 예제: 값 객체 + 엔티티 초기화 final class Email { public function __construct(public readonly string $value) { if (!filter_var($this->value, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException('invalid email'); } } } final class User { public function __construct( private int $id, private Email $email, private DateTimeImmutable $createdAt = new DateTimeImmutable() ) { if ($this->id <= 0) throw new InvalidArgumentException('id > 0'); } public function id(): int { return $this->id; } public function email(): Email { return $this->email; } }

댓글

아직 댓글이 없습니다.

로그인 후 댓글을 남길 수 있습니다.