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;
}
未完待续
所有资料参考自: