您的位置:首页 > 编程语言 > PHP开发

【PHP内核学习】变量和数据类型

2014-05-08 14:05 507 查看
|=-----------------------------------------------------------------------=||=---------------------=[ PHP内核中的变量和数据类型]=--------------------=||=-----------------------------------------------------------------------=||=--------------------------=[ by d4shman ]=-----------------------------=||=-----------------------------------------------------------------------=||=-------------------------=[  May 6, 2014  ]=---------------------------=||=-----------------------------------------------------------------------=|
(_____ \| |   | (_____ \   /\   / _____) |  / )    _____) ) |__ | |_____) ) /  \ | /     | | / /    |  ____/|  __)| (_____ ( / /\ \| |     | |< <     | |     | |   | |     | | |__| | \_____| | \ \    |_|     |_|   |_|     |_|______|\______)_|  \_)   (向phrack致敬!)
<--------------------------( Table of Contents )-------------------------->
 0x01  变量的结构和类型 0x02  哈希表--PHP的灵魂 0x03  常量 0x04  参考文献<------------------------------------------------------------------------->
/////0x01  变量的结构和类型/////1.数据类型  1.1静态类型语言(C/Java),编译时确定  1.2动态类型语言(php/python),运行时确定  1.3无类型语言(汇编),操作的底层存储
2.php内核中所有的变量使用同一种数据结构zval来保存,而这个结构同时表示php中各种数据类型,它不仅仅包含变量的值,也包含变量的类型。这就是php弱类型的核心。        php中的8中数据类型:  2.1标量类型: boolean, integer, float, string  2.2复合类型:  array, object  2.3特殊类型: resource, null  3.zval结构体(在php源码目录下Zend/zend.h中定义):  struct _zval_struct{  	  /*Variable information*/  	  zvalue_value value  	/*value, 变量的值*/  	  zend_uint refcount__gc  /*reference count, 引用计数器*/  	  zend_uchar type 		/*active type, 变量的类型*/  	  zend_uchar is_ref__gc;  /*变量是否被引用*/  }
4.变量类型:  /*data types */  #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  5.变量的值存储  typedef union _zvalue_value {      long lval; 		/*long、bool、resource类型*/	  double dval ;	/*double 类型*/	  struct {		/*string 类型, len保存了字符串的长度*/	  	char *val;	  	int len;	  } str;	  HashTable *ht;  /*数组, 用HashTable实现*/	  zend_object_value obj; /*object 类型*/  } zvalue_value;    这里之所以用共同体(union)是因为一个变量只可能有一种类型,符合共同体的特性,如果使用结构体则会浪费内存。    实例:创建一个值为10的整型变量lvar,用php脚本的话很简单,就是:$lvar = 10  而PHP内核中的实现可能就是类似下面这样:  zval lval;  Z_TYPE(lvar) = IS_LONG;  Z_LVAL(lvar) = 10;  /////0x02  哈希表--PHP的灵魂/////1.为什么用哈希表  哈希表通常提供CRUD(Create, Read, Update, Delete)操作,设计合理的哈希表中,这些操作时间复杂度为O(1),这也是它被钟爱的原因。  hash(key) -> index  2.哈希表的实现:结构体 bucket和_hashtable组成了完整的HashTable。  首先看bucket结构体(定义在 Zend/zend_hash.h):  typedef struct bucket {	  ulong h;  					/*hash值*/	  uint nKeyLength;			/*key的长度*/	  void *pData;				/*要保存的内存块地址,通常是malloc来的地址*/	  void *pDataPtr;				/*保存指针数据,不经过malloc的指针,防止产生内存碎片*/	  struct bucket *pListNext;   /*bucket中具有同一hash值的下一个元素*/	  struct bucket *pListLast;   /*bucket中具有同一hash值的上一个元素*/	  struct bucket *pNext;		/*双向链表的下一个元素*/	  struct bucket *pLast;       /*双向链表的上一个元素*/	  const char *arKey;			/*保存key*/  } Bucket;    可以看出bucket是一个双向链表,这是为了解决多个key冲突的问题(即算法导论中的链接法)      再看_hashtable结构体:  typedef struct _hashtable {      uint nTableSize;                /*bucket数组的大小*/	  uint nTableMask;					  uint nNumOfElements;			/*HashTable中元素的个数*/	  ulong nNextFreeElement;			/*下一个可用的Bucket位置*/	  Bucket *pInternalPointer		/*遍历HashTable元素*/	  Bucket *pListHead;				/*双向链表表头*/	  Bucket *pListTail;				/*双向链表表尾*/	  Bucket **arBuckets;				/*Bucket数组*/  } HashTable;    ========  此处为HashTable的结构图  ========
3.神奇的数字--33  见我原来的一篇博客:http://blog.csdn.net/wusuopubupt/article/details/11479869  下面是PHP源码中的一段注释:  /*   * DJBX33A (Daniel J. Bernstein, Times 33 with Addition)   *   * This is Daniel J. Bernstein's popular `times 33' hash function as   * posted by him years ago on comp.lang.c. It basically uses a function   * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best   * known hash functions for strings. Because it is both computed very   * fast and distributes very well.   *   * The magic of number 33, i.e. why it works better than many other   * constants, prime or not, has never been adequately explained by   * anyone. So I try an explanation: if one experimentally tests all   * multipliers between 1 and 256 (as RSE did now) one detects that even   * numbers are not useable at all. The remaining 128 odd numbers   * (except for the number 1) work more or less all equally well. They   * all distribute in an acceptable way and this way fill a hash table   * with an average percent of approx. 86%.   *   * If one compares the Chi^2 values of the variants, the number 33 not   * even has the best value. But the number 33 and a few other equally   * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great   * advantage to the remaining numbers in the large set of possible   * multipliers: their multiply operation can be replaced by a faster   * operation based on just one shift plus either a single addition   * or subtraction operation. And because a hash function has to both   * distribute good _and_ has to be very fast to compute, those few   * numbers should be preferred and seems to be the reason why Daniel J.   * Bernstein also preferred it.   *   *   *                  -- Ralf S. Engelschall <rse@engelschall.com>   */
  4.哈希表的操作接口(省略了部分参数)  初始化HashTable:int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction);  添加新hash值:   int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData)  查找hash:       int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData);

/////0x03  常量///// 1.常量的内部结构  typedef struct _zend_constant {	  zval value;	  int flags;  /*常量标记,如 CONST_PERSISTENT | CONST_CS */	  char *name;	  uint name_len;	  int module_number;  } zend_constant;
2.define定义常量的过程    define的实现(定义在Zend/zend_builtin_functions.c),下面是部分核心代码:    ZEND_FUNCTION(define)  {      /* 检查常量名是否存在 */      if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) {          zend_error(E_WARNING, "Class constants cannot be defined or redefined");          RETURN_FALSE;      }            ... // 类常量定义 此处不做介绍            c.value = *val;      zval_copy_ctor(&c.value);      if (val_free) {              zval_ptr_dtor(&val_free);      }      c.flags = case_sensitive;  /* 大小写敏感 */      c.name = zend_strndup(name, name_len);      c.name_len = name_len+1;      c.module_number = PHP_USER_CONSTANT;      if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {  /*注册常量*/              RETURN_TRUE;      } else {              RETURN_FALSE;      }  }  3.魔术常量  PHP中的魔术常量,虽然叫做常量,但它们的值实际上随它们在代码中的位置而变化的。  __LINE__	 	文件中的当前行号。  __FILE__	 	文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。  __DIR__	 	文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。它等价于 dirname(__FILE__)。  __FUNCTION__	函数名称  __CLASS__	 	类的名称。类名包括其被声明的作用区域(例如 Foo\Bar)。  __TRAIT__	 	Trait 的名字。Trait 名包括其被声明的作用区域(例如 Foo\Bar)。  __METHOD__	类的方法名  __NAMESPACE__	当前命名空间的名称(区分大小写)。此常量是在编译时定义的(PHP 5.3.0 新增)。    PHP内核会在词法解析时将这些常量的内容赋值进行替换,而不是在运行时进行分析。 举个例子:  <?php  echo __LINE__;  function demo() {    echo __FUNCTION__;  }  demo();  ?>  PHP已经在词法解析时将这些常量换成了对应的值,以上的代码可以看成如下的PHP代码:  <?php  echo 2;  function demo() {      echo "demo";  }  demo();  ?>
  ===========  此处涉及编译原理知识,需补充。  ===========  /////0x04  参考文献///// 
TIPI: http://www.php-internals.com/book/?p=chapt03/03-00-variable-and-data-types[/code]
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: