php扩展分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php扩展分析相关的知识,希望对你有一定的参考价值。

<>调用堆栈
php_ext_test.dll!zif_confirm_test_compiled(int ht, _zval_struct * return_value, _zval_struct * * return_value_ptr, _zval_struct * this_ptr, int return_value_used) 行 60    C
php5.dll!zend_do_fcall_common_helper_SPEC(_zend_execute_data * execute_data) 行 558    C
php5.dll!execute_ex(_zend_execute_data * execute_data) 行 363    C
php5.dll!zend_execute(_zend_op_array * op_array) 行 388    C
php5.dll!zend_execute_scripts(int type, _zval_struct * * retval, int file_count, ...) 行 1341    C
php5.dll!php_execute_script(_zend_file_handle * primary_file) 行 2613    C
技术分享
 
技术分享
 
技术分享
 
<>
PHP_FUNCTION(confirm_test_compiled)
{
    char *arg = NULL;
    int arg_len, len;
    char *strg;
 
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
        return;
    }
 
    len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "test", arg);
    RETURN_STRINGL(strg, len, 0);
}
 
技术分享
技术分享
 
 
<>PHP_FUNCTION(confirm_test_compiled)
技术分享
 
技术分享
 
技术分享
 
zif_confirm_test_compiled
 
技术分享
 
 
void zif_confirm_test_compiled(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC)
 
技术分享
 
技术分享
 
 
 
技术分享
 
<>zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE
 
技术分享
 
zend_api.h

Boolean b zend_bool
Long l long
Double d double
String s char*, int
Resource r zval*
Array a zval*
Object o zval*
zval z zval*

类型指定符

对应的C类型

描述

l

long

符号整数

d

double

浮点数

s

char *, int

二进制字符串,长度

b

zend_bool

逻辑型(1或0)

r

zval *

资源(文件指针,数据库连接等)

a

zval *

联合数组

o

zval *

任何类型的对象

O

zval *

指定类型的对象。需要提供目标对象的类类型

z

zval *

无任何操作的zval 

RETURN_STRING
RETURN_LONG
RETURN_DOUBLE
RETURN_BOOL
RETURN_NULL
注意RETURN_STRING有两个参数
当你需要复制一份字符串时使用
RETURN_STRING("Hello World", 1);
否则使用
RETURN_STRING(str, 0);
技术分享
 
zend_api.c
技术分享
 
