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

PHP에서 클래스 정의

lmkfox · 2025-08-25 · 조회 0
PHP에서 클래스 정의
1) 가장 기본: 클래스, 인스턴스, 메소드 <?php declare(strict_types=1); class Greeter { // 프로퍼티(상태) private string $prefix = 'Hello'; // 메소드(행위) public function greet(string $name): string { return "{$this->prefix}, {$name}"; } } $g = new Greeter(); // 인스턴스 생성 echo $g->greet('World'); // "Hello, World" 요점 - class로 타입(설계도)을 정의하고, new로 인스턴스(실제 객체)를 만듭니다. - 메소드 안에서 자기 자신에 접근할 때는 $this를 사용합니다. - declare(strict_types=1);를 파일 상단에 두면 타입이 엄격해져 버그를 줄일 수 있습니다. 2) 접근 제어자(가시성)와 타입 선언 class User { public function __construct( private int $id, private string $name, // 생성자 프로퍼티 승격(8.0+) ) {} public function id(): int { return $this->id; } // 게터 public function rename(string $to): void { $this->name = $to; } public function name(): string { return $this->name; } } - public: 어디서나 접근 가능 - protected: 자신과 자식 클래스에서만 접근 - private: 해당 클래스 내부에서만 접근 - 매개변수/반환 타입, 프로퍼티 타입을 꼭 선언하세요. 유지보수와 도구 지원이 좋아집니다. 3) 생성자, 프로퍼티, 불변(immutable) 설계 final class Money { public function __construct( public readonly int $amount, // 8.1+: readonly 프로퍼티 public readonly string $currency ) {} public function add(Money $other): Money { if ($this->currency !== $other->currency) { throw new InvalidArgumentException('Currency mismatch'); } return new Money($this->amount + $other->amount, $this->currency); } } - __construct는 인스턴스 초기화. - readonly는 생성 이후 변경 불가(불변 값 객체에 유리). - 도메인 규칙(통화 일치 등)은 메소드에서 강제하세요. 4) 정적 멤버와 클래스 상수 class MathUtil { public const PI = 3.1415926535; public static function circleArea(float $r): float { return self::PI * $r * $r; } } echo MathUtil::circleArea(2.0); - 정적 메소드/프로퍼티는 인스턴스 없이 ClassName::method()로 호출. - 상태가 필요 없고 순수 계산일 때만 제한적으로 사용하세요(과도한 static 남용 지양). 5) 메소드 체이닝(Fluent 인터페이스) class Query { private array $where = []; private ?int $limit = null; public function where(string $cond): self { $this->where[] = $cond; return $this; // 체이닝 포인트 } public function limit(int $n): self { $this->limit = $n; return $this; } public function toSql(): string { $sql = 'SELECT * FROM t'; if ($this->where) $sql .= ' WHERE ' . implode(' AND ', $this->where); if ($this->limit !== null) $sql .= " LIMIT {$this->limit}"; return $sql; } } $sql = (new Query())->where('age >= 20')->where('active = 1')->limit(10)->toSql(); 6) 상속, 오버라이드,  parent abstract class Notifier { abstract public function send(string $msg): void; // 추상 메소드 } class EmailNotifier extends Notifier { public function __construct(private string $to) {} public function send(string $msg): void { // 이메일 발송 로직 } } class SmsNotifier extends Notifier { public function __construct(private string $phone) {} public function send(string $msg): void { // SMS 발송 로직 } } - extends로 상속, abstract로 공통 인터페이스 강제. - 오버라이드 시 시그니처(매개변수/반환타입)를 호환되게 유지하세요. - 부모 메소드를 함께 쓰고 싶으면 parent::method(). 7) 인터페이스와 다형성, 의존성 주입 interface Clock { public function now(): DateTimeImmutable; } final class SystemClock implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable(); } } final class GreetingService { public function __construct(private Clock $clock) {} public function greet(string $name): string { $hour = (int)$this->clock->now()->format('G'); $prefix = $hour < 12 ? 'Good morning' : 'Hello'; return "{$prefix}, {$name}"; } } $svc = new GreetingService(new SystemClock()); // 테스트에선 FakeClock 주입 가능 - 인터페이스로 의존을 추상화하면 테스트/교체가 쉬워집니다. - 프레임워크 없이도 생성자 주입 패턴을 쓰는 습관이 좋습니다. 8) 트레이트로 코드 재사용 trait Timestamps { private ?DateTimeImmutable $createdAt = null; public function touch(): void { $this->createdAt = new DateTimeImmutable(); } public function createdAt(): ?DateTimeImmutable { return $this->createdAt; } } class Post { use Timestamps; } - trait는 다중 상속 대신 메소드/프로퍼티 묶음을 주입하는 도구. - 트레이트끼리 충돌 시 insteadof, as로 해결 가능. 9)  self  vs  static (늦은 정적 바인딩) class Base { public static function make(): static // 8.0+: static 반환 타입 { return new static(); // 호출한 클래스 타입으로 생성 } public function who(): string { return self::class; } } class Sub extends Base { public function who(): string { return static::class; } } echo Base::make()->who(); // "Base" echo Sub::make()->who(); // "Sub" - self는 정의된 클래스 고정, static은 실제 호출한 하위 클래스를 따릅니다. 10) 매직 메소드(필요할 때만) class Box { public function __construct(private array $items = []) {} public function __toString(): string { return json_encode($this->items); } public function __get(string $name) { /* 동적 접근 처리 */ } public function __set(string $name, $value) { /* 동적 설정 처리 */ } } - __construct, __destruct, __get/__set, __call/__callStatic, __toString, __clone 등이 있습니다. - 과도하게 의존하면 디버깅이 어려워지므로 최소 사용을 권장합니다. 11) 네임스페이스와 오토로딩(PSR-4) src/ Domain/ User.php // namespace App\Domain; <?php namespace App\Domain; final class User { /* ... */ } composer.json { "autoload": { "psr-4": { "App\\": "src/" } } } - composer dump-autoload 후 use App\Domain\User;로 클래스 자동 로딩. - 함수만 담긴 파일은 autoload.files를 쓰거나 클래스로 감싸 관리성을 높입니다. 12) 객체 비교, 복제, 불변 컬렉션 $a = new User(1, 'A'); $b = $a; var_dump($a === $b); // true (같은 인스턴스) $c = clone $a; // 얕은 복제 var_dump($a === $c); // false - ===는 같은 객체인지(동일 참조) 비교, ==는 프로퍼티 값 동등 비교. - 복제 시 내부 참조가 있으면 깊은 복제를 직접 구현해야 합니다. 13) 예외 처리와 계약 보증 class BankAccount { public function __construct(private int $balance = 0) {} public function deposit(int $amount): void { if ($amount <= 0) throw new InvalidArgumentException('amount > 0'); $this->balance += $amount; } public function withdraw(int $amount): void { if ($amount <= 0) throw new InvalidArgumentException('amount > 0'); if ($amount > $this->balance) throw new RuntimeException('insufficient funds'); $this->balance -= $amount; } public function balance(): int { return $this->balance; } } - 잘못된 입력은 예외로 막아 불변식을 지키세요. - 퍼블릭 메소드는 클래스의 “계약”입니다. 입력·출력 타입과 예외를 문서화하세요. 14) 코딩 규칙과 실무 팁 - 클래스명 StudlyCaps, 메소드/프로퍼티 camelCase(PSR-12). - 가능한 한 public 프로퍼티 금지, private + 메소드로 캡슐화. - 상태가 없는 유틸은 정적 메소드보다 독립 함수가 종종 더 깔끔합니다. - 도메인 규칙을 값 객체로 모델링하면 버그가 줄어듭니다. - 단위 테스트하기 좋게 의존성은 생성자 주입으로. 15) 한 번에 복습하는 예제 <?php declare(strict_types=1); namespace App\Billing; interface DiscountRule { public function apply(int $price): int; } final class PercentOff implements DiscountRule { public function __construct(private float $rate) {} // 0.1 = 10% public function apply(int $price): int { return (int) round($price * (1 - $this->rate)); } } final class Cart { /** @var list<int> */ private array $items = []; public function addItem(int $price): self { if ($price < 0) throw new \InvalidArgumentException('price >= 0'); $this->items[] = $price; return $this; } public function total(): int { return array_sum($this->items); } public function checkout(DiscountRule $rule): int { return max(0, $rule->apply($this->total())); } } // 사용 use App\Billing\{Cart, PercentOff}; $cart = (new Cart())->addItem(12000)->addItem(8000); echo $cart->checkout(new PercentOff(0.1)); // 18000

댓글

아직 댓글이 없습니다.

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