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

|=-----------------------------------------------------------------------=|

|=---------------------=[ 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 <[email protected]>

   */

  

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

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

时间: 2024-10-11 06:49:04

【PHP内核学习】变量和数据类型的相关文章

轻松学习JavaScript五:JavaScript的变量和数据类型

对于一们编程语言,肯定包含变量和数据类型.今天我们就来看看JavaScript脚本语言的变量和数据类型.相对 于其他的Java,C++等高级程序语言,JavaScript显得很简单. 一变量 JavaScript的变量是松散类型的,所谓松散就是用来保存任何类型的数据.变量是存储信息的容器.定义变量时 要使用var操作符(var是关键字),后面跟一个变量名(变量名是标识符).变量也就是初始化后可以再次改变的量. 那么我们来看看实例: <span style="font-size:18px;&

Java学习 (三)、变量,数据类型(一)

一.声明和使用变量的步骤: ①声明一个变量以分配空间:根据类型开辟空间. int a;  int 占4个字节 ②为变量赋值:将数据存入空间. a=20; ③使用变量:取出数据,使用. System.out.println(a); 二.标识符命名规则 变量名=首字符+其余部分 首字符:字母.下划线.’$’ 其余部分:数字.字母.下划线.’$’ 变量名:应避开关键字,如int int=10;第二个int就是关键字,不能使用 符合驼峰命名法:mySocre,若名字由多个单词组成,从第二个单词开始,首字

JavaSE学习笔记(二)——变量和数据类型

一.  Java中的变量 1.1           字面值的概念 字面值是内存中的一块空间,这块空间存放有值,并且这个值是有类型的.如:在内存中的某个空间存放着100的值,类型是整型.在内存的另一个空间存放着true,代表真,是布尔类型. 例子:字面值举例 public class VariableTest01 { public  static void main(String[] args){ //  整型字面值 System.out.println(100); //  字符串类型字母值 S

前端学习(25)~js学习(三):变量的数据类型

变量的数据类型 为什么需要数据类型 在计算机中,不同的数据所需占用的存储空间不同,为了充分利用存储空间,于是定义了不同的数据类型.而且,不同的数据类型,寓意也不同. JS 的变量数据类型,是在程序运行的过程中,根据等号右边的值来确定的.而且,变量的数据类型是可以变化的.比如说: var name = 'qianguyihao'; name = 123; // 强制将变量 name 修改为 数字类型 JS中一共有六种数据类型 基本数据类型(值类型):String 字符串.Number 数值.Boo

PHP100-第三讲 PHP5.4 语法、常量、变量、数据类型详解

内容摘要: ①PHP5.4 的基本语法与写作格式 ②PHP5.4 的变量与变量数据类型 ③PHP5.4 的系统常量与自定义常量 PHP5.4 的基本语法与写作格式: 任何程序语言都有自己的语言风格,PHP语言也有自己独特的风格,虽然也继承了许多Perl和C的语言特色.但经过多年的发展PHP已经成为了一个成熟 的编程语言,所以我们还需要认真的学习PHP的独特语法.PHP一个很大的特色就是与HTML标签语言进行混编,这种模式是今后很长一段学习过程中所用到 的格式,因此我们先来通过一个例子来认识一下P

Linux内核学习-进程

先说几个术语: 一.Linux进程的五个段 下面我们来简单归纳一下进程对应的内存空间中所包含的5种不同的数据区都是干什么的.重点:代码段.数据段.堆栈段,这是一个概念堆.栈.全局区.常量区,这是另一个概念1)代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像.代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作--它是不可写的.代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域.这部分

第二章 变量、数据类型和运算符

1 变量和数据类型 1.1 变量 电脑使用内存来记忆计算时所使用的数据 内存如何存储数据:内存像旅馆一样 开房间(单人间.双人间.总统套间);告诉内存在存放何种类型的数据 入住;存入数据 使用内存做什么:存放数据 怎么找到存入的数据? 根据内在地址可以找到内存空间的位置,但内存地址不好记 通过变量名可以简单快速地找到它存储的数据 1.2 数据类型 1.2.1 Java数据 那么Java中有哪些常用的数据类型呢? 正如前面所讲到的"根据数据的类型为其在内存中分配一块空间",不同的数据在存

python入门课程 第3章 Python变量和数据类型

第3章 Python变量和数据类型3-1 Python中数据类型计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据,需要定义不同的数据类型.在Python中,能够直接处理的数据类型有以下几种:一.整数Python可以处理任意大小的整数,当然包括负整数,在Python程序中,整数的表示方法和数学上的写法一模一样.计算机由于使用二进制,所以,有时候用十六进制表示整数比较

【PHP内核学习】深入理解FastCGI

本文github地址:https://github.com/wusuopubupt/phpLib/blob/master/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3FastCGI |=-----------------------------------------------------------------------=| |=------------------------=[ 深入理解FastCGI ]=--------------------------