0Pricing
PHP Academy · 강의

C로 기본 PHP 확장 기능 작성

직접 만든 네이티브 확장 기능을 빌드하고 로드합니다.

C로 기본 PHP 확장 기능 작성은(는) CoddyKit의 무료 PHP Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 PHP Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. PHP Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

PHP의 네이티브 코드

순수 PHP가 너무 느리거나 C 라이브러리를 연결해야 한다면 Zend API를 사용해 C로 PHP 확장 기능을 작성합니다. 확장 기능은 PHP가 VM 오버헤드 없이 직접 호출하는 네이티브 함수와 클래스를 제공합니다.

이 단원에서는 최소한의 hello 확장 기능을 처음부터 끝까지 만듭니다. 뼈대 작성, 함수 구현, 빌드, 로드, 테스트를 다룹니다.

빌드 도구 체인

확장 모듈은 설치된 PHP의 헤더를 사용해 autoconf 빌드를 준비하는 PHP의 phpize로 빌드합니다. phpize와 php-config를 제공하는 php-dev/php-devel과 C 컴파일러, make가 필요합니다.

# Install build prerequisites (Debian/Ubuntu)
sudo apt install php-dev build-essential

# Confirm the tools exist
phpize --version
php-config --extension-dir   # where the .so will be installed

config.m4

모든 확장 모듈에는 빌드 플래그를 등록하고 소스 파일을 선언하는 config.m4가 필요합니다. phpize는 이를 사용해 configure 스크립트를 생성합니다.

dnl config.m4 for the 'hello' extension
PHP_ARG_ENABLE([hello],
  [whether to enable hello support],
  [AS_HELP_STRING([--enable-hello], [Enable hello])],
  [no])

if test "$PHP_HELLO" != "no"; then
  PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fi

확장 모듈 헤더

C 소스는 Zend/PHP 헤더를 포함하고 모듈 진입점을 선언합니다. php.h는 핵심 API를 불러오고, ext/standard/info.h는 phpinfo() 출력에 사용됩니다. 모든 확장 모듈은 zend_module_entry를 정의합니다.

/* hello.c — includes */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "ext/standard/info.h"
#include "hello_arginfo.h"   /* generated from stub */

인수 정보 스텁

최신 PHP는 .stub.php 파일에서 인수 메타데이터를 생성합니다. PHP와 비슷한 구문으로 함수 시그니처를 작성하면 gen_stub.php가 hello_arginfo.h를 생성합니다. 이를 통해 리플렉션과 형식 정보가 정확하게 유지됩니다.

<?php
// hello.stub.php — describes the native function's signature
/** @generate-class-entries */

function hello_greet(string $name): string {}
?>

함수 구현하기

네이티브 함수는 PHP_FUNCTION으로 표시된 C 함수입니다. ZEND_PARSE_PARAMETERS 매크로로 들어오는 인수를 분석하고, RETURN_* 매크로를 통해 값을 반환합니다. 여기서는 인사말 문자열을 만듭니다.

/* hello.c — the native function */
PHP_FUNCTION(hello_greet)
{
    char *name;
    size_t name_len;

    ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_STRING(name, name_len)
    ZEND_PARSE_PARAMETERS_END();

    /* Build "Hello, <name>!" into a new zend_string */
    zend_string *result = strpprintf(0, "Hello, %s!", name);
    RETURN_STR(result);   /* hands ownership to the engine */
}

모듈 진입점

zend_module_entry는 이름, 버전, 함수 테이블(인수 정보에서 가져옴), 생명 주기 후크(MINIT, RINIT, MINFO)를 모두 연결합니다. ZEND_GET_MODULE은 로더가 찾는 진입 심볼을 내보냅니다.

