• php内核杂七杂八。


    PHP的启动
    PHP的启动经历了
    PHP_MINIT_FUNCTION->
    PHP_RINIT_FUNCTION->
    PHP_RSHUTDOWN_FUNCTION->
    PHP_MSHUTDOWN_FUNCTION
    4个阶段。
    但是 这4个阶段会由于SAPI宿主的不同在不同阶段执行。
    如果把PHP比作汽车,那么SAPI就是公路。
    常见的SAPI可以是
    CLI/CGI
    一个请求过来,会执行以上4个阶段。
    多进程模型
    以APACHE的PRE-FORK为代表,在此模式下,APACHE会设定一个初始进程数量,然后请求增多以后,会以2的指数次方创建进程。
    多线程模型
    以APACHE的worker为代表,在这种模式下,只有一个服务器进程在运行着,但会同时运行很多线程,这样可以减少一些资源开销,向Module init和Module shutdown就只需要运行一遍就行了,一些全局变量也只需要初始化一次,因为线程独具的特质,使得各个请求之间方便的共享一些数据成为可能。
    PHP的类型
    struct _zval_struct {
        zvalue_value value; /* 变量的值 */
        zend_uint refcount__gc; //引用计数
        zend_uchar type;    /* 变量当前的数据类型 */
        zend_uchar is_ref__gc;  //是否被引用
    };
    typedef struct _zval_struct zval;

    其中变量的值zvalue_value又是个union,具体如下
    typedef union _zvalue_value {
        long lval;  /* long value */
        double dval;    /* double value */
        struct {
            char *val;
            int len;
        } str;       //可以看到php的str与c的用\0结束不同,而是用一个int表示他的长度
        HashTable *ht;  /* hash table value PHP数组的保存方式*/
        zend_object_value obj;
    } zvalue_value;

    如何判断PHP值的类型(zval->type),PHP定义了一些以IS_开头的常量
    IS_NULL,IS_LONG,IS_DOUBLE,IS_STRING,IS_ARRAY,IS_OBJECT,IS_RESOURCE
    还定义了三个检测变量类型的宏,分别接收zval,zval*,zval**类型的变量
    define Z_TYPE(zval) (zval).type
    define Z_TYPE_P(zval_p) Z_TYPE(*zval_p)
    define Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp)
    说明:本来也可以把zval->type和IS_开头的常量比较,但是如果以后PHP改变zval的定义,就不能保证兼容性。

    如何操作PHP的值(zval->value)
    PHP定义了基础宏获取zval->value
    //操作整数的
    #define Z_LVAL(zval)            (zval).value.lval
    #define Z_LVAL_P(zval_p)        Z_LVAL(*zval_p)
    #define Z_LVAL_PP(zval_pp)      Z_LVAL(**zval_pp)

    //操作IS_BOOL布尔型的
    #define Z_BVAL(zval)            ((zend_bool)(zval).value.lval)
    #define Z_BVAL_P(zval_p)        Z_BVAL(*zval_p)
    #define Z_BVAL_PP(zval_pp)      Z_BVAL(**zval_pp)

    //操作浮点数的
    #define Z_DVAL(zval)            (zval).value.dval
    #define Z_DVAL_P(zval_p)        Z_DVAL(*zval_p)
    #define Z_DVAL_PP(zval_pp)      Z_DVAL(**zval_pp)

    //操作字符串的值和长度的
    #define Z_STRVAL(zval)          (zval).value.str.val
    #define Z_STRVAL_P(zval_p)      Z_STRVAL(*zval_p)
    #define Z_STRVAL_PP(zval_pp)        Z_STRVAL(**zval_pp)

    #define Z_STRLEN(zval)          (zval).value.str.len
    #define Z_STRLEN_P(zval_p)      Z_STRLEN(*zval_p)
    #define Z_STRLEN_PP(zval_pp)        Z_STRLEN(**zval_pp)

    //操作数组的
    #define Z_ARRVAL(zval)          (zval).value.ht
    #define Z_ARRVAL_P(zval_p)      Z_ARRVAL(*zval_p)
    #define Z_ARRVAL_PP(zval_pp)        Z_ARRVAL(**zval_pp)

    对象和资源类型的暂时不考虑了。

    PHP值的创建
    第一步,通过MAKE_STD_ZVAL(pzv)初始化一个指向zval的指针pzv
    第二步,通过之前学过的操作PHP类型的各种宏对zval->type,zval->value进行赋值。
    比如:
    Z_TYPE_P(pzv) = IS_LONG;
    Z_LVAL_P(pzv) = l;
    也可以用新的宏把它简化
    ZVAL_LONG(pzv, l);
    注意:字符串在php中的表示是
    struct {
        char *val;
        int len;
    } str;  
    所以赋值时候要即赋值val 还要赋值len
    比如:
    Z_TYPE_P(pzv) = IS_STRING;
    Z_STRLEN_P(pzv) = len;
    if (dup)
        {Z_STRVAL_P(pzv) =estrndup(str, len + 1);} //estrndup重新申请内存,并复制字符串
    else
        {Z_STRVAL_P(pzv) = str;}
    也可以用新的宏把它简化
    ZVAL_STRINGL(pzv,str,len,dup);

    变量的存储
    struct _zend_executor_globals {
        ...
        HashTable symbol_table;
        HashTable *active_symbol_table;
        ...
    };   
        创建一个zval结构,并设置其类型。
        设置值为'bar'。
        将其加入当前作用域的符号表,只有这样用户才能在PHP里使用这个变量。

    具体的代码为:
    {
        zval *fooval;

        MAKE_STD_ZVAL(fooval);
        ZVAL_STRING(fooval, "bar", 1);
        ZEND_SET_SYMBOL( EG(active_symbol_table) ,  "foo" , fooval);
    }       

    上面解释了zval->type,zval->vale相关的,下面解释zval->refcount__gc,zval->is_ref_gc
    相关文章检索copy-on-write

    PHP内核中的函数
    ZEND_FUNCTION返回值
    ZEND_FUNCTION的宏展开是
    void name(INTERNAL_FUNCTION_PARAMETERS) 展开INTERNAL_FUNCTION_PARAMETERS
    #define INTERNAL_FUNCTION_PARAMETERS
    int ht,
    zval *return_value, //返回值的指针,给他赋值就行了。
    zval **return_value_ptr,
    zval *this_ptr,
    int return_value_used TSRMLS_DC
    返回值例子:
    ZEND_FUNCTION(sample_long)
    {
        ZVAL_LONG(return_value, 42); //前面讲过的如何给zval* 赋值。
        return;
    }

    未完待续

    所有资料参考自:

    http://www.php-internal.com

    https://github.com/laruence/phpbook

  • 相关阅读:
    codec功能简介
    dtmf原理说明
    linux的vm.overcommit_memory的内存分配参数详解
    Hibernate与Sleep的区别
    简单的读写-simple_read_from_buffer
    linux delay sleep
    Linux系统上的popen()库函数
    Linux中popen函数的作用小结
    ulimit 命令详解
    LTE Cat1有什么用?基于4G LTE打造cat1,弥补NB-IoT和5G的空缺
  • 原文地址:https://www.cnblogs.com/23lalala/p/2703690.html
Copyright © 2020-2023  润新知