함수 매개변수
함수 호출자가 전달한 매개변수를 얻는 가장 간단한 방법은 zend_parse_parameters() 함수를 사용하는 것입니다. 커널의 매크로를 사용하여 zend_parse_parameters() 함수의 처음 몇 개의 매개변수를 ZEND_NUM_ARGS() TSRMLS_CC 형식으로 직접 생성할 수 있습니다. 둘 사이에는 공백이 있지만 쉼표는 없습니다. 이름에서 알 수 있듯이 ZEND_NUM_ARGS()는 매개변수의 개수를 나타냅니다. zend_parse_parameters() 함수에 전달되어야 하는 다음 매개변수는 printf의 첫 번째 매개변수와 마찬가지로 형식 지정에 사용되는 문자열입니다. 가장 일반적으로 사용되는 기호 중 일부는 다음과 같습니다.
type_spec은 형식 문자열이며 일반적인 의미는 다음과 같습니다.
매개변수는 유형을 나타냅니다.
b Boolean
l Integer
d 부동 소수점 부동 소수점
s 문자열 문자열
r 자원 자원
a 배열 배열
o 객체 인스턴스 객체
O 지정된 유형의 객체 인스턴스 특정 유형의 객체
z 비특정 zval 모든 유형 ~
Z zval** type
f는 함수명과 메소드명을 나타내는데 PHP5.1에는 그런게 없는 것 같은데...
이 함수는 printf() 함수와 같습니다. 형식 문자열은 일대일로 대응됩니다. 일부 기본 데이터 유형은 C 언어의 유형에 직접 매핑됩니다.
ZEND_FUNCTION(sample_getlong) {
long foo;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"l", &foo) == FAILURE)
{
RETURN_ NULL() ;
}
php_printf("매개변수의 정수 값: %ldn", foo);
RETURN_TRUE;
}
일반적으로 int와 long의 두 가지 데이터 유형은 데이터는 동일한 경향이 있지만 예외가 있습니다. 따라서 특히 64비트 플랫폼에서는 긴 배열을 int에 넣어서는 안 됩니다. 그러면 문제 해결이 쉽지 않은 버그가 발생할 수 있습니다. 따라서 zend_parse_parameter() 함수를 통해 매개변수를 수신할 때 커널에서 동의한 유형의 변수를 캐리어로 사용해야 합니다.
매개변수는 C의 데이터 유형에 해당합니다.
b zend_bool
l long
d double
s char*, int 전자는 포인터를 받고, 후자는 길이를 받습니다.
r zval *
a zval*
o zval*
O zval*, zend_class_entry*
z zval*
Z zval**
PHP 언어의 모든 복합 유형 매개변수에는 zval*이 필요합니다. 유형은 커널에 의해 사용자 정의된 일부 데이터 구조이기 때문에 캐리어로 사용됩니다. 매개변수의 유형과 캐리어가 일치하는지 확인해야 합니다. 필요한 경우 배열을 stdClass 객체로 변환하는 등의 유형 변환을 수행할 수 있습니다. s 및 O(유럽 대문자) 유형은 둘 다 두 개의 캐리어가 필요하므로 별도로 설명해야 합니다. 우리는 다음 장에서 PHP의 구체적인 객체 구현에 대해 배울 것입니다. 그럼 5장에서 정의한 함수를 다시 작성해 보겠습니다.
function Sample_hello_world($name) {
echo "Hello $name!n"
}
확장 프로그램을 사용하려면 다음 문자열을 받으려면 zend_parse_parameters()를 사용해야 합니다.
ZEND_FUNCTION(sample_hello_world) {
char *name
int name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS( ) TSRMLS_CC, "s",&name, &name_len) == 실패)
{
RETURN_NULL()
}
php_printf("Hello ")
PHPWRITE(name, name_len); php_printf("!n");
}
함수에 전달된 매개변수 개수가 zend_parse_parameters()에서 수신할 매개변수 개수보다 적으면 실패하고 FAILURE를 반환합니다.
여러 매개변수를 수신해야 하는 경우 다음과 같이 zend_parse_paramenters()의 매개변수에 수신 캐리어를 직접 나열할 수 있습니다.
function Sample_hello_world($name, $greeting) {
echo "Hello $greeting $name!n";
}
sample_hello_world('John Smith', 'Mr.')
이것은 PHP 확장에서 구현되어야 합니다:
ZEND_FUNCTION( Sample_hello_world) {
char *name
int name_len
char *greeting
int Greeting_len;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",&name, &name_len, &greeting, &greeting_len) == FAILURE) {
RETURN_NULL();
}
php_printf("Hello "); PHPWRITE(greeting, Greeting_len);
php_printf(" ");
PHPWRITE(name, name_len);
php_printf("!n");
}
위에는 매개변수 수신 기능을 강화하는 세 가지 다른 매개변수가 있습니다.
유형 수정자 의미
| 이전 매개변수는 모두 필요하며 다음 매개변수는 필요하지 않습니다. 즉, 기본값이 있습니다. 가치.
PHP 언어에서 null 변수를 받으면 IS_NULL 유형의 zval로 캡슐화하는 대신 C 언어에서 직접 NULL로 변환합니다.
/ 전달된 변수가 다른 변수와 zval을 공유하고 참조가 아닌 경우 새 zval의 is_ref__gc==0 및 refcount__gc==1이 강제로 분리됩니다.
함수 매개변수의 기본값
이제 계속해서 Sample_hello_world()를 다시 작성하겠습니다. 다음으로 PHP 언어에서 다음과 같은 일부 매개변수의 기본값을 사용합니다. , $greeting=' Mr./Ms.') {
echo "Hello $greeting $name!n"
}
sample_hello_world('Ginger Rogers','Ms.'); Sample_hello_world('Fred Astaire');
이번에는 Sample_hello_world에 하나의 매개변수만 전달할 수도 있고, 두 개의 완전한 매개변수를 전달할 수도 있습니다. 그렇다면 확장 기능에서 동일한 기능을 어떻게 구현할 수 있습니까? zend_parse_parameters에서 (|) 매개변수를 사용해야 합니다. 이 매개변수 이전의 매개변수는 필수로 간주되며, 전달되지 않은 매개변수는 필수가 아닌 것으로 간주됩니다.
ZEND_FUNCTION(sample_hello_world) {
char *name;
int name_len;
char *greeting = "Mr./Mrs."
int Greeting_len = sizeof("Mr./Mrs. ") - 1;
if (zend_parse_parameters (zend_num_args () tsrmls_cc," s | s ",
& name_len, & Greeting_len) == 실패
Return_null ( );
}
php_printf("안녕하세요");
PHPWRITE(greeting, Greeting_len);
php_printf(" ")
PHPWRITE(이름, 이름_len); );
}
두 번째 매개변수를 전달하지 않으면 확장 기능이 기본값으로 간주되어 벡터를 수정하지 않습니다. 따라서 캐리어의 값은 NULL인 경우가 많거나 함수 로직과 관련된 값을 직접 미리 설정해야 합니다. IS_NULL 유형 zval을 포함한 각 zval은 일정한 양의 메모리 공간을 점유해야 하며 이에 대한 메모리를 적용하고 초기화하고 작업 완료 후 해제하려면 CPU 컴퓨팅 리소스가 필요합니다. 그러나 많은 코드는 이를 인식하지 못합니다. IS_NULL 유형의 zval에 null 값을 래핑하는 코드가 많이 있습니다. 이 작업은 확장 개발에서 최적화될 수 있습니다. C 언어에서는 매개변수를 NULL로 받을 수 있습니다. 이 문제에 대해 다음 코드를 살펴보겠습니다.
ZEND_FUNCTION(sample_arg_fullnull) {
zval *val;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",&val) == FAILURE) {
RETURN_NULL();
}
if (Z_TYPE_P(val) == IS_NULL) {
val = php_sample_make_defaultval(TSRMLS_C)
}
...
}
ZEND_FUNCTION (sample_arg_nullok) {
zval *val;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!",
{
RETURN_NULL()
}
if (! val) {
val = php_sample_make_defaultval(TSRMLS_C)
}
}
두 코드 조각은 언뜻 보면 크게 다르지 않지만 첫 번째 코드 조각에는 더 많은 CPU와 메모리 리소스가 필요합니다. 어쩌면 이 기술은 평소에는 그다지 유용하지 않을 수도 있지만, 모르는 것보다는 아는 것이 더 낫습니다.
강제 분리
변수가 함수에 전달되면 참조 여부에 관계없이 refcoung__gc 속성이 1씩 증가하여 최소 2가 됩니다. 하나의 복사본은 그 자체이고 다른 하나는 함수에 전달된 복사본입니다. 이 zval을 변경하기 전에 미리 두 개의 실제 복사본으로 나누어야 하는 경우가 있습니다. "/" 형식 문자의 역할입니다. 쓰기 중 복사 zval을 미리 두 개의 완전하고 독립적인 복사본으로 분할하므로 다음 코드에서 마음대로 작업할 수 있습니다. 그렇지 않으면 수신된 매개변수와 기타 작업을 분리하도록 지속적으로 상기시켜야 할 수도 있습니다. NULL 플래그와 마찬가지로 이 수정자는 영향을 미치려는 유형을 따릅니다. 또한 NULL 플래그와 마찬가지로 이 기능을 실제로 사용할 때까지 이 기능이 필요한지 알 수 없습니다.
zend_get_arguments()
확장 프로그램이 이전 버전의 PHP와 호환되기를 원하거나 매개변수를 수신하기 위한 전달자로 zval을 사용하려는 경우 zend_get_parameters() 함수를 사용하여 매개변수를 수신하는 것을 고려할 수 있습니다. zend_get_parameters()는 zend_parse_parameters()와 다릅니다. 이름에서 알 수 있듯이 파싱 없이 직접 가져옵니다. 우선, 확장 구현에서 모든 매개변수의 전달자는 zval 유형이어야 합니다. 가장 간단한 예를 살펴보겠습니다.
ZEND_FUNCTION(sample_onearg) {
zval * firstarg ;
if (zend_get_parameters(ZEND_NUM_ARGS(), 1, &firstarg)== FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "1개 이상의 매개변수가 필요합니다."); > }
/* firstarg로 뭔가를 하세요... */
}
두 번째로, zend_get_parameters()는 수신 실패 시 자체적으로 오류를 발생시키지 않으며 매개변수의 기본값을 편리하게 처리할 수도 없습니다. 마지막 요점은 쓰기 중 복사를 준수하는 모든 zval을 자동으로 강제로 분리하고 새 복사본을 생성하여 함수에 보낸다는 점에서 zend_parse_parameters와 다르다는 것입니다. 다른 기능을 사용하고 싶지만 이 함수가 필요하지 않은 경우 zend_get_parameters_ex() 함수를 사용하여 매개변수를 받을 수 있습니다. 쓰기 중 복사의 변수를 분리하지 않기 위해 zend_get_parameters_ex()의 매개변수는 zval* 대신 zval** 유형입니다. 이 함수는 극단적인 문제가 발생할 때만 생각할 수 있지만 사용하기는 매우 간단합니다.
ZEND_FUNCTION(sample_onearg) {
zval **firstarg; zend_get_parameters_ex(1, &firstarg) == FAILURE) {
WRONG_PARAM_COUNT;
}
/* firstarg로 작업 수행... */
}
zend_get_parameters_ex에는 ZEND_NUM_ARGS()가 필요하지 않습니다. 매개변수로서 이후 단계에서 추가되었으므로 해당 매개변수는 더 이상 필요하지 않습니다.
위 예제에서도 WRONG_PARAM_COUNT 매크로가 사용되었습니다. 그 기능은 E_WARNING 수준 오류 메시지를 발생시키고 자동으로 반환하는 것입니다.
변수 매개변수
두 가지 다른 zend_get_parameter_** 함수가 있는데, 이는 매개변수가 많거나 매개변수 개수를 미리 알 수 없는 문제를 해결하는 데 특별히 사용됩니다. PHP 언어에서 var_dump() 함수의 사용법을 생각해 보세요. 커널에서의 구현은 실제로 다음과 같습니다.
ZEND_FUNCTION(var_dump) {
int i, argc = ZEND_NUM_ARGS ();
zval ***args;
args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); == 0 || zend_get_parameters_array_ex(argc, args) == 실패) {
efree(args);
WRONG_PARAM_COUNT;
}
for (i=0; i
}
efree(args);
}
프로그램은 먼저 매개변수 수를 얻은 다음 해당 메모리 크기에 적용합니다. safe_emalloc 함수를 통해 이러한 zvals ** 유형 매개변수를 저장합니다. 여기서 zend_get_parameters_array_ex() 함수는 함수에 전달된 매개변수를 args에 채우는 데 사용됩니다. zend_get_parameters_array()라는 함수도 있다는 것을 즉시 생각하셨을 것입니다. 유일한 차이점은 zval* 유형 매개변수를 args에 채우고 매개변수로 ZEND_NUM_ARGS()가 필요하다는 것입니다.