2013-01-31 1 views
5

私はCを使ってPHP拡張を開発しています。これまでは、PHPユーザー空間から拡張関数に渡された引数の適切な検証に取り組んでいます。ZEND_BEGIN_ARG_INFO_EXをPHP拡張モジュールに渡す引数の数を制御する方法は?

マクロZEND_BEGIN_ARG_INFO_EXを使用すると、関数の引数に関する情報をZend Engineに提供できます。 required_num_argsという名前のマクロの4番目のパラメータは、エンジンが引数の数を自動的に制御して、私からこの面倒を取り除きます。しかし、私はそれを動作させる方法を見つけることができませんでした。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 Engineが引数の数を自動的にチェックするように、関数の引数構造を正しく設定するにはどうすればよいですか?または、私はrequired_num_args引数の目的を間違ってZEND_BEGIN_ARG_INFO_EXマクロに入れていますか?

答えて

8

私が知る限り、これはZEND_BEGIN_ARG_INFO_EXが対象ではありません。

ZEND_BEGIN_ARG_INFO_EXは、より洗練されたコードを生成するために使用され、型ヒント、参照渡しおよびリフレクションを可能にします。ちょうどtrueを返すあなたの実際の機能については、以下のarginfo宣言を考えてみましょう:

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() 

それは次のような効果があります。

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

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 

また、それはあなたの関数への反射機能を提供します

...同様の出力を出す:

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!"(null指定子を持つ特定のオブジェクト型)を使用しなかったことに注意してください。タイプヒントは既にarginfoで指定されているので、2回行う必要はありません。

ので、arginfoなし:

  • あなたがオブジェクトの引数をヒント入力するzend_fetch_classコールとクラスエントリの一握りを使用する必要があると思います。
  • これは反射を有効にしません。
  • 参照渡しの引数を宣言することはできません。
  • 明らかに、きれいなコードを生成しません。

明白な理由から、arginfo宣言とzend_parse_parameters呼び出しが一致するようにしてください。

+0

このマクロの目的を明確にするための情報と努力については、@netcoderありがとうございます。それはかなり意味をなさない、そして実際に私は質問をする前にそれを発見した。しかし、私の困惑を引き起こし、私をSOにした主なものは、 'required_num_args'パラメータでした。 args numの自動検証のようですが、実際には何もしません。あなたはその目的を知っているでしょうか? –

+0

@AndreyTserkus: 'required_num_args'は、リフレクションに使用され、必要に応じて(' isOptional() 'を呼び出すとき)、パラメータのカウントをいつ停止するかを示します。それ以外の効果はありません。 (私もこの情報で答えを更新しました) – netcoder

+0

素晴らしい、ありがとう! –

関連する問題