기존 public 멤버를 유지하면서 기타 타입의 저장소에 타입 차원을 추가하고 캐시 접근 경로를 공통화한다. API와 clone 동작을 유지하고 직접 멤버 접근 코드의 이전 방법을 문서화한다. 검증: PHP 5.2.17 및 PHP 8.4.22에서 구문 검사와 객체 캐시 회귀 테스트 통과.
5.7 KiB
객체 캐시의 타입 격리와 호환성
G5_object_cache는 한 요청 안에서 사용하는 메모리 캐시다. common.php에서
요청마다 객체를 생성하며 요청 간 값 공유, TTL, Redis/Memcached 연동은 제공하지 않는다.
메서드 계약
캐시 주소는 (type, group, key)로 결정된다. 타입, 그룹, 키 중 하나라도 다르면
별도의 값을 저장한다. bbs, content, shop과 플러그인에서 정한 타입 모두에 적용된다.
인자 순서와 기본값은 기존과 같다.
$cache->set($type, $key, $data = array(), $group = 'default');
$cache->get($type, $key, $group = 'default');
$cache->exists($type, $key, $group = 'default');
$cache->delete($type, $key, $group = 'default');
type,group,key는 문자열 또는 정수 식별자를 사용한다. 배열과 객체를 식별자로 사용하는 것은 지원하지 않는다. PHP 배열 키 규칙에 따라 정수123과 문자열'123'은 같은 키다. 타입에도 같은 규칙이 적용된다.- 빈 문자열은 각 차원에서 유효하다. 빈 그룹
''은 생략 시 사용하는'default'와 다르다. 식별자에 별도의 정규화나 구분자 연결을 하지 않는다. set()은 값을 저장하고 명시적인 반환값 없이NULL을 반환한다.get()은 저장한 값을 반환하며, 없는 값은false를 반환한다. 저장한false와 cache miss는exists()로 구분한다.exists()는NULL,false,0,'0','', 빈 배열을 저장한 경우에도true다.delete()는 해당 주소만 제거하며 성공 시true, 없는 값이면false를 반환한다.- 객체는 저장 시와 조회 시 각각
clone한다. 기존과 같은 얕은 복사이며, 객체 내부의 중첩 객체나 배열 내부 객체까지 재귀적으로 복사하지 않는다. - 빈 타입·그룹 버킷은 정리하지 않는다. 기타 타입을 처음 조회할 때도 빈 타입 버킷이 만들어질 수 있으며 요청 종료 시 함께 해제된다.
$cache->set('shop', 'same-key', 'shop-value', 'same-group');
$cache->set('plugin', 'same-key', 'plugin-value', 'same-group');
$cache->get('shop', 'same-key', 'same-group'); // 'shop-value'
$cache->delete('plugin', 'same-key', 'same-group');
$cache->exists('shop', 'same-key', 'same-group'); // true
public 멤버 호환성과 업그레이드
세 public 멤버는 제거하지 않고 직접 접근을 deprecated로 표시했다.
$writes[$group][$key]와 $contents[$group][$key] 구조는 유지한다.
기타 타입의 충돌을 해결하기 위해 $etcs에는 타입 차원을 추가했다.
| 타입 | 기존 저장 구조 | 변경 후 저장 구조 |
|---|---|---|
bbs |
$writes[$group][$key] |
동일 |
content |
$contents[$group][$key] |
동일 |
| 그 외 | $etcs[$group][$key] |
$etcs[$type][$group][$key] |
메서드와 public 멤버는 같은 저장소를 사용한다. 호환용 데이터를 별도로 복제하거나
기존 $etcs 주소로 fallback하지 않는다. 기존 주소에는 타입 정보가 없어 어느 타입의
값인지 복원할 수 없기 때문이다. 메서드만 사용하는 호출부는 변경할 필요가 없다.
외부 테마·플러그인이 $etcs를 직접 읽거나 쓰거나 삭제한다면 다음과 같이 수정해야 한다.
기존의 서로 다른 타입 간 캐시 공유에 의존했다면 공유할 호출부에서 동일한 타입을
명시적으로 사용해야 한다.
// 변경 전: shop 등 모든 기타 타입이 같은 주소를 사용했다.
$cache->etcs[$group][$key] = $item;
$item = $cache->etcs[$group][$key];
unset($cache->etcs[$group][$key]);
// 변경 후 권장: 메서드로 타입과 존재 여부를 명시한다.
$cache->set('shop', $key, $item, $group);
if ($cache->exists('shop', $key, $group)) {
$item = $cache->get('shop', $key, $group);
}
$cache->delete('shop', $key, $group);
// 직접 접근이 불가피한 기존 코드의 새 주소 (deprecated)
$cache->etcs['shop'][$group][$key] = $item;
2026-09-09 저장소 PHP 코드 검색에서는 클래스 외부의 캐시 public 멤버 직접 접근을
확인하지 못했다. 코어의 bbs, content, shop 호출은 메서드를 사용한다.
공개 구현과
원 제보도 검토했다. 공개 웹에서
g5_object->writes, g5_object->contents, g5_object->etcs를 검색했으나
외부 플러그인의 직접 접근 사례는 확인하지 못했다. 검색에 잡히지 않는 코드의
호환성까지 보장하는 결과는 아니므로 public 멤버 제거는 이번 변경에 포함하지 않는다.
검증
php -l lib/Cache/obj.class.php
php -l tests/object_cache.php
php tests/object_cache.php
회귀 테스트는 타입·그룹·키 격리, 삭제 범위, 빈 값과 기본값, 객체 clone,
public 멤버와 메서드의 저장소 일치, 인스턴스 간 격리를 확인한다.
DB 대역을 사용해 실제 get_shop_item()의 빈 그룹 및 shop_{query hash} 그룹,
get_content_by_field()의 bbs/content 적재와 get_content_db()의 재사용도 확인한다.
실제 DB나 웹 세션은 필요하지 않다.
구현과 테스트는 PHP 5.2.17에서 지원하는 문법으로 작성했다. PHP 8.4.22와 PHP 5.2.17 CLI에서 변경 파일의 구문 검사와 회귀 테스트가 모두 통과했다. PHP 5.2.17은 공식 소스 배포본을 임시 디렉터리에서 CLI와 PCRE를 포함하도록 빌드해 검증했다. 시스템 PHP는 변경하지 않았다. 이 검증은 객체 캐시와 위 코어 호출부에 한정하며, 사이트 전체의 PHP 5.2 호환성을 검증한 것은 아니다.