Heim >Backend-Entwicklung >PHP-Tutorial >【php原理】狂言php常量

【php原理】狂言php常量

WBOY
WBOYOriginal
2016-06-13 12:00:461084Durchsuche

【php原理】大话php常量

我们先看一个php常量的定义方法

<code style="font-size:14px; line-height:1.3em; border-left-width:4px; border-left-style:solid; border-left-color:rgb(0,136,0); display:block; padding:0.5em; color:rgb(0,0,0)">define(<span class="string" style="color:rgb(136,0,0)">'PRICE'</span>, <span class="number" style="color:rgb(0,136,0)">30</span>);</code>

 之前,我一直把define和C中的宏定义理解一致,因此在使用的时候也只是将其当成简单地字符替换。后来研究了PHP内核以后,发现PHP中的常量和宏定义完全不是一回事。

在PHP脚本运行的过程中,zend引擎会维护一个常量列表,对于普通用户来说,可以对这个常量列表进行CRUD操作,api分别为

define():定义一个常量

defined(): 判断一个常量是否存在

constant(): 得到一个常量的值

我们来看下PHP内核中常量的定义

<code style="font-size:14px; line-height:1.3em; border-left-width:4px; border-left-style:solid; border-left-color:rgb(0,136,0); display:block; padding:0.5em; color:rgb(0,0,0)"><span class="keyword" style="font-weight:bold">typedef</span> <span class="keyword" style="font-weight:bold">struct</span> _zend_constant{	zval value;	<span class="keyword" style="font-weight:bold">int</span> flags;	<span class="keyword" style="font-weight:bold">char</span> *name;	uint name_len;	<span class="keyword" style="font-weight:bold">int</span> module_number;} _zend_constant;</code>

 其中value为普通的变量结构zval,在此基础上,常量还定义了标记,常量名和模块号三个属性。

1. 标记(flags)

首先看常量的标记属性flag,目前可供选择的几个可能值分别为

用户态(可通过define方法的第三个参数赋值):

        1: case sensitive

        0: case insensitive

内核态:

        CONST_PERSISTANT: persistent

        CONST_CT_SUBST: allow compile-time substitution

用户定义的常量的标记默认为case sensitive, 也可通过define函数的第三个参数进行修改。对于内核态标记,CONST_PERSISTANT代表这个常量在内存申请的时候需要持久化。

上图是PHP脚本运行的的生命周期,我们知道多个request共享一次MINIT和MSHUTDOWN过程,而每个request有自己的RINIT和RSHUTDOWN过程,因此在MINIT中初始化的变量会常驻内存当中。这样被标记为CONST_PERSISTANT的常量只会在MSHUTDOWN中才会被析构掉。这也就不难理解,在内核C代码中,一些字符串和数字作为代码的一部分也被定义为PHP内核中的常量,它们通常就会被标记为CONST_PERSISTENT常量。

而CONST_CT_SUBST目前在内核里只有5个(TRUE, FALSE, NULL, ZEND_THREAD_SAFE, ZEND_DEBUG_BUILD),

2.模块号(module_number)

模块号同样分为用户态和内核态,确切的说,模块号就是用来做此区分的。用户定义的常量均为PHP_USER_CONSTANT, 除此以外,还有一些PHP内置的标准常量,例如E_ALL, E_WARNING等。在zend引擎启动以后,zend会进行标准常量的注册工作(zend_register_standard_constants()),一般来说,这些标准常量都被标记为持久化常量,即CONST_PERSISTENT

3. define()函数

define是PHP的内置接口,用户会通过define来定义常量,其实该方法过程如下

4. 魔术常量

PHP中还提供了一种魔术常量,他们的值是随着外部环境的变化而变化的,例如

__LINE__ 当前文件的行号

__FILE__ 文件的完整路径

这些魔术常量不是真正的常量(_zend_constants),PHP内核在此法解析的时候就会将其替换掉。

最后附上define的源码(在Zend/zend_builtin_functions.c中):

<code style="font-size:14px; line-height:1.3em; border-left-width:4px; border-left-style:solid; border-left-color:rgb(0,136,0); display:block; padding:0.5em; color:rgb(0,0,0)"><span class="comment" style="color:rgb(136,136,136)">/* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false)   Define a new constant */</span>ZEND_FUNCTION(define){	<span class="keyword" style="font-weight:bold">char</span> *name;	<span class="keyword" style="font-weight:bold">int</span> name_len;	zval *val;	zval *val_free = NULL;	zend_bool non_cs = <span class="number" style="color:rgb(0,136,0)">0</span>;	<span class="keyword" style="font-weight:bold">int</span> case_sensitive = CONST_CS;	zend_constant c;	<span class="keyword" style="font-weight:bold">if</span> (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, <span class="string" style="color:rgb(136,0,0)">"sz|b"</span>, &name, &name_len, &val, &non_cs) == FAILURE) {		<span class="keyword" style="font-weight:bold">return</span>;	}	<span class="keyword" style="font-weight:bold">if</span>(non_cs) {		case_sensitive = <span class="number" style="color:rgb(0,136,0)">0</span>;	}	<span class="comment" style="color:rgb(136,136,136)">/* class constant, check if there is name and make sure class is valid & exists */</span>	<span class="keyword" style="font-weight:bold">if</span> (zend_memnstr(name, <span class="string" style="color:rgb(136,0,0)">"::"</span>, <span class="keyword" style="font-weight:bold">sizeof</span>(<span class="string" style="color:rgb(136,0,0)">"::"</span>) - <span class="number" style="color:rgb(0,136,0)">1</span>, name + name_len)) {		zend_error(E_WARNING, <span class="string" style="color:rgb(136,0,0)">"Class constants cannot be defined or redefined"</span>);		RETURN_FALSE;	}repeat:	<span class="keyword" style="font-weight:bold">switch</span> (Z_TYPE_P(val)) {		<span class="keyword" style="font-weight:bold">case</span> IS_LONG:		<span class="keyword" style="font-weight:bold">case</span> IS_DOUBLE:		<span class="keyword" style="font-weight:bold">case</span> IS_STRING:		<span class="keyword" style="font-weight:bold">case</span> IS_BOOL:		<span class="keyword" style="font-weight:bold">case</span> IS_RESOURCE:		<span class="keyword" style="font-weight:bold">case</span> IS_NULL:			<span class="keyword" style="font-weight:bold">break</span>;		<span class="keyword" style="font-weight:bold">case</span> IS_OBJECT:			<span class="keyword" style="font-weight:bold">if</span> (!val_free) {				<span class="keyword" style="font-weight:bold">if</span> (Z_OBJ_HT_P(val)->get) {					val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);					<span class="keyword" style="font-weight:bold">goto</span> repeat;				} <span class="keyword" style="font-weight:bold">else</span> <span class="keyword" style="font-weight:bold">if</span> (Z_OBJ_HT_P(val)->cast_object) {					ALLOC_INIT_ZVAL(val_free);					<span class="keyword" style="font-weight:bold">if</span> (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) {						val = val_free;						<span class="keyword" style="font-weight:bold">break</span>;					}				}			}			<span class="comment" style="color:rgb(136,136,136)">/* no break */</span>		<span class="keyword" style="font-weight:bold">default</span>:			zend_error(E_WARNING,<span class="string" style="color:rgb(136,0,0)">"Constants may only evaluate to scalar values"</span>);			<span class="keyword" style="font-weight:bold">if</span> (val_free) {				zval_ptr_dtor(&val_free);			}			RETURN_FALSE;	}		c.value = *val;	zval_copy_ctor(&c.value);	<span class="keyword" style="font-weight:bold">if</span> (val_free) {		zval_ptr_dtor(&val_free);	}	c.flags = case_sensitive; <span class="comment" style="color:rgb(136,136,136)">/* non persistent */</span>	c.name = IS_INTERNED(name) ? name : zend_strndup(name, name_len);	<span class="keyword" style="font-weight:bold">if</span>(c.name == NULL) {		RETURN_FALSE;	}	c.name_len = name_len+<span class="number" style="color:rgb(0,136,0)">1</span>;	c.module_number = PHP_USER_CONSTANT;	<span class="keyword" style="font-weight:bold">if</span> (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {		RETURN_TRUE;	} <span class="keyword" style="font-weight:bold">else</span> {		RETURN_FALSE;	}}<span class="comment" style="color:rgb(136,136,136)">/* }}} */</span></code>

 

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn