ホームページ >バックエンド開発 >PHPチュートリアル >PHP 拡張機能と埋め込み -- PHP 拡張機能のパラメーター_PHP チュートリアル

PHP 拡張機能と埋め込み -- PHP 拡張機能のパラメーター_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 10:42:24994ブラウズ

これまでの記事では、関数は受け取るパラメーターと返す型の点で比較的単純ですが、実際にはより複雑になることがよくあります。この記事では主に、PHP 拡張機能の開発においてユーザー空間からパラメーターを受け取り、それに応じてこれらのパラメーターの型、数、その他の情報を確認する方法について説明します。


1. 自動型変換には zend_parse_parameters() を使用します

PHP 拡張機能では、入力パラメーターを取得する最も簡単な方法は、zend_parse_parameters() 関数を使用することです。

この関数の呼び出しの最初の引数は常に ZEND_NUM_ARGS() TSRMLS_CC です。この引数は入力引数の数を int として返します。
2 番目のパラメータは format パラメータで、Zend Engine がサポートするさまざまなタイプに対応する文字列タイプで構成されます。
次の図は、フォーマット パラメータの可能なタイプを示しています。
次のパラメータは、以前にリクエストされたタイプによって異なります。次の例に示すように、比較的単純な型の場合、このパラメーターは通常、参照されるプリミティブです。 ここでの
PHP_FUNCTION(sample_getlong)
{
    long foo;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                         "l", &foo) == FAILURE) {
        RETURN_NULL();
    }
    php_printf("The integer value of the parameter you "
             "passed is: %ld\n", foo);
    RETURN_TRUE;
}
は l であり、long 型であるため、それに対応して、事前に long 型の foo パラメータを宣言し、その値を参照渡しします。 以下に、C 言語のパラメータと型のより詳細な対応関係を示します。 b ------ zend_bool l ------- 長い d ------- ダブル s ------- char* 、 int r ------- zval* a ------ zval* o ------ zval* O ----- zval*、zend_class_entry* z ------ zval* Z ----- zval**
複合型の場合は、単純な zval* 型が使用されることに注意してください。これは、複合型を返すときに RETURN_* がない理由と同じです。 ZPP が行うことは、受信した zval* が正しいタイプであることを確認することです。必要に応じて、配列を stdClass オブジェクトに変換するなど、暗黙的な変換も実行します。
s 型の場合、これは非常に特殊で、1 つの char* 1 つの int です。これは主に、PHP の文字列の特殊な構造によるものです。
function sample_hello_world($name) {
    echo "Hello $name!\n";
}
C 言語では、zend_parse_parameters 関数が使用されます。 れーれー
複数のパラメータがある場合、zend_parse_parameters はこれらのパラメータを左から右に抽出します。 れーれーるーるー
タイプ識別子に加えて、パラメーターの処理方法を変更する 3 つのメタキャラクターがあります。 | : これが表示される場合、前のパラメータは必須で、次のパラメータはオプションであることを意味します。PHP 言語で null 変数を受け取った場合、それはカプセル化されずに C 言語で直接 NULL に変換されます。 IS_NULL型のzval
/: 渡された変数が他の変数と zval を共有しており、真の参照ではない場合、新しい zval の is_ref__gc = 0、refcount__gc = 1 を強制的に分離する必要があります。
オプションのパラメータ: PHP のパラメータにデフォルト値を指定できます: 現時点で
PHP_FUNCTION(sample_hello_world)
{
    char *name;
    int name_len;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
                        &name, &name_len) == FAILURE) {
        RETURN_NULL();
    }
    php_printf("Hello ");
    PHPWRITE(name, name_len);
    php_printf("!\n");
}
を呼び出す場合、2 番目のパラメータを指定する必要はありません。 れーれー
C の解釈にも同様の実装があります。 れーれー
オプションのパラメータは通常、指定されない限り値を持たないため、デフォルトのパラメータを指定することが重要です。ほとんどの場合、NULL/0 です



IS_NULL VS NULL: 各 zval 型は、最も単純な IS_NULL 型であっても、一定量のメモリ領域を占有します。また、それらの適用と解放にも時間がかかります。したがって、多くの場合、このタイプを使用する必要はありません。次の 2 つのコードで比較が行われます。

りー

強制分離:

変数が関数に渡されるとき、参照によって渡されるかどうかに関係なく、refcount は常に少なくとも 2 になります。1 つはそれ自体であり、もう 1 つは関数に渡されるコピーです。この zval を変更する前に、参照されていないコレクションからそれを分離する必要があります。

