2013-01-31 18 views
5

我正在開發一個PHP擴展,使用C.到目前爲止,我正在對參數進行適當的驗證,並從PHP用戶空間傳遞給擴展的函數。如何讓ZEND_BEGIN_ARG_INFO_EX控制傳遞給PHP擴展的參數個數?

ZEND_BEGIN_ARG_INFO_EX可用於爲Zend引擎提供有關函數參數的信息。該宏的第四個參數(名爲required_num_args)讓引擎自動控制參數的數量,從而消除了這種麻煩。但是,我找不到使其工作的方式:即使PHP腳本沒有傳遞足夠的參數,引擎也會始終運行擴展的功能,而不會發出任何警告。

這裏是我的函數參數的定義:

ZEND_BEGIN_ARG_INFO_EX(test_func_swt_arginfo, 0, 0, 3) 
    ZEND_ARG_INFO(1, firstArg) 
    ZEND_ARG_ARRAY_INFO(0, secondArg, true) 
    ZEND_ARG_OBJ_INFO(1, thirdArg, SomeClass, false) 
ZEND_END_ARG_INFO() 

這裏是我的功能定義,由PHP擴展出口:

static const zend_function_entry test_func_functions[] = { 
    PHP_FE(sample_with_types, test_func_swt_arginfo) 
    PHP_FE_END 
}; 

這裏是我的功能:

PHP_FUNCTION(sample_with_types) 
{ 
    RETURN_TRUE; 
} 

這是我運行的PHP腳本:

<?php 
sample_with_types(); 

預期結果:PHP顯示錯誤/警告/異常,如「沒有足夠的參數傳遞給函數」;該功能不會執行。

實際結果:函數執行並返回true

如何正確配置函數參數結構,以便Zend引擎自動檢查參數的數量?或者我在ZEND_BEGIN_ARG_INFO_EX宏中誤將required_num_args參數的目的?

回答

8

據我所知,這不是什麼ZEND_BEGIN_ARG_INFO_EX是。

ZEND_BEGIN_ARG_INFO_EX是一個PHP 5添加用於生成更乾淨的代碼,啓用類型提示,傳遞引用和反射。考慮以下arginfo聲明爲您的實際功能,只是返回true:

ZEND_BEGIN_ARG_INFO_EX(arginfo_test, 0, 0, 3) 
    ZEND_ARG_INFO(0, firstArg) 
    ZEND_ARG_OBJ_INFO(0, objNonNull, stdClass, 0) 
    ZEND_ARG_OBJ_INFO(0, obj, stdClass, 1) 
    ZEND_ARG_OBJ_INFO(1, objByRef, stdClass, 1) 
ZEND_END_ARG_INFO() 

它具有以下作用:

sample_with_types();       // ok 
sample_with_types(1, null);     // error: arg #2 should be stdClass 
sample_with_types(1, new stdClass, null);  // ok 
sample_with_types(1, new stdClass, 1);  // error: arg #3 should be stdClass 
sample_with_types(1, new stdClass, null, 2); // error: arg #4 must be reference 

此外,它還提供反射功能,你的函數:

$ref = new ReflectionFunction('sample_with_types'); 
var_dump($ref->getParameters()); 

...給出類似於:

array(4) { 
    [0]=> 
    &object(ReflectionParameter)#2 (1) { 
    ["name"]=> 
    string(8) "firstArg" 
    } 
    [1]=> 
    &object(ReflectionParameter)#3 (1) { 
    ["name"]=> 
    string(10) "objNonNull" 
    } 
    [2]=> 
    &object(ReflectionParameter)#4 (1) { 
    ["name"]=> 
    string(3) "obj" 
    } 
    [3]=> 
    &object(ReflectionParameter)#5 (1) { 
    ["name"]=> 
    string(8) "objByRef" 
    } 
} 

如果您省略了arginfo,ReflectionFunction::getParameters()會返回一個空數組。

required_num_args宏參數專門用於反射,表示反映該函數時需要標記多少個參數。

如果您需要進行要求,而不是爭論只是將其標記爲需要使用反射時,你還是要用zend_parse_parameters,在大多數情況下,你仍然需要得到的參數的實際值:

PHP_FUNCTION(sample_with_types) 
{ 
    long arg1; 
    zval *arg2 = NULL, *arg3 = NULL, *arg4 = NULL; 
    zend_class_entry ce2, ce3, ce4; 

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "looo", &arg1, 
           &arg2, &ce2, &arg3, &ce3, &arg4, &ce4) == FAILURE) 
    { 
     return; 
    } 

    RETURN_TRUE; 
} 

請注意我如何在上面使用"looo"(通用對象類型)而不是"lOO!O!"(具有空指定符的特定對象類型)。類型提示已經用arginfo指定,所以不需要執行兩次。

所以,沒有arginfo:

  • 你不得不使用的zend_fetch_class調用和類條目少數鍵入提示您的對象參數。
  • 它不會啓用反射。
  • 您將無法聲明通過引用傳遞的參數。
  • 它顯然會產生較少乾淨的代碼。

由於顯而易見的原因,您需要確保您的arginfo聲明和您的zend_parse_parameters調用匹配。

+0

感謝@netcoder的信息和努力,澄清該宏的目的。它非常有意義,事實上我在問這個問題之前已經發現了它。然而,主要的是,這引起了我的困惑,並讓我走向SO,它是'required_num_args'參數。它看起來像args num的自動驗證,但實際上它什麼都不做。難道是,你知道它的目的? –

+0

@AndreyTserkus:'required_num_args'用於反射並表示何時根據需要停止計數參數(即:調用'isOptional()'時)。除此之外,它沒有任何效果。 (我用這個信息更新了答案。) – netcoder

+0

太棒了,謝謝! –

相關問題