目次
PHP拡張開発の関連まとめ、PHP拡張の概要
1. スレッドセーフなマクロ定義
2. PHP のライフサイクル
例: PHP_GINIT_FUNCTION
これはコードの一部です。テストできます
3. セグメンテーション障害のデバッグ
6、常量的实例化
7、全局变量
8、包装第三方库
9、用于返回的宏
10、hashTable的遍历函数
ホームページ バックエンド開発 PHPチュートリアル PHP 拡張機能開発の概要、PHP 拡張機能の概要_PHP チュートリアル

PHP 拡張機能開発の概要、PHP 拡張機能の概要_PHP チュートリアル

Jul 12, 2016 am 09:05 AM
PHP言語

PHP拡張開発の関連まとめ、PHP拡張の概要

1. スレッドセーフなマクロ定義

TSRM/TSRM.hファイルには以下の定義があります

リーリー

ext/xsl/php_xsl.hにこんな箇所があります

リーリー

1. メソッドを定義するときに TSRMLS_D (メソッドにパラメーターがない場合に使用します) または TSRMLS_DC (複数のパラメーターがある場合) を追加します。
2. TSRMLS_C (メソッドにパラメーターがない場合にこれを使用します) または TSRMLS_CC (パラメーターが 1 つある場合) を追加します。パラメータ以上のメソッドを呼び出すとき)

このように理解すべきです

最初の接尾辞文字 D は定義を意味します (つまり D=Define)、最初の接尾辞文字 C は呼び出しを意味します (つまり C=Call)、そして 2 番目の接尾辞文字 C はコンマを意味しますか? C=カンマ(カンマ)

リーリー

つまり、1 つは仮パラメータで、もう 1 つは実際のパラメータです

こんな使い方もできます

リーリー

スレッドの安全性を確保するには、一般に tsrm_ls ポインター定義メソッドを使用することをお勧めします

TSRMLS_FETCH 呼び出しには一定の処理時間が必要です。これは 1 回の反復では目立ちませんが、スレッド数が増加し、TSRMLS_FETCH() を呼び出すポイントが増加すると、スケーリングによってこのボトルネックが明らかになります。したがって、慎重に使用してください。 注: C++ コンパイラとの互換性を確保するために、TSRMLS_FETCH() とすべての変数定義を指定されたブロック スコープの先頭 (他のステートメントの前) に配置してください。 TSRMLS_FETCH() マクロ自体はさまざまな方法で解析できるため、変数定義の最後の行として使用するのが最善です

2. PHP のライフサイクル

PHP の最も一般的な 2 つの動作モードは WEB モードと CLI モードです。どちらのモードであっても、PHP は同じ原理で動作し、SAPI として実行されます。

1. ターミナルに php コマンドを入力すると、CLI が使用されます。
リクエストを完了するためにphpをサポートするWebサーバーのようなものです。リクエストが完了すると、制御がターミナルに戻ります。
2. Apacheをホストとして使用する場合、リクエストが来たとき、PHPはリクエストの完了をサポートします

リーリー

例: PHP_GINIT_FUNCTION

リーリー

これはコードの一部です。テストできます

リーリー

3. セグメンテーション障害のデバッグ

Linux 上の C プログラムでは、メモリ アクセス エラーなどの理由でセグメント フォールトが発生することがよくあります。このとき、システム コア ダンプ機能がオンになっていると、その後、gdb を使用してメモリ イメージがハードディスクにダンプされます。 core ファイルを解析し、システムセグメンテーション障害発生時のスタック状況を復元します。これはプログラムのバグを見つけるのに非常に役立ちます。
システム コア ファイルのサイズ制限を表示するには、ulimit -a を使用します。システムが生成できるコア ファイルのサイズを設定するには、ulimit -c [kbytes] を使用します。

ulimit -c 0 はコア ファイルを生成しません
ulimit -c 100 は最大コア ファイルを 100k に設定します
ulimit -c unlimited はコア ファイル サイズを制限しません

手順:

1. セグメンテーション違反が発生した場合、ulimit -a (core file size (blocks, -c) 0) をチェックしますが、ファイルはありません。
2. 設定: ulimit -c unlimited はコア ファイル サイズを制限しません。プログラムを実行します。セグメンテーション違反が発生すると、コアに自動的に記録されます (php -f WorkWithArray.php)
4. そのファイル (-rw------1) leconte leconte 139264 01-06 22: 3 1 core.2065)
5. gdb を使用してプログラムを実行し、セグメンテーション違反のあるファイルを記録します。 (gdb ./test core.2065)
6. どの行が間違っているかを説明します。


多くのシステムのデフォルトのコア ファイル サイズは 0 です。シェル起動スクリプト /etc/bashrc または ~/.bashrc に ulimit -c コマンドを追加することで、コア ファイル サイズを指定できます。生成することが可能です。
さらに、/proc/sys/kernel/core_pattern にコアファイルのファイル名テンプレートを設定することもできます。詳細については、コアの公式マニュアルを参照してください。

4. 共通変数操作マクロ

リーリー

1. SG は、main/SAPI.h ファイル内の SAPI 情報です

リーリー

SGの定義を見てください

リーリー

メンバー全員が sapi_globals_struct にいます

じゃあ、こう呼んでいいですか

リーリー

このコードを感じてください

リーリー

2. EG Executor Globals

EGは

構造struct _zend_execution_globals内のデータを取得します リーリー

通常、

を使用して現在のスコープ内のシンボルテーブルを取得しますEG(symbol_table)获取的是全局作用域中的符号表,使用EG(active_symbol_table)

たとえば、$foo = 'bar' を定義するには

リーリー

またはシンボルテーブルから $foo を検索します

リーリー

上記のコードでは、

EG(active_symbol_table) == &EG(symbol_table)

3. CG() は、コアのグローバル変数にアクセスするために使用されます。 (zend/zend_globals_macros.h)

4. PG() PHP グローバル変数。 php.ini が 1 つ以上の PHP グローバル構造をマップすることがわかっています。 (main/php_globals.h)

5. FG() ファイルのグローバル変数。ファイル I/O または関連するグローバル変数のほとんどのデータ ストリームは、標準の拡張出口構造にプラグインされます。 (ext/standard/file.h)

5. 変数の型と値を取得します

リーリー

たとえば、変数の型を取得する

リーリー

いくつか種類があります

#define IS_NULL     0
#define IS_LONG     1
#define IS_DOUBLE   2
#define IS_BOOL     3
#define IS_ARRAY    4
#define IS_OBJECT   5
#define IS_STRING   6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY   9
#define IS_CALLABLE 10
ログイン後にコピー

php_printf()函数是内核对printf()函数的一层封装,我们可以像使用printf()函数那样使用它,以一个P结尾的宏的参数大多是*zval型变量。 此外获取变量类型的宏还有两个,分别是Z_TYPE和Z_TYPE_PP,前者的参数是zval型,而后者的参数则是**zval

比如gettype函数的实现

//开始定义php语言中的函数gettype
PHP_FUNCTION(gettype)
{
    //arg间接指向调用gettype函数时所传递的参数。是一个zval**结构
    //所以我们要对他使用__PP后缀的宏。
    zval **arg;

    //这个if的操作主要是让arg指向参数~
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
        return;
    }

    //调用Z_TYPE_PP宏来获取arg指向zval的类型。
    //然后是一个switch结构,RETVAL_STRING宏代表这gettype函数返回的字符串类型的值
    switch (Z_TYPE_PP(arg)) {
        case IS_NULL:
            RETVAL_STRING("NULL", 1);
            break;

        case IS_BOOL:
            RETVAL_STRING("boolean", 1);
            break;

        case IS_LONG:
            RETVAL_STRING("integer", 1);
            break;

        case IS_DOUBLE:
            RETVAL_STRING("double", 1);
            break;

        case IS_STRING:
            RETVAL_STRING("string", 1);
            break;

        case IS_ARRAY:
            RETVAL_STRING("array", 1);
            break;

        case IS_OBJECT:
            RETVAL_STRING("object", 1);
            break;

        case IS_RESOURCE:
            {
                char *type_name;
                type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(arg) TSRMLS_CC);
                if (type_name) {
                    RETVAL_STRING("resource", 1);
                    break;
                }
            }

        default:
            RETVAL_STRING("unknown type", 1);
    }
}   
ログイン後にコピー

