PHP源码分析之变量的存储过程分解

PHP代码如下:

代码如下:

$php_var = 1;

对应C的代码是:

代码如下:

zval* c_var;    //定义PHP变量指针 
MAKE_STD_ZVAL(c_var);  //初始化PHP变量 
ZVAL_LONG(c_var,1) ;//赋值 
ZEND_SET_SYMBL( EG(active_symbol_table), " php_var ", c_var);//注册到全局变量符号表

一.首先看第一行: zval* c_var;//申明一个zval指针c_var; zval的结构如下:

代码如下:

struct _zval_struct { 
    /* Variable information */ 
    zvalue_value value;     /* 变量的值 */ 
    zend_uint refcount;     /* 引用计数,垃圾回收的时候用到 */ 
    zend_uchar type;        /* 变量类型 */ 
    zend_uchar is_ref;      /* 是否为引用变量 */ 
}; 
typedef struct _zval_struct zval;

其中值zvalue_value的结构如下:

代码如下:

typedef union _zvalue_value { 
    long lval;              /* 长整形*/ 
    double dval;            /* 双精度类型 */ 
    struct {                  /* 字符串类型的值 */ 
        char *val;             
        int len; 
    } str; 
    HashTable *ht;              /* 数组类型的值 */ 
    zend_object_value obj;     /*对象类型的值*/ 
} zvalue_value;

二.接下来看第二行: MAKE_STD_ZVAL(new_val);//变量初始化 相关宏如下: //初始化

代码如下:

#define MAKE_STD_ZVAL(zv)                \ 
    ALLOC_ZVAL(zv); \ 
    INIT_PZVAL(zv); 
 
#define ALLOC_ZVAL(z)   \ 
    ZEND_FAST_ALLOC(z, zval, ZVAL_CACHE_LIST) 
 
#define ZEND_FAST_ALLOC(p, type, fc_type)   \ 
    (p) = (type *) emalloc(sizeof(type)) 
 
#define INIT_PZVAL(z)       \ 
    (z)->refcount = 1;      \ 
    (z)->is_ref = 0;

展开后为:

代码如下:

(c_var) = (zval *) emalloc(sizeof(zval));  //分配内存 
(c_var)-> refcount = 1;  //引用计数初始化 
(c_var)-> is_ref = 0; //是否引用

可以看到其作用就是分配内存,初始化refcount,is_ref

三.下面看第三行 ZVAL_LONG(c_var,1) 相关宏为:

代码如下:

//定义值 
#define ZVAL_LONG(z, l) {           \ 
     Z_TYPE_P(z) = IS_LONG;      \ 
     Z_LVAL_P(z) = l;            \ 

#define Z_TYPE_P(zval_p)    Z_TYPE(*zval_p) 
#define Z_TYPE(zval)        (zval).type 
#define Z_LVAL_P(zval_p)    Z_LVAL(*zval_p) 
#define Z_LVAL(zval)            (zval).value.lval

展开后为:

代码如下:

(* c_var).type = IS_LONG; 
(* c_var).value = 1;

四:接下来看第四行: ZEND_SET_SYMBOL( EG(active_symbol_table), “php_var”, c_var); 首先说明下PHP的变量是存在一个hashtable里的

代码如下:

struct _zend_executor_globals {   
        …. 
        HashTable symbol_table;//全局变量的符号表   
        HashTable *active_symbol_table;//局部变量的符号表   
        ….. 
    };

Hashtable的Key为变量的名称,即php_var,值为指向PHP变量的指针,即c_var指针; 相关宏为:

代码如下:

#define ZEND_SET_SYMBOL(symtable, name, var)          \   {                                                     \ 
        char *_name = (name);                         \ 
        ZEND_SET_SYMBOL_WITH_LENGTH(symtable, _name, strlen(_name)+1, var, 1, 0);   \ 

//主要的实现为下面这个函数: 
#define ZEND_SET_SYMBOL_WITH_LENGTH(symtable, name, name_length, var, _refcount, _is_ref)                                                       \ 
    {                                                                        
        zval **orig_var;                                        \  
        if (zend_hash_find(symtable, (name), (name_length), (void **) &orig_var)==SUCCESS                                                         \ 
            && PZVAL_IS_REF(*orig_var)) {                     \ 
            (var)->refcount = (*orig_var)->refcount;                  \ 
            (var)->is_ref = 1;                                \ 
            if (_refcount) {                                      \ 
                (var)->refcount += _refcount-1;               \ 
            }                                             \ 
            zval_dtor(*orig_var);                             \ 
            **orig_var = *(var);                                  \ 
            FREE_ZVAL(var);                               \ 
        } else {                                              \ 
            (var)->is_ref = _is_ref;                              \ 
            if (_refcount) {                                      \ 
                (var)->refcount = _refcount;                      \ 
            }                                             \ 
            zend_hash_update(symtable, (name), (name_length), &(var), sizeof(zval *), NULL);                                                           \ 
        }                                                  \ 
    }

该函数的功能是:
1. 如果全局符号表已经存在该变量且是引用类型,则

a. 将原来变量的引用计数refcount,is_ref信息赋给c_var;
b. 释放掉原来变量zvalue的值,比如原来其值指向的是一个mysql连接资源,则释放该资源。
c. 将c_var指向的变量赋值给原来的变量 d. 释放c_var的内存空间 这样保证了,如果变量被应用,值一起改变。比如如果前面有$b=&a;

2. 如果全局符号表不存在该变量或者存在该变量但不是引用变量,则直接改变其值。

(0)