技术分享
 
 
static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, int flags TSRMLS_DC) /* {{{ */
{
    const  char *spec_walk;
    int c, i;
    int min_num_args = -1;
    int max_num_args = 0;
    int post_varargs = 0;
    zval **arg;
    int arg_count;
    int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
    zend_bool have_varargs = 0;
    zval ****varargs = NULL;
    int *n_varargs = NULL;
 
    for (spec_walk = type_spec; *spec_walk; spec_walk++) {
        c = *spec_walk;
        switch (c) {
            case ‘l‘: case ‘d‘:
            case ‘s‘: case ‘b‘:
            case ‘r‘: case ‘a‘:
            case ‘o‘: case ‘O‘:
            case ‘z‘: case ‘Z‘:
            case ‘C‘: case ‘h‘:
            case ‘f‘: case ‘A‘:
            case ‘H‘: case ‘p‘:
                max_num_args++;
                break;
 
            case ‘|‘:
                min_num_args = max_num_args;
                break;
 
            case ‘/‘:
            case ‘!‘:
                /* Pass */
                break;
 
            case ‘*‘:
            case ‘+‘:
                if (have_varargs) {
                    if (!quiet) {
                        zend_function *active_function = EG(current_execute_data)->function_state.function;
                        const char *class_name = active_function->common.scope ? active_function->common.scope->name : "";
                        zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted",
                                class_name,
                                class_name[0] ? "::" : "",
                                active_function->common.function_name);
                    }
                    return FAILURE;
                }
                have_varargs = 1;
                /* we expect at least one parameter in varargs */
                if (c == ‘+‘) {
                    max_num_args++;
                }
                /* mark the beginning of varargs */
                post_varargs = max_num_args;
                break;
 
            default:
                if (!quiet) {
                    zend_function *active_function = EG(current_execute_data)->function_state.function;
                    const char *class_name = active_function->common.scope ? active_function->common.scope->name : "";
                    zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters",
                            class_name,
                            class_name[0] ? "::" : "",
                            active_function->common.function_name);
                }
                return FAILURE;
        }
    }
 
    if (min_num_args < 0) {
        min_num_args = max_num_args;
    }
 
    if (have_varargs) {
        /* calculate how many required args are at the end of the specifier list */
        post_varargs = max_num_args - post_varargs;
        max_num_args = -1;
    }
 
    if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) {
        if (!quiet) {
            zend_function *active_function = EG(current_execute_data)->function_state.function;
            const char *class_name = active_function->common.scope ? active_function->common.scope->name : "";
            zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given",
                    class_name,
                    class_name[0] ? "::" : "",
                    active_function->common.function_name,
                    min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
                    num_args < min_num_args ? min_num_args : max_num_args,
                    (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
                    num_args);
        }
        return FAILURE;
    }
 
    arg_count = (int)(zend_uintptr_t) *(zend_vm_stack_top(TSRMLS_C) - 1);
 
    if (num_args > arg_count) {
        zend_error(E_WARNING, "%s(): could not obtain parameters for parsing",
            get_active_function_name(TSRMLS_C));
        return FAILURE;
    }
 
    i = 0;
    while (num_args-- > 0) {
        if (*type_spec == ‘|‘) {
            type_spec++;
        }
 
        if (*type_spec == ‘*‘ || *type_spec == ‘+‘) {
            int num_varargs = num_args + 1 - post_varargs;
 
            /* eat up the passed in storage even if it won‘t be filled in with varargs */
            varargs = va_arg(*va, zval ****);
            n_varargs = va_arg(*va, int *);
            type_spec++;
 
            if (num_varargs > 0) {
                int iv = 0;
                zval **p = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count - i));
 
                *n_varargs = num_varargs;
 
                /* allocate space for array and store args */
                *varargs = safe_emalloc(num_varargs, sizeof(zval **), 0);
                while (num_varargs-- > 0) {
                    (*varargs)[iv++] = p++;
                }
 
                /* adjust how many args we have left and restart loop */
                num_args = num_args + 1 - iv;
                i += iv;
                continue;
            } else {
                *varargs = NULL;
                *n_varargs = 0;
            }
        }
 
        arg = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count-i));
 
        if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) {
            /* clean up varargs array if it was used */
            if (varargs && *varargs) {
                efree(*varargs);
                *varargs = NULL;
            }
            return FAILURE;
        }
        i++;
    }
 
    return SUCCESS;
}
 
FAILURE 
技术分享
 
 
 
;
 
typedef union _zvalue_value {
    long lval;                    /* long value */
    double dval;                /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;                /* hash table value */
    zend_object_value obj;
    zend_ast *ast;
} zvalue_value;
 
struct _zval_struct {
    /* Variable information */
    zvalue_value value;        /* value */
    zend_uint refcount__gc;
    zend_uchar type;    /* active type */
    zend_uchar is_ref__gc;
};
 
 
/******/
技术分享
技术分享
 
typedef struct bucket {
    ulong h;                        /* Used for numeric indexing */
    uint nKeyLength;
    void *pData;
    void *pDataPtr;
    struct bucket *pListNext;
    struct bucket *pListLast;
    struct bucket *pNext;
    struct bucket *pLast;
    const char *arKey;
} Bucket;
 
typedef struct _hashtable {
    uint nTableSize;
    uint nTableMask;
    uint nNumOfElements;
    ulong nNextFreeElement;
    Bucket *pInternalPointer;    /* Used for element traversal */
    Bucket *pListHead;
    Bucket *pListTail;
    Bucket **arBuckets;
    dtor_func_t pDestructor;
    zend_bool persistent;
    unsigned char nApplyCount;
    zend_bool bApplyProtection;
#if ZEND_DEBUG
    int inconsistent;
#endif
} HashTable;
 
 
typedef struct _zend_hash_key {
    const char *arKey;
    uint nKeyLength;
    ulong h;
} zend_hash_key;
 
 
<>PHP_RINIT_FUNCTION 每次请求调的
PHP_RSHUTDOWN_FUNCTION 每次请求结束
PHP_MINIT_FUNCTION 模块加载调
技术分享
 

以上是关于php扩展分析的主要内容,如果未能解决你的问题,请参考以下文章

XDebug分析php代码性能

超级有用的9个PHP代码片段

PHP必用代码片段

PHP代码-psysh调试代码片段工具

超实用的php代码片段

比较有用的php代码片段