获取变量的值,有这么多宏来获取

Long

Boolean

Double

String value

String length

<pre class="code">Z_LVAL( )
ログイン後にコピー
<pre class="code">Z_BVAL( )
ログイン後にコピー
<pre class="code">Z_DVAL( )
ログイン後にコピー
<pre class="code">Z_STRVAL( )
ログイン後にコピー
<pre class="code">Z_STRLEN( )
ログイン後にコピー
<pre class="code">Z_LVAL_P( )
ログイン後にコピー
<pre class="code">Z_BVAL_P( )
ログイン後にコピー
<pre class="code">Z_DVAL_P( )
ログイン後にコピー
<pre class="code">Z_STRVAL_P( )
ログイン後にコピー
<pre class="code">Z_STRLEN_P( )
ログイン後にコピー
<pre class="code">Z_LVAL_PP( )
ログイン後にコピー
<pre class="code">Z_BVAL_PP( )
ログイン後にコピー
<pre class="code">Z_DVAL_PP( )
ログイン後にコピー
<pre class="code">Z_STRVAL_PP( )
ログイン後にコピー
<pre class="code">Z_STRLEN_PP( )
ログイン後にコピー

HashTable

Object

Object properties

Object class entry

Resource value

<pre class="code">Z_ARRVAL( )
ログイン後にコピー
<pre class="code">Z_OBJ( )
ログイン後にコピー
<pre class="code">Z_OBJPROP( )
ログイン後にコピー
<pre class="code">Z_OBJCE( )
ログイン後にコピー
<pre class="code">Z_RESVAL( )
ログイン後にコピー
<pre class="code">Z_ARRVAL_P( )
ログイン後にコピー
<pre class="code">Z_OBJ_P( )
ログイン後にコピー
<pre class="code">Z_OBJPROP_P( )
ログイン後にコピー
<pre class="code">Z_OBJCE_P( )
ログイン後にコピー
<pre class="code">Z_RESVAL_P( )
ログイン後にコピー
<pre class="code">Z_ARRVAL_PP( )
ログイン後にコピー
<pre class="code">Z_OBJ_PP( )
ログイン後にコピー
<pre class="code">Z_OBJPROP_PP( )
ログイン後にコピー
<pre class="code">Z_OBJCE_PP( )
ログイン後にコピー
<pre class="code">Z_RESVAL_PP( )
ログイン後にコピー

rot13函数的实现

PHP_FUNCTION(rot13)
{
  zval **arg;
  char *ch, cap;
  int i;
  
  if (ZEND_NUM_ARGS( ) != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
      WRONG_PARAM_COUNT;
  }
  *return_value = **arg;
  zval_copy_ctor(return_value);
  convert_to_string(return_value);
  
  for(i=0, ch=return_value->value.str.val;
      i<return_value->value.str.len; i++, ch++) {
        cap = *ch & 32;
        *ch &= ~cap;
        *ch = ((*ch>='A') && (*ch<='Z') ? ((*ch-'A'+13) % 26 + 'A') : *ch) | cap;
    }
}
ログイン後にコピー

要获取变量的值,也应该使用Zend定义的宏进行访问。对于简单的标量数据类型、Boolean,long,double, 使用Z_BVAL, Z_LVAL, Z_DVAL

void display_values(zval boolzv, zval *longpzv, zval **doubleppzv)
{
  if (Z_TYPE(boolzv) == IS_BOOL) {
    php_printf("The value of the boolean is : %s\n", Z_BVAL(boolzv) ? "true" : "false");
  }
  if(Z_TYPE_P(longpzv) == IS_LONG) {
    php_printf("The value of the long is: %ld\n", Z_LVAL_P(longpzv));
  }
  if(Z_TYPE_PP(doubleppzv) == IS_DOUBLE) {
    php_printf("The value of the double is : %f\n", Z_DVAL_PP(doubleppzv));
  }
}
ログイン後にコピー

对于字符串类型,因为它含有两个字段char * (Z_STRVAL) 和 int (Z_STRLEN),因此需要用两个宏来进行取值,因为需要二进制安全的输出这个字符串

void display_string(zval *zstr)
{
  if (Z_TYPE_P(zstr) != IS_STRING) {
    php_printf("The wronng datatype was passed!\n");
    return ;
  }
  PHPWRITE(Z_STRVAL_P(zstr), Z_STRLEN_P(zstr));
}
ログイン後にコピー

因为数组在zval中是以HashTable形式存在的,因此使用Z_ARRVAL()进行访问

void display_zval(zval *value)
{
    switch (Z_TYPE_P(value)) {
        case IS_NULL:
            /* 如果是NULL,则不输出任何东西 */
            break;

        case IS_BOOL:
            /* 如果是bool类型,并且true,则输出1,否则什么也不干 */
            if (Z_BVAL_P(value)) {
                php_printf("1");
            }
            break;
        case IS_LONG:
            /* 如果是long整型,则输出数字形式 */
            php_printf("%ld", Z_LVAL_P(value));
            break;
        case IS_DOUBLE:
            /* 如果是double型,则输出浮点数 */
            php_printf("%f", Z_DVAL_P(value));
            break;
        case IS_STRING:
            /* 如果是string型,则二进制安全的输出这个字符串 */
            PHPWRITE(Z_STRVAL_P(value), Z_STRLEN_P(value));
            break;
        case IS_RESOURCE:
            /* 如果是资源,则输出Resource #10 格式的东东 */
            php_printf("Resource #%ld", Z_RESVAL_P(value));
            break;
        case IS_ARRAY:
            /* 如果是Array,则输出Array5个字母! */
            php_printf("Array");
            break;
        case IS_OBJECT:
            php_printf("Object");
            break;
        default:
            /* Should never happen in practice,
             * but it's dangerous to make assumptions
             */
             php_printf("Unknown");
             break;
    }
}    
ログイン後にコピー

一些类型转换函数

ZEND_API void convert_to_long(zval *op);
ZEND_API void convert_to_double(zval *op);
ZEND_API void convert_to_null(zval *op);
ZEND_API void convert_to_boolean(zval *op);
ZEND_API void convert_to_array(zval *op);
ZEND_API void convert_to_object(zval *op);
ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC);
ログイン後にコピー

6、常量的实例化

我们可以这样实例化

PHP_MINIT_FUNCTION(consts) //模块初始化时定义常量
{
    REGISTER_LONG_CONSTANT("CONSTS_MEANING_OF_LIFE", 42, CONST_CS | CONST_PERSISTENT);
    REGISTER_DOUBLE_CONSTANT("CONSTS_PI", 3.1415926, CONST_PERSISTENT);
    REGISTER_STRING_CONSTANT("CONSTS_NAME", "leon", CONST_CS|CONST_PERSISTENT);
}

PHP_RINIT_FUNCTION(consts) //每次请求时定义常量
{
    char buffer[40];
    srand((int)time(NULL));
    snprintf(buffer, sizeof(buffer), "%d", rand());
    REGISTER_STRING_CONSTANT("CONSTS_RAND", estrdup(buffer), CONST_CS);
    return SUCCESS;
}
ログイン後にコピー

常见的宏

/*注册LONG类型常量*/
#define REGISTER_LONG_CONSTANT(name, lval, flags)  zend_register_long_constant((name), sizeof(name), (lval), (flags), module_number TSRMLS_CC)

/*注册double类型常量*/
#define REGISTER_DOUBLE_CONSTANT(name, dval, flags)  zend_register_double_constant((name), sizeof(name), (dval), (flags), module_number TSRMLS_CC)

/*注册STRING类型常量*/
#define REGISTER_STRING_CONSTANT(name, str, flags)  zend_register_string_constant((name), sizeof(name), (str), (flags), module_number TSRMLS_CC)

