| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- dhgrp
- 객체복제
- 인덱스
- 데코레이터패턴
- 라라벨
- Tool Calling
- 데이터베이스
- docker
- 디자인패턴
- docker network
- mcp client
- SQL
- MCP
- mcp server
- OOP
- PHP객체지향
- MySQL
- 어댑터패턴
- 소프트웨어설계
- 객체지향
- SQL문법
- Laravel
- 매직메서드
- ai agent
- PHP
- LLM
- ai 에이전트
- linux 권한
- Agent Loop
- SQL기초
- Today
- Total
개발블로그
[객체지향] PHP static과 스코프 해석 연산자 본문
개념
static
객체가 아니라 클래스 자체에 속한 속성이나 메서드를 정의할 때 사용하는 키워드
static으로 정의한 속성이나 메서드는 객체를 만들지 않고 클래스 이름으로 접근 가능
클래스 멤버]
| 구분 | 의미 | 예시 |
| 객체 멤버 | 객체마다 따로 가지는 속성이나 메서드 | 자동차의 색상, 무게 |
| 클래스 멤버 | 클래스 자체에 속하는 속성이나 메서드 | 생성된 자동차 수, 공통 설정값 |
| 클래스 상수 | 클래스 안에 정의한 변하지 않는 값 | 상태 코드, 타입 값 |
스코프 해석 연산자
::
=> 클래스, 부모 클래스, 현재 클래스의 정적 멤버나 상수에 접근할 때 사용
비교]
| 연산자 | 사용 대상 | 예시 |
| -> | 객체 | $car->startEngine() |
| :: | 클래스, 정적 멤버, 상수 | Car::getCount() |
관련키워드
[self]
현재 클래스 자신을 가리킴
정적 메서드나 클래스 상수에 접근할 때 자주 사용함
class Car
{
public const TYPE = "vehicle";
public static function getType()
{
return self::TYPE;
}
}
[parent]
부모 클래스를 가리킴
자식 클래스에서 부모 클래스의 메서드나 생성자, 상수에 접근할 때 사용함
class Animal
{
public function speak()
{
return "동물이 소리를 냅니다.";
}
}
class Dog extends Animal
{
public function speak()
{
// 부모클래스인 Animal의 speak() 메서드를 호출함
return parent::speak() . " 그리고 멍멍";
}
}
[static]
현재 호출된 클래스를 기준으로 정적 멤버에 접근할 때 사용
self와 비슷해 보이지만 상속 관계에서 차이가 있음
| 키워드 | 기준 |
| self | 코드가 작성된 클래스 |
| static | 실제 호출한 클래스 |
class ParentClass
{
public static function who()
{
return "부모";
}
public static function test()
{
return static::who();
}
}
class ChildClass extends ParentClass
{
public static function who()
{
return "자식";
}
}
echo ChildClass::test(); // 자식
정적 속성
객체가 아니라 클래스 자체에 속하는 속성
속성 앞에 static을 붙여 정의
class Car
{
public static $count = 0;
public $color = "";
public function __construct()
{
self::$count++;
}
}
// 접근 : 객체를 생성하지 않고, 클래스 이름으로 접근
echo Car::$count;
// 일반속성은 객체마다 따로 존재함
$car1 = new Car();
$car2 = new Car();
$car1->color = "black";
$car2->color = "white";
// 정적속성은 모든 객체가 공유함
echo Car::$count; // 2
정적 메서드
개념/문법
객체를 만들지 않고 클래스 이름으로 호출할 수 있는 메서드
class Calculator
{
public static function add($a, $b)
{
return $a + $b;
}
}
echo Calculator::add(10, 20); // 30
정적 메서드 안에서든 $this 사용 불가
why) $this는 현재 객체를 의미하는데, 정적 메서드는 객체 없이 이름으로 호출될 수 있기 때문에 객체가 존재하지 않음
=> 정적메서드에서 정적 속성에 접근하려면 self:: 사용
class Car
{
public static $count = 0;
public static function getCount()
{
return self::$count;
}
}
객체 멤버와 차이
| 구분 | 객체 멤버 | 정적 멤버 |
| 소속 | 객체 | 클래스 |
| 접근 방식 | $object->method() | ClassName::method() |
| 상태 | 객체마다 다를 수 있음 | 클래스 단위로 공유됨 |
| $this 사용 | 가능 | 불가능 |
늦은 정적 바인딩
개념
상속 관계에서 static:: 이 실제로 호출한 클래스 기준으로 동작하게 하는 PHP의 기능
=> 어떤 클래스를 기준으로 할지 코드 작성 시점에 고정하지 않고 실행 시점에 결정 함
비교
| 키워드 | 기준 |
| self:: | 코드가 작성된 클래스 |
| static:: | 실제로 호출한 클래스 |
필요성
상속 구조에서는 부모 클래스에 공통 정적 메서드를 두고, 자식 클래스마다 일부 정적 동작만 다르게 만들고 싶을 때가 있음.
EX) 부모 클래스에는 공통 조회 메서드가 있고, 자식 클래스마다 다른 테이블 이름을 반환해야 함
Model
→ User
→ Post
<?php
class ParentClass
{
public static function identify()
{
return "부모";
}
public static function test()
{
echo "self 결과: " . self::identify() . PHP_EOL;
echo "static 결과: " . static::identify() . PHP_EOL;
}
}
class ChildClass extends ParentClass
{
public static function identify()
{
return "자식";
}
}
ChildClass::test();
/*
[결과]
self 결과: 부모
static 결과: 자식
[실행흐름]
ChildClass::test()
↓
ParentClass에 작성된 test() 실행
↓
self::identify()
↓
ParentClass::identify()
↓
"부모"
static::identify()
↓
ChildClass::identify()
↓
"자식"
*/
주의점
static과 스코프 해석 연산자는 클래스 단위의 값이나 기능을 다룰 때 유용하다.
하지만 정적 멤버를 무분별하게 사용하면 객체지향적인 구조가 흐려질 수 있음
static 남용
정적 메서드는 객체를 만들지 않고 바로 호출할 수 있어 편리하다.
객체 상태와 무관한 유틸리성 기능이라면 정적 메서드가 잘 맞을 수 있다.
하지만 객체가 가져야 할 상태나 책임까지 정적 메서드로 처리하며 코드가 절차적인 함수 모음처럼 변할 수 있다
EX]
class UserService
{
public static function createUser($name)
{
// 사용자 생성
}
public static function updateUser($id, $name)
{
// 사용자 수정
}
public static function deleteUser($id)
{
// 사용자 삭제
}
}
전역 상태
정적 속성은 클래스 전체에서 공유되는 값이기 때문에 여러 곳에서 같은 값을 쉽게 사용할 수 있다.
하지만 정적 속성은 전역 상태처럼 사용될 수 있어서, 어디서든 접근하고 변경할 수 있으면, 값이 언제 어디서 바뀌었는지 추적하기 어려워진다.
테스트 어려움
정적 메서드나 정적 속성에 강하게 의존하면 테스트가어려워질 수 있음.
ex]
class OrderService
{
public function createOrder($name)
{
Logger::log("주문 생성: " . $name);
}
}
Logger에 직접 의존함.
테스트할 때 가짜 로거로 교체하거나, 로그 호출 여부만 따로 확인하기 어려울 수 있음.
반면 필요한 객체를 외부에서 전달받으면 더 유연해짐
ex)
class OrderService
{
private $logger;
public function __construct($logger)
{
$this->logger = $logger;
}
public function createOrder($name)
{
$this->logger->log("주문 생성: " . $name);
}
}
테스트 시 원하는 로거 객체를 넣을 수 있음.
고려사항
| 질문 | 의미 |
| 객체 상태와 무관한 기능인가? | 정적 메서드가 적합한지 판단한다. |
| 여러 객체가 공유해야 하는 값인가? | 정적 속성이 필요한지 확인한다. |
| 어디서든 값이 바뀌어도 괜찮은가? | 전역 상태 문제가 없는지 본다. |
| 테스트에서 쉽게 대체할 수 있는가? | 정적 의존성이 테스트를 어렵게 만들지 않는지 확인한다. |
| 객체의 책임을 정적 메서드로 빼앗고 있지는 않은가? | 객체지향 구조가 흐려지는지 점검한다. |
'STUDY > PHP' 카테고리의 다른 글
| [객체지향] PHP Trait (1) | 2026.09.05 |
|---|---|
| PHP 변수 대입과 객체 복제 (1) | 2026.09.05 |
| [객체지향] PHP 매직 메서드 (0) | 2026.09.05 |
| PHP 네임스페이스와 use (0) | 2026.09.05 |
| Web Server에서 PHP가 실행되는 구조 (0) | 2026.08.29 |