相关推荐

  • 用PHP调用Oracle存储过程的方法

    但是使用存储过程至少有两个最明显的优点:速度和效率.使用存储过程的速度显然更快.在效率上,如果应用一次需要做一系列sql操作,则需要往返于php与oracle,不如把该应用直接放到数据库方以减少往返次数,增加效率.但是在internet应用上,速度是极度重要的,所以很有必要使用存储过程.偶也是使用php调用存储过程不久,做了下面这个列子. 代码 复制代码 代码如下: //建立一个test表 create table test ( id number(16) not null, name varc

  • Php Mssql操作简单封装支持存储过程

    核心代码: <?php /* * class :Mssql * time :2009-12-10 * author :Libaochang * version :1.0b * description :mssql database access class,it can execute the procedur or sql */ class MssqlUtil { var $user = null; //database user name var $keys = null; //databa

  • php调用mysql存储过程实例分析

    本文实例分析了php调用mysql存储过程的方法.分享给大家供大家参考.具体分析如下: Mysql存储过程创建语法,代码如下: CREATE PROCEDURE和CREATE FUNCTION : 复制代码 代码如下: CREATE PROCEDURE sp_name ([proc_parameter[,...]])       [characteristic ...] routine_body   CREATE FUNCTION sp_name ([func_parameter[,...]])

  • php存储过程调用实例代码

    复制代码 代码如下: //比如要调用的存储过程为gxtj(a,b) $db=new mysqli("localhost","ssss","aaaaa","bbbb"); mysqli_query($db,"SET NAMES utf8"); $result=$db->query("call gxtj($year,$jd)"); // gxtj是mysql的存储过程名称 [color

  • php调用mysql存储过程

    前面转载了一篇<php调用mysql存储过程的文章>经过测试,发现文章中的方法似乎不可行! 调用带有select语句的存储过程就出现 PROCEDURE p can't return a result set in the given context的错误.google了半天,在mysql官网上找到一些说法,db_mysql的模块不支持存储过程调用,解决方法是用db_mysqli.测试了一下,果然可以了. 用法比较简单,没啥好说的,从网上copy一段代码吧: <?php /* Conne

  • PHP调用存储过程返回值不一致问题的解决方法分析

    本文实例讲述了PHP调用存储过程返回值不一致问题的解决方法.分享给大家供大家参考,具体如下: 今天遇一个同学聊存储过程返回值经常得到意外的值为null, 因为白天有事,晚上给做一个实验放在这里供有相应问题的同学查看一下. 存储过程: delimiter// createprocedureusp_s2(outpar1int) begin selectinet_ntoa(ip),portfromproxy_listlimit5; selectcount(*)intopar1fromproxy_lis

  • 基于Php mysql存储过程的详解

    实例一:无参的存储过程 复制代码 代码如下: $conn = mysql_connect('localhost','root','root') or die ("数据连接错误!!!");mysql_select_db('test',$conn);$sql = "create procedure myproce()beginINSERT INTO user (id, username, sex) VALUES (NULL, 's', '0');end;";mysql_

  • PHP调用MySQL的存储过程的实现代码

    MySQL好像从5.0开始才引入存储过程,反正以前做应用的时候从没碰过,不过现在因为主要作内部系统,所以很多应用都用到了存储过程,当然前台有时候也需要调用MySQL存储过程,PHP的MySQL Lib好像支持的不是很好,不过我搜索了些资料,虽然不多,但是还是尝试的使用了,现在介绍一下方法,以便用到的朋友不用再头疼. lMySQL扩展也是支持存储过程的,不过只支持无返回结果的存储过程,如果该存储过程存在输出,这个调用就会抛出一个错误,具体错误忘记了.调用方式很简单: $rs = mysql_que

  • PHP调用MySQL存储过程并返回值的方法

    本文实例讲述了php中调用执行mysql存储过程然后返回由存储过程返回的值,分享给大家供大家参考.具体分析如下: 调用存储过程的方法. a.如果存储过程有 IN/INOUT参数,声明一个变量,输入参数给存储过程,该变量是一对,一个php变量,也可以不必,只是没有php变量时,没有办法进行动态输入,一个Mysql变量. b.如果存储过程有OUT变量,声明一个Mysql变量,mysql变量的声明比较特殊,必须让mysql服务器知道此变量的存在,其实也就是执行一条mysql语句,入set @mysql

  • PHP调用MsSQL Server 2012存储过程获取多结果集(包含output参数)的详解

    [PHP Source Code]: 复制代码 代码如下: $dbh = new PDO('sqlsrv:server=连接地址;Database=数据库名', 用户名, 密码);try { $procName = "P_Test_GetMixData"; $stmt = $dbh->prepare("EXEC $procName ?, ?, ?"); $nReturnValue = 0; $strReturnValue = ""; $st

  • PHP得到mssql的存储过程的输出参数功能实现

    在开发过程中可能会遇到无法取得MSSQL存储过程的输出参数,很多朋友都不知道该怎么办,本文将详细介绍PHP得到mssql的存储过程的输出参数功能实现,需要了解的朋友可以参考下 复制代码 代码如下: <? $conn=mssql_connect("127.0.0.1","user","passwd"); mssql_select_db("mydb"); $stmt=mssql_init("pr_name"

  • PHP MSSQL 存储过程的方法

    复制代码 代码如下: function generateDocCode() { $wf_id = self::WORKFLOW_ID; $doc_code = ""; $link = mssql_connect($this->cfg->db->params->host, $this->cfg->db->params->username, $this->cfg->db->params->password) or di

随机推荐