/*注册STRING类型常量*/
#define REGISTER_STRINGL_CONSTANT(name, str, len, flags)  zend_register_stringl_constant((name), sizeof(name), (str), (len), (flags), module_number TSRMLS_CC)
ログイン後にコピー

7、全局变量

#php-fpm 生成 POST|GET|COOKIE|SERVER|ENV|REQUEST|FILES全局变量的流程
php_cgi_startup() -> php_module_startup() -> php_startup_auto_globals() -> 保存变量到symbol_table符号表

php_cgi_startup()在 fpm/fpm/fpm_main.c中定义
php_module_startup() 在main/main.c中定义
php_startup_auto_globals() 在main/php_variables.h中定义
zend_hash_update(&EG(symbol_table), "_GET", sizeof("_GET") + 1, &vars, sizeof(zval *), NULL);

/* 读取$_SERVER变量 */
static PHP_FUNCTION(print_server_vars) {
    zval **val;
    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {
        RETURN_ZVAL(*val, 1, 0);
    }else{
     RETURN_FALSE;
    }
}


/* 读取$_SERVER[$name] */

ZEND_BEGIN_ARG_INFO(print_server_var_arginfo, 0)
    ZEND_ARG_INFO(0, "name")
ZEND_END_ARG_INFO()

static PHP_FUNCTION(print_server_var) {
    char *name;
    int name_len;
    zval **val;
    HashTable *ht_vars = NULL;
    HashPosition pos;
    zval **ret_val;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &name_len) == FAILURE) {
        RETURN_NULL();
    }

    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {
        ht_vars = Z_ARRVAL_PP(val);

        //此处需传入大于name长度+1的值,因为字符串值后面需要'\0'

        if (zend_hash_find(ht_vars, name, name_len+1, (void **)&ret_val) == SUCCESS) {              RETURN_STRING(Z_STRVAL_PP(ret_val), 0);
        }else{
            RETURN_NULL();
        }
    }else{
        RETURN_NULL();
    }
}
ログイン後にコピー

8、包装第三方库

配置(config.m4)

SEARCH_PATH="/usr/local /usr"     #lib搜索的目录
SEARCH_FOR="/include/curl/curl.h"  #lib头文件的路径
if test -r $PHP_LIBS/$SEARCH_FOR; then 
    LIBS_DIR=$PHP_LIBS
else # search default path list
    AC_MSG_CHECKING([for libs files in default path])
    for i in $SEARCH_PATH ; do
        if test -r $i/$SEARCH_FOR; then
            LIBS_DIR=$i                #搜索到的lib的路径
            AC_MSG_RESULT(found in $i)
        fi
    done
fi

/*验证lib是否存在*/
if test -z "$LIBS_DIR"; then
    AC_MSG_RESULT([not found])
    AC_MSG_ERROR([Please reinstall the libs distribution])
fi


/*编译的时候添加lib的include目录,  -I/usr/include*/
PHP_ADD_INCLUDE($LIBS_DIR/include) 

LIBNAME=curl            #lib名称  
LIBSYMBOL=curl_version  #lib的一个函数,用来PHP_CHECK_LIBRARY验证lib

/*验证lib*/
PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,  
[
    PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $LIBS_DIR/$PHP_LIBDIR, LIBS_SHARED_LIBADD) #编译的时候链接lib, -llibcurl
    AC_DEFINE(HAVE_LIBSLIB,1,[ ])
],[
    AC_MSG_ERROR([wrong libs lib version or lib not found])
],[
    -L$LIBS_DIR/$PHP_LIBDIR -lm
])  


PHP_SUBST(LIBS_SHARED_LIBADD)
ログイン後にコピー

9、用于返回的宏

//这些宏都定义在Zend/zend_API.h文件里
#define RETVAL_RESOURCE(l)              ZVAL_RESOURCE(return_value, l)
#define RETVAL_BOOL(b)                  ZVAL_BOOL(return_value, b)
#define RETVAL_NULL()                   ZVAL_NULL(return_value)
#define RETVAL_LONG(l)                  ZVAL_LONG(return_value, l)
#define RETVAL_DOUBLE(d)                ZVAL_DOUBLE(return_value, d)
#define RETVAL_STRING(s, duplicate)         ZVAL_STRING(return_value, s, duplicate)
#define RETVAL_STRINGL(s, l, duplicate)     ZVAL_STRINGL(return_value, s, l, duplicate)
#define RETVAL_EMPTY_STRING()           ZVAL_EMPTY_STRING(return_value)
#define RETVAL_ZVAL(zv, copy, dtor)     ZVAL_ZVAL(return_value, zv, copy, dtor)
#define RETVAL_FALSE                    ZVAL_BOOL(return_value, 0)
#define RETVAL_TRUE                     ZVAL_BOOL(return_value, 1)

#define RETURN_RESOURCE(l)              { RETVAL_RESOURCE(l); return; }
#define RETURN_BOOL(b)                  { RETVAL_BOOL(b); return; }
#define RETURN_NULL()                   { RETVAL_NULL(); return;}
#define RETURN_LONG(l)                  { RETVAL_LONG(l); return; }
#define RETURN_DOUBLE(d)                { RETVAL_DOUBLE(d); return; }
#define RETURN_STRING(s, duplicate)     { RETVAL_STRING(s, duplicate); return; }
#define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; }
#define RETURN_EMPTY_STRING()           { RETVAL_EMPTY_STRING(); return; }
#define RETURN_ZVAL(zv, copy, dtor)     { RETVAL_ZVAL(zv, copy, dtor); return; }
#define RETURN_FALSE                    { RETVAL_FALSE; return; }
#define RETURN_TRUE                     { RETVAL_TRUE; return; }
ログイン後にコピー

其实,除了这些标量类型,还有很多php语言中的复合类型我们需要在函数中返回,如数组和对象,我们可以通过RETVAL_ZVAL与RETURN_ZVAL来操作它们

10、hashTable的遍历函数

//基于long key的操作函数

zval *v3;
MAKE_STD_ZVAL(v3);
ZVAL_STRING(v3, "value3", 1);
zend_hash_index_update(names, 0, &v3, sizeof(zval *), NULL);//按数字索引键更新HashTable元素的值

zval **v4;
zend_hash_index_find(names, 1, &v4); //按数字索引获取HashTable元素的值
php_printf("v4 : ");
PHPWRITE(Z_STRVAL_PP(v4), Z_STRLEN_PP(v4));
php_printf("\n");

ulong idx;
idx = zend_hash_index_exists(names, 10);//按数字索引查找HashTable,如果找到返回 1, 反之则返回 0

zend_hash_index_del(names, 2);    //按数字索引删除HashTable元素


//hashTable的遍历函数

zend_hash_internal_pointer_reset(names); //初始化hash指针
zend_hash_internal_pointer_reset_ex(names, &pos);//初始化hash指针,并付值给pos

zend_hash_get_current_data(names, (void**) &val); //获取当前hash存储值,data should be cast to void**, ie: (void**) &data
zend_hash_get_current_data_ex(names, (void**) &val, &pos) == SUCCESS; //获取当前hash存储值

zend_hash_get_current_key(names, &key, &klen, &index, 0) == HASH_KEY_IS_LONG
zend_hash_get_current_key_ex(names, &key, &klen, &index, 0, &pos) == HASH_KEY_IS_LONG; //读取hashtable当前的KEY,返回值会有两种 HASH_KEY_IS_LONG | HASH_KEY_IS_STRING ,分别对应array("value"),array("key"=>"value")两种hashtable

zend_hash_move_forward(names); 
zend_hash_move_forward_ex(names, &pos); //hash指针移至下一位

//HashTable长度
php_printf("%*carray(%d) {\n", depth * 2, ' ', zend_hash_num_elements(Z_ARRVAL_P(zv))
ログイン後にコピー

一个简单的函数

function hello_array_strings($arr) {
    if (!is_array($arr)) return NULL;
    printf("The array passed contains %d elements ", count($arr));

    foreach($arr as $data) {
        if (is_string($data)) echo "$data ";
    }
}
ログイン後にコピー

PHP内核实现

PHP_FUNCTION(hello_array_strings)
{
    zval *arr, **data;
    HashTable *arr_hash;
    HashPosition pointer;
    int array_count;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) {
        RETURN_NULL();
    }

    arr_hash = Z_ARRVAL_P(arr);
    array_count = zend_hash_num_elements(arr_hash);
    php_printf("The array passed contains %d elements ", array_count);

    for(zend_hash_internal_pointer_reset_ex(arr_hash, &pointer); zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS; zend_hash_move_forward_ex(arr_hash, &pointer)) {
        if (Z_TYPE_PP(data) == IS_STRING) {

            PHPWRITE(Z_STRVAL_PP(data), Z_STRLEN_PP(data));

            php_printf(" ");

        }
    }

    RETURN_TRUE;
}
ログイン後にコピー

 

参考文章 

http://php.find-info.ru/php/016/ch23lev1sec1.html

http://docstore.mik.ua/orelly/webprog/php/ch14_10.htm

http://wiki.jikexueyuan.com/project/extending-embedding-php/2.4.html

http://www.php-internals.com/book/?p=chapt02/02-03-02-opcode

http://blog.csdn.net/phpkernel/article/details/5721134

https://github.com/chenpingzhao/php-ext-trie-filter/blob/master/trie_filter.c

http://aicode.cc/tags/php%E6%89%A9%E5%B1%95/

http://www.phpboy.net/2013-12/28-php-stream-wrapper.html

http://thiniki.sinaapp.com/?p=163

http://top.jobbole.com/26400/

https://github.com/walu/phpbook/blob/master/9.1.md

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1067638.htmlTechArticlePHP扩展开发相关总结,php扩展总结 1、线程安全宏定义 在TSRM/TSRM.h文件中有如下定义 #define TSRMLS_FETCH() void ***tsrm_ls = (void ***) ts_resource_ex(0,...
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PHP言語開発におけるリクエストヘッダーエラーにどう対処するか? PHP言語開発におけるリクエストヘッダーエラーにどう対処するか? Jun 10, 2023 pm 05:24 PM

PHP 言語開発では、リクエスト ヘッダー エラーは通常、HTTP リクエスト内の何らかの問題によって発生します。これらの問題には、無効なリクエスト ヘッダー、リクエスト本文の欠落、認識されないエンコード形式などが含まれる場合があります。これらのリクエスト ヘッダー エラーを正しく処理することが、アプリケーションの安定性とセキュリティを確保する鍵となります。この記事では、より信頼性が高く安全なアプリケーションを構築するために役立つ、PHP リクエスト ヘッダー エラーを処理するためのいくつかのベスト プラクティスについて説明します。リクエスト メソッドの確認 HTTP プロトコルは、利用可能なリクエスト メソッドのセット (GET、POS など) を指定します。

PHP の Ctype 拡張機能を使用するにはどうすればよいですか? PHP の Ctype 拡張機能を使用するにはどうすればよいですか? Jun 03, 2023 pm 10:40 PM

PHP は、開発者がさまざまなアプリケーションを作成できるようにする非常に人気のあるプログラミング言語です。ただし、PHP コードを作成するときに、文字の処理と検証が必要になる場合があります。ここで、PHP の Ctype 拡張機能が役に立ちます。この記事では、PHPのCtype拡張機能の使い方を紹介します。 Ctype 拡張機能とは何ですか? PHP の Ctype 拡張機能は、文字列内の文字タイプを検証するためのさまざまな関数を提供する非常に便利なツールです。これらの関数には isalnum、is が含まれます。

PHP プログラミングで Behat を使用するにはどうすればよいですか? PHP プログラミングで Behat を使用するにはどうすればよいですか? Jun 12, 2023 am 08:39 AM

PHP プログラミングにおいて、Behat は、プログラマーが開発プロセス中にビジネス要件をよりよく理解し、コードの品質を保証するのに役立つ非常に便利なツールです。この記事では、PHP プログラミングで Behat を使用する方法を紹介します。 1. ベハトとは何ですか? Behat は、言語記述 (Gherkin 言語で記述されたユースケース) を通じて PHP コードを結合する動作駆動開発 (BDD) フレームワークであり、それによってコードとビジネス要件が連携できるようにします。 Behatを使用して行うこと

PHP 言語開発におけるパス トラバーサルの脆弱性セキュリティ問題を回避する方法 PHP 言語開発におけるパス トラバーサルの脆弱性セキュリティ問題を回避する方法 Jun 10, 2023 am 09:43 AM

インターネット技術の発展に伴い、PHP 言語を使用して開発される Web サイトやアプリケーションがますます増えています。ただし、セキュリティの問題も発生します。一般的なセキュリティ問題の 1 つは、パス トラバーサルの脆弱性です。この記事では、PHP 言語開発におけるパス トラバーサルの脆弱性を回避してアプリケーションのセキュリティを確保する方法を検討します。パストラバーサルの脆弱性とは何ですか?パス トラバーサルの脆弱性 (PathTraversal) は、攻撃者が許可なく Web サーバーにアクセスできるようにする一般的な Web の脆弱性です。

PHP での単体テストに Phpt を使用する方法 PHP での単体テストに Phpt を使用する方法 Jun 27, 2023 am 08:35 AM

最新の開発では、単体テストが必要なステップになっています。これを使用すると、コードが期待どおりに動作し、いつでもバグを修正できることを確認できます。 PHP 開発では、Phppt は非常に人気のある単体テスト ツールであり、単体テストの作成と実行に非常に便利です。この記事では、Phpt を単体テストに使用する方法を説明します。 1. Phpt とは Phpt は、PHP テストの一部である、シンプルだが強力な単体テスト ツールです。 Phpt テスト ケースは、一連の PHP ソース コード スニペットです。

PHP 言語はいくつかのコメント スタイルをサポートしています PHP 言語はいくつかのコメント スタイルをサポートしています Feb 15, 2022 pm 02:05 PM

PHP 言語は 3 つのコメント スタイルをサポートしています: 1. C++ スタイル、「//」記号と構文「//コメント コンテンツ」を使用; 2. C 言語スタイル、「/* */」記号と構文「/*」を使用comment content*" /"; 3. シェル スタイル (Perl スタイル)、「#」記号と構文「#comment content」を使用します。

PHP 言語開発で JSON を解析する際の一般的なエラーと解決策 PHP 言語開発で JSON を解析する際の一般的なエラーと解決策 Jun 10, 2023 pm 12:00 PM

PHP 言語開発では、後続のデータ処理や操作のために JSON データを解析することが必要になることがよくあります。ただし、JSON を解析すると、さまざまなエラーや問題が発生しやすくなります。この記事では、PHP 開発者が JSON データをより適切に処理できるようにするための一般的なエラーと処理方法を紹介します。 1. JSON 形式エラー 最も一般的なエラーは、JSON 形式が間違っていることです。 JSON データは JSON 仕様に準拠している必要があります。つまり、データはキーと値のペアのコレクションであり、データを含めるには中括弧 ({}) と角括弧 ([]) を使用する必要があります。

PHP 言語開発における LDAP 関連の脆弱性を回避するにはどうすればよいですか? PHP 言語開発における LDAP 関連の脆弱性を回避するにはどうすればよいですか? Jun 10, 2023 pm 09:18 PM

LDAP (Lightweight Directory Access Protocol) は、ディレクトリ サービスへのアクセスと管理に使用される一般的なネットワーク プロトコルです。 PHP 言語開発では、ID 認証やユーザー認可などの外部 LDAP ディレクトリ サービスと対話するために LDAP がよく使用されます。ただし、LDAP の性質上、LDAP インジェクションや LDAP オーバーライドの問題など、セキュリティ上の脆弱性もいくつかあります。この記事では、PHP 言語開発における LDAP 関連の脆弱性を回避する方法について説明します。 LDAP インジェクションを回避する LDAP インジェクションは、次のような一般的なセキュリティ脆弱性です。

See all articles