zend_parse_parameters 함수를 사용합니다.

아마 매크로겠지만 그런 것 까지 신경쓰진 않습니다. ㅎㅎ


함수 만들기 기본 설명, 상세 파라미터 종류 들은 http://www.php.net/manual/en/internals2.funcs.php 에서 볼 수 있습니다..만 퍼옵니다.

 Spec

 Type

 Locals

 a

 array

 zval*

 A

 array or object

 zval*

 b

 boolean

 zend_bool

 C

 class

 zend_class_entry*

 d

 double

 double

 f

 function

 zend_fcall_info*, zend_fcall_info_cache*

 h

 array

 HashTable*

 H

 array or object

 HashTable*

 l

 long

 long

 L

 long (limits out-of-range LONG_MAX/LONG_MIN)

 long

 o

 object

 zval*

 O

 object (of specified zend_class_entry)

 zval*, zend_class_entry*

 p

 string (a valid path)

 char*, int

 r

 resource

 char*

 s

 string

 char*, int

 z

 mixed

 zval*

 Z

 mixed

 zval**


3번째 파라메터 문자열은 어떤 변수타입들을 받을지, 4번째 이후는 받을 변수들입니다.

zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "받을변수타입들", &변수1, &변수2, ....)


간단히 예시로 정리하면..

// bool : zend_bool
PHP_FUNCTION(test_func1)
{
	zend_bool bool_test;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &bool_test) == FAILURE) {
		RETURN_NULL();
	}
	
	if(bool_test==1)
	{
		// true
	}
	else
	{
		// false
	}

	RETURN_NULL();
}

// long
PHP_FUNCTION(test_func2)
{
	long long_test;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &long_test) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}

// string
PHP_FUNCTION(test_func3)
{
	char* str_test;
	int str_test_len;
	// 문자열의 경우 파라메터가 무조건 2개임을 명심..
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str_test, &str_test_len) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}



여러개일 경우는 그냥 타입을 여러개 쓰고 문자열같은 경우는 깊이값도 같이 받아주면 됩니다.


// multiple params
PHP_FUNCTION(test_func4)
{
	long a;
	double b;
	zend_bool c;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldb", &a, &b, &c) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}


// multiple params with string
PHP_FUNCTION(test_func5)
{
	long a;
	double b;
	zend_bool c;
	char * d;
	int d_len;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldb", &a, &b, &c, &d, &d_len) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}



리턴도 간단합니다.

자세한건 이 링크를 참고하면 되고.. http://docstore.mik.ua/orelly/webprog/php/ch14_08.htm


다른 타입들도 맞춰서 하면 됩니다. 잘 정리되어있네요.

RETURN_RESOURCE(int r);
RETURN_BOOL(int b) ;
RETURN_NULL( );
RETURN_LONG(int l) ;
RETURN_DOUBLE(double d) ;
RETURN_STRING(char *s, int dup) ;
RETURN_STRINGL(char *s, int l, int dup);
RETURN_EMPTY_STRING( );
RETURN_FALSE ;
RETURN_TRUE;
RETVAL_RESOURCE(int r);
RETVAL_BOOL(int b);
RETVAL_NULL( );
RETVAL_LONG(int l);
RETVAL_DOUBLE(double d);
RETVAL_STRING(char *s, int dup);
RETVAL_STRINGL(char *s, int l, int dup);
RETVAL_EMPTY_STRING( );
RETVAL_FALSE;
RETVAL_TRUE;

// return null
PHP_FUNCTION(test_func_ret1)
{
	RETURN_NULL();
}

조금 골치 아픈 건 배열이나 클래스인데 배열만 좀 써보면..

// assoc_array
PHP_FUNCTION(test_func_ret2)
{
	// return_value 는 zval* 타입입니다.
	// 선언은? 글로벌인지 로컬인지 모르겠지만 어딘가에서 해놨나봅니다. 다시 선언하면 오류납니다.
	array_init(return_value);

	add_assoc_long(return_value, "x", 123);
	add_assoc_double(return_value, "y", 456.7);
}

이러면 됩니다.

따로 return 명령을 내리지 않아도 리턴이 됩니다.

PHP에서 받아보면 이런 형태죠

<?php
$ret = test_func_ret2();
var_dump($ret);
?>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}


그럼 배열 안의 배열은 ? (subarray)

어떤 함수가 있는지는 PHP 페이지에 있습니다. http://www.php.net/manual/ro/internals2.variables.arrays.php


// sub_array PHP_FUNCTION(test_func_ret3) { zval *subarray; // 요걸 하나 만들어둡니다. int i; array_init(return_value); // 당연히 초기화 하고 for(i=0; i<3; i++) // 3개를 추가해보겠습니다. { MAKE_STD_ZVAL(subarray); // 이름봐선 데이터를 널이나 0으로 채워주는 놈인가봅니다... array_init(subarray); // 추가할 서브배열도 초기화하고 // 값들을 집어넣습니다. add_assoc_long(subarray, "x", 123); add_assoc_double(subarray, "y", 456.7); // 리턴할 값에 서브배열을 추가합니다. add_next_index_zval(return_value, subarray); } }


결과를 찍어보면?

<?php
$ret = test_func_ret3();
var_dump($ret);
?>

요렇게 나오겠죠

array(3) {

[0]=>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}

[1]=>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}

[2]=>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}

  }


Posted by freezn

PHP 모듈 작성 시 다음과 같은 오류 메세지가 나오는 경우가 있다.

error: 'PHP_FE_END' undeclared here (not in a function)


1. 

내 상황은 서버가 centos6.3 으로 php 는 rpm으로 설치되어있다.


php-devel 패키지도 설치해놨지만 ext_skel 은 없었고 구글링하다보니 src.rpm 을 던져주는 링크만 나오더라.

https://www.centos.org/forums/viewtopic.php?t=28478


2.

굳이 src.rpm으로 작업하고 싶은 생각은 없어 그냥 php-5.3.3 의 소스를 찾았지만 나오질 않는다.

그냥 php-5.3.28 을 받아 타르볼을 풀고

ext로 들어가 알려진대로


./ext_skel --extname=test_mod


cd test_mod


vi config.m4

10라인, PHP_ARG_WITH(test_mod, for test_mod support,

12라인, [  --with-test_mod             Include test_mod support])

에서 dnl 주석 해제


phpize

./configure

make


3.

뭐 이런 수순으로 스켈레톤을 빌드 해보는데 정의되지 않았다고 오류가 발생한다.

libtool: compile:  cc -I. -I/ ~~~~ :43: error: 'PHP_FE_END' undeclared here (not in a function)

make: *** [test_mod.lo] Error 1


4.

구글링해보니 PHP_FE_END는 php-5.3.10 부터 등장했단다. https://github.com/sqmk/pecl-jsmin/issues/23

이하버전에 호환되는 모듈을 뒤져보니 

{NULL, NULL, NULL}

다행히도 PHP_FE_END 대신 쓰이는 놈이 있다.

덜 게으르면 버전 확인해서 #if 하겠지만 한두개 뒤져봤을 때 PHP 버전 정의가 잘 안뵌다.

여러버전에서 자주 컴파일 할일이 있을 때 까진 그냥 이리 써야겠다.

test_mod.c :

const zend_function_entry test_mod_functions[] = {

PHP_FE(confirm_test_mod_compiled, NULL) /* For testing, remove later. */

//PHP_FE_END /* Must be the last line in test_mod_functions[] */ // PHP 5.3.10 ~

{NULL, NULL, NULL} /* Must be the last line in test_mod_functions[] */ // PHP 5.3.10 under

};


Posted by freezn