/* hello.c — module wiring */
zend_module_entry hello_module_entry = {
    STANDARD_MODULE_HEADER,
    "hello",                 /* extension name */
    ext_functions,           /* function table from arginfo */
    NULL,                    /* MINIT  (module startup)  */
    NULL,                    /* MSHUTDOWN */
    NULL,                    /* RINIT  (per-request)     */
    NULL,                    /* RSHUTDOWN */
    PHP_MINFO(hello),        /* phpinfo section */
    "0.1.0",
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif

메모리: emalloc과 malloc 비교

확장 모듈 내부에서는 요청 수명 메모리를 할당할 때 emalloc/efree를 사용해야 합니다. 이 메모리는 Zend 메모리 관리자가 추적하며 요청이 끝날 때 해제됩니다. 원시 malloc은 사용하지 마세요. 영구적 할당(요청 간에 유지되는 할당)에는 pemalloc을 사용합니다. RETURN_STR을 통해 zend_string을 반환하면 소유권이 엔진으로 이전되고, 엔진이 이를 해제합니다.

/* Request-scoped buffer the engine will clean up on error/shutdown */
char *buf = emalloc(64);
/* ... use buf ... */
efree(buf);

/* Persistent allocation surviving the request (rare) */
/* char *cfg = pemalloc(128, 1);  ...  pefree(cfg, 1); */

빌드하기

전통적인 3단계 빌드는 다음과 같습니다. phpize로 뼈대를 만들고, 활성화 플래그와 함께 ./configure를 실행한 다음, make를 실행합니다. 먼저 gen_stub.php를 실행해 인수 정보 헤더를 생성해야 합니다.

# Generate arginfo from the stub
php /path/to/php-src/build/gen_stub.php hello.stub.php

# Scaffold + configure + compile
phpize
./configure --enable-hello
make

# Result lands in modules/hello.so
ls -la modules/hello.so

로드 및 테스트

컴파일된 .so는 -d extension=...로 로드하거나 ini 파일에 추가합니다. 그런 다음 네이티브 함수를 내장 함수와 똑같이 PHP에서 호출합니다. 다음은 확장 모듈을 설치한 후 작성하는 테스트 및 검증 스크립트의 모습입니다.

<?php
// After:  php -d extension=./modules/hello.so test.php
if (!extension_loaded('hello')) {
    fwrite(STDERR, "hello extension not loaded\n");
    exit(1);
}

echo hello_greet('Zend') . PHP_EOL;   // Hello, Zend!
var_dump(extension_loaded('hello'));  // bool(true)
?>

작성할 때와 작성하지 말아야 할 때

네이티브 확장 모듈은 C 메모리 버그, PHP 마이너 버전마다 필요한 재빌드, ABI 손상과 같은 유지 관리 비용을 발생시킵니다. 네이티브 방식으로 만들기 전에 FFI를 사용하거나 순수 PHP를 최적화하는 방법을 고려해 보세요. 컴파일 없이 PHP에서 C 라이브러리를 호출할 수 있습니다. 최고 속도, 깊은 엔진 통합, 또는 복잡한 C 라이브러리를 깔끔하게 감싸는 기능이 필요할 때 C 확장 모듈을 선택하면 됩니다.

<?php
// FFI alternative: call a C library directly, no extension build
$ffi = FFI::cdef(
    "int abs(int);",   // declare the symbol
    "libc.so.6"
);
echo $ffi->abs(-42) . PHP_EOL;   // 42
?>

빠른 확인

확장 모듈 내부에서 요청 수명 메모리를 관리해야 하는 할당자는 무엇인가요?

복습

최소한의 C 확장 모듈을 만들었습니다. config.m4가 빌드를 등록하고, .stub.php가 인수 정보를 생성하며, PHP_FUNCTION이 ZEND_PARSE_PARAMETERS로 인수를 분석하고 RETURN_STR로 반환하는 로직을 구현합니다. 또한 zend_module_entry가 생명 주기 후크를 연결합니다. phpize → configure → make로 빌드하고, .so를 로드한 다음 PHP에서 테스트하세요. 요청 메모리에는 emalloc을 사용하고, 네이티브 코드를 선택하기 전에 FFI도 고려해 보세요.

자주 묻는 질문

“C로 기본 PHP 확장 기능 작성” 강의는 무료인가요?

네 — “C로 기본 PHP 확장 기능 작성” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 PHP Academy 강의 전체를 잠금 해제할 수 있습니다. PHP Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“C로 기본 PHP 확장 기능 작성”에서 뭘 배우나요?

직접 만든 네이티브 확장 기능을 빌드하고 로드합니다. 브라우저에서 직접 실행하는 실습 코드로 PHP Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

PHP Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 PHP Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“C로 기본 PHP 확장 기능 작성” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 PHP Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 PHP Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Zend Engine의 작동 원리
  2. 메모리 관리와 가비지 컬렉션
  3. OPcache와 JIT 컴파일
  4. C로 기본 PHP 확장 기능 작성
← PHP Academy(으)로 돌아가기