/ を使用すると、コピーオンライトで参照される変数 (つまり、誤った参照) が自動的に分離されるため、非常に便利です。

この機能は NULL フラグと同じであり、必要な場合にのみ使用されます。



zend_get_parameters():

古いバージョンの PHP と互換性を持たせたい場合、またはパラメータを受信するためのキャリアとして zval を使用したいだけの場合は、zend_get_parameters() 関数を使用してパラメータを受信することを検討できます zend_parse_parameters() と比較すると、解析せずに直接取得されます。型変換は自動的には実行されません。拡張実装のすべてのパラメーターのキャリアは zval です。

リーリー
同時に、受信が失敗してもエラーをスローしません。また、デフォルト値を持つパラメーターを処理することもできません。解析との最後の違いは、コピーオンライトに準拠するすべての zval を自動的に強制的に分離することです。それをコピーして関数内に送信します。

この関数が必要ない場合は、zend_get_parameters_ex() を使用できます。そのパラメータは zval**

です。

りー


変数パラメータ、任意の数のパラメータを処理します:


2 つの zend_get_parameters_** 関数もあります。これらは、パラメーターが多数ある場合、またはパラメーターの数が事前にわからない状況を解決するために特別に使用されます。 PHP 言語の var_dump() 関数は、任意の数のパラメーターを入力できます。

ZEND_FUNCTION(var_dump) {
    int i, argc = ZEND_NUM_ARGS();
    zval ***args;
 
    args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    if (ZEND_NUM_ARGS() == 0 || zend_get_parameters_array_ex(argc, args) == FAILURE) {
        efree(args);
        WRONG_PARAM_COUNT;
    }
    for (i=0; i<br>
程序首先获取参数数量,然后通过safe_emalloc函数申请相应大小的内存来存储这些zval**的参数。这里使用zend_get_parameters_array_ex()函数来把传递给函数的参数填充到args中。提醒一下,还存在一个zend_get_parameters_array()函数,唯一不同是它将zval*类型的参数填充到args中,并且需要ZEND_NUM_ARGS()作为参数。<br>
</p>
<p><br>
</p>
<p><br>
</p>
<p><strong>2. Arg info参数和类型的绑定</strong></p>
<p>这个arg info结构是ZE2才有的。每一个arg info声明都由一个ZEND_BEGIN_ARG_INFO()或ZEND_BEGIN_ARG_INFO_EX()宏组成,后面跟着0个或多个ZEND_ARG_*INFO(), 然后最后以ZEND_END_ARG_INFO()作为结尾。<br>
假定要重写count()函数:<br>
</p>
<p><pre class="code">PHP_FUNCTION(sample_count_array)
{
    zval *arr;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a",
                                    &arr) == FAILURE) {
        RETURN_NULL();
    }
    RETURN_LONG(zend_hash_num_elements(Z_ARRVAL_P(arr)));
}

zend_parse_parameters()会确保输入到你函数中的参数是一个数组。但是如果你需要用zend_get_parameter()的话,那么就需要自己在函数内部内建类型检查。除非使用类型绑定:

ZEND_BEGIN_ARG_INFO(php_sample_array_arginfo, 0)
         ZEND_ARG_ARRAY_INFO(0, "arr", 0)
     ZEND_END_ARG_INFO()
。。。     PHP_FE(sample_count_array, php_sample_array_arginfo)  。。。

通过这种方式,zend engine就会帮你进行类型检查了。同时还给了参数一个名字,从而使得产生的错误信息更加具有可读性。

而对于对象来说,也可以通过arg info进行限定:

ZEND_BEGIN_ARG_INFO(php_sample_class_arginfo, 0)
         ZEND_ARG_OBJECT_INFO(1, "obj", "stdClass", 0)
     ZEND_END_ARG_INFO()

这里第一个参数被设为1,表示是引用方式传递,但是对象其实在ZE2中都是引用传递的。不要忘记了array和object的allow_null选项。
如果使用的是php4的话,只能用PHP_TYPE_P()进行检查,或使用convert_to_type()方法进行类型转换。









www.bkjia.comtruehttp://www.bkjia.com/PHPjc/635059.htmlTechArticle之前的文章中,函数在接收的参数和返回的类型上都比较简单,但是往往实际中所遇到的都更加复杂一些。这篇文章主要说一下如何在php扩...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。