深入理解PHP内核(七)变量及数据类型-常量
原文链接:http://www.orlion.ga/246/
在PHP中,常量的名字是一个简单值的标识符,在脚本执行期间该值不能改变。和变量一样,常量默认为大小写敏感,但是通常是大写的。
常量是在变量的zval结构的基础上添加了一额外的元素。如下所示为PHP中常量的内部结构。
一、常量的内部结构
typedef struct _zend_constant {
zval value; /* zval结构,PHP内部变量的存储结构,在第一小节有说明 */
int flags; /* 常量的标记如CONST_PERSISTENT | CONST_CS */
char *name; /* 常量名称 */
uint name_len;
int module_number; /* 模块号 */
} zend_constant;
在Zend/zend_constants.h文件的第33行可以看到如上所示的结构定义。在常量的结构中,除了与变量一样的zval结构,它还包括常量的标记,常量名以及常量所在的模块号。
我们来看PHP常量的定义过程:
define('TIPI', 'Thinking In PHP Internal');
这是一个很常规的常量定义过程,它使用了PHP的内置函数difine(),常量名为TIPI,值为一个字符串,存放在zval结构中。从这个例子出发,看下define定义常量的过程实现。
二、define定义常量的过程
define是PHP的内置函数,在Zend/zend_builtin_functions.c文件中定义了此函数的实现。如下所示为部分源码:
/* {{{ proto bool define(string constant_name, mixed value, boolean
case_insensitive=false)
Define a new constant */
ZEND_FUNCTION(define)
{
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name,
&name_len, &val, &non_cs) == FAILURE) {
return;
}
... // 类常量定义 此不做介绍
... // 值类型判断和处理
c.value = *val;
zval_copy_ctor(&c.value);
if (val_free) {
zval_ptr_dtor(&val_free);
}
c.flags = case_sensitive; /* non persistent */
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;
}
}
/* }}} */
上面的代码已经对对象和类常量做了简化处理,其实现基本上是一个将传递的参数传递给新建的zend_constant结构,并将这个结构体注册到常量列表中的过程。关于大小写敏感,函数的第三个参数表示是否大小写不敏感,默认为false(大小写敏感)。这个参数最后会赋值给zend_constant结构体的flags字段,其在函数中实现的代码如下:
zend_bool non_cs = 0; // 第三个参数的临时存储变量
int case_sensitive = CONST_CS; // 是否大小写敏感,默认为1
if(non_cs) { // 输入为真,大小写不敏感
case_sensitive = 0;
}
c.flags = case_sensitive; // 赋值给结构体字段
从上面的define函数的实现来看,PHP对于常量的名称在定义时其实是没有所谓的限制。
三、defined判断常量是否设置
和define一样,defined的实现也在Zend/zend_builtin_functions.c文件,其实现时一个读取参数变量,调用zend_get_constant_ex函数获取常量的值来判断常量是否存在的过程。而zend_get_constant_ex函数不仅包括了常规的常量获取,还包括类常量的获取,最后是通过zend_get_constant函数获取常量的值。在zend_get_constant函数中,基本上是通过下面的代码来获取常量的值:
zend_hash_find(EG(zend_constants), name, name_len+1, (void **) &c)
除此之外,只在调用这个函数之前和之后对name有一些特殊的处理。
四、标准常量的初始化
以上通过define定义的常量的模块编号都是PHP_USER_CONSTANT,表示这是用户定义的常量。除此之外我们在平时使用较多的,如在显示所有级别错误报告时使用的E_ALL常量就有点不同了。我们以cgi模式为例说明标准常量的定义过程。整个调用顺序:php_cgi_startup() -> php_module_startup() -> zend_startup() -> zend_register_standard_constant()
void zend_register_standard_constants(TSRMLS_D)
{
... // 若常量以REGISTER_MAIN_LONG_CONSTANT设置
REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS);
...
}
REGISTER_MAIN_LONG_CONSTANT宏展开是以zend_register_long_constant实现。zend_register_long_constant函数将常量中值的类型,值,名称及模块号赋值给新的zend_constant。并调用zend_register_constant添加到全局的常量列表中。
php_cgi_startup() -> php_module_startup() -> zend_startup() -> zend_register_standart_constant() -> zend_register_constant
ZEND_API void zend_register_long_constant(const char *name, uint name_len,
long lval, int flags, int module_number TSRMLS_DC)
{
zend_constant c;
c.value.type = IS_LONG;
c.value.value.lval = lval;
c.flags = flags;
c.name = zend_strndup(name, name_len-1);
c.name_len = name_len;
c.module_number = module_number;
zend_register_constant(&c TSRMLS_CC);
}
zend_register_constant函数首先根据常量中的c->flags判断是否区分大小写,如果不区分,则名字统一为小写,如果包含"\\",也统一成小写。否则为定义的名字然后将调用下面的语句将当前常量添加到EG(zend_constant)。EG(zend_constants)是一个HashTable,下面的代码是将常量添加到这个HashTable中
zend_hash_add(EG(zend_constants), name, c->name_len, (void *) c,、
sizeof(zend_constant), NULL)==FAILURE)
在php_module_startup函数中,除了zend_startup函数中有注册标准的常量,它本身通过宏REGISTER_MAIN_LONG_CONSTANT等注册了一些常量,如:PHP_VERSION,PHP_OS等。
深入理解PHP内核(七)变量及数据类型-常量的更多相关文章
- 深入理解PHP内核(九)变量及数据类型-静态变量
原文链接:http://www.orlion.ga/251/ 通常静态变量是静态分配的,他们的生命周期和程序的生命周期一样长,只有在程序退出后才结束生命周期,这和局部变量相反,有的语言中全局变量也是静 ...
- [PHP] 深入理解PHP内核:变量及数据类型
1.现实生活中我们会找一个小箱子来存放物品,一来显得不那么凌乱,二来方便以后找到.计算机也是这个道理,我们需要先在内存中找一块区域,规定用它来存放数据,并起一个好记的名字,方便以后查找.这块区域就是“ ...
- 深入理解PHP内核(八)变量及数据类型-预定义变量
原文链接:http://www.orlion.ga/249/ PHP脚本在执行的时候用户全局变量(在用户空间显示定义的变量)会保存在一个HashTable数据类型的符号表中(symbol_table) ...
- 深入理解PHP内核(五)变量及数据类型-变量的结构和类型
原文链接:http://www.orlion.ga/238/ 编程语言的类型可以分为强类型和弱类型两种,PHP是弱类型语言,但是C语言是强类型语言.在官网PHP实现内部,所有变量使用同一种数据结构(z ...
- 深入理解PHP内核(十)变量及数据类型-类型提示的实现
原文链接:http://www.orlion.ga/253/ PHP是弱类型语言,向方法传递参数时也并不严格检查数据类型.不过有时候需要判断传递到方法中的参数,为此PHP中提供了一些函数来判断数据的类 ...
- 深入理解php内核 编写扩展 I:介绍PHP和Zend
内容: 编写扩展I - PHP和Zend起步 原文:http://devzone.zend.com/public/view/tag/Extension Part I: Introduction to ...
- 深入理解php内核——读书笔记1
第一章 基础准备 宏定义 #字符串化 ##连接符 do{}while(0) 多行 全局宏: EG.PG 第二章 用户代码的执行 php请求的生命周期 SAPI接口 php脚本执行 第三章 变量及数据类 ...
- Javascript一(变量,数据类型,正则表达式,数据,语句)
本文章适合具有一定程序编程语言基础的人士阅读,最好学完Java基础再来阅读本文章更容易理解语言初学者会看起来比较费劲,不易理解 一.导入脚本 在html导入Javascript的格式是: <sc ...
- Python变量和数据类型(入门2)
转载请标明出处: http://www.cnblogs.com/why168888/p/6400809.html 本文出自:[Edwin博客园] Python变量和数据类型 一.整数 int = 20 ...
随机推荐
- app快速开发
最近由于工作的原因,公司要开发和系统相应的app, 所以了解了一些这方面的内容.(非原生android IOS 开发) 借用其他网站提供的平台. www.apicloud.com
- H5 canvas填充文字自动换行
canvas是H5中非常重要,非常常用,也是非常强大的一个新标签,美中不足的事,canvas中没没有自动换行的属性,我的第一反应是,字符串截取,然后计算每行的距离来实现自动换行.. 然后百度了一下,已 ...
- Byte,TBytes,array of Byte, array[0..9] of byte的区别
Byte前面已经说是存放bit的单元,是电脑内存的基本单位,byte表示0-255中的256个数字 下面为Byte的用法: var B: Byte; // 表示0-255的数字 begin B := ...
- Android 把电话保存到现有联系人 已有联系人
搜索了很长时间,想找个把电话保存到现有联系人的代码,就是打开选中的联系人编辑界面,然后自动添加电话,再手动保存,就跟手机上的一样,功夫不负有心人,终于给搜到了,很不容易啊,现分享如下, // 保存至现 ...
- codeforces 484E
题意:给定n<=105的数组h,有m<=105的询问,每个询问为l,r,w求[l,r]区间内连续w个的最小高度最大是多少.. 思路:首先把h数组从大到小排序,然后用建立一个可持久化的下标线 ...
- java 上传POJO model jar
打开eclipse----找到要打包的java文件,右键----Export----选择 JAR File 然后NEXT,会让你选择打包的文件,,选择你想打包的,一个或几个.... 在文件选择框的下面 ...
- Linux磁盘管理
本系列的博客来自于:http://www.92csz.com/study/linux/ 在此,感谢原作者提供的入门知识 这个系列的博客的目的在于将比较常用的liunx命令从作者的文章中摘录下来,供自己 ...
- sql 优化 链接提示 查询提示 标提示
SQL Server的查询优化器在select查询执行的时候产生一个高效的查询执行计划.如果优化器不能选择最优的计划,那么就需要检查查询计划.统计信息.支持的索引等,而通过使用提示可以改变优化器选择查 ...
- [Xamarin] 動態載入Fragment (转帖)
這篇我們來動態加入,一樣務求好懂簡單 1.一樣先將專案調整成3.0以上版本 2.首先建立自定Control的Layout \Resources\Layout\MyControlLayout1.axml ...
- [Asp.net 开发系列之SignalR篇]专题二:使用SignalR实现酷炫端对端聊天功能
一.引言 在前一篇文章已经详细介绍了SignalR了,并且简单介绍它在Asp.net MVC 和WPF中的应用.在上篇博文介绍的都是群发消息的实现,然而,对于SignalR是为了实时聊天而生的,自然少 ...