[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 エンジンは定数リストを維持します。API は
define() です。定数を定義する
define(): 定数が存在するかどうかを判断する
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 です。これに基づいて、定数はタグ、定数名、モジュール番号の 3 つの属性も定義します。
1. フラグ
まず、現在選択可能な値は
です。定義メソッドの 3 番目のパラメータを通じて割り当てられます):
1: 大文字と小文字を区別します
0: 大文字と小文字を区別しません
カーネル状態:
CONST_PERSISTANT : 永続的
CONST_CT_SUBST: コンパイル時の置換を許可します
ユーザー定義定数のマーク付けはデフォルトで大文字と小文字が区別され、define 関数の 3 番目のパラメーターを使用して変更することもできます。カーネル状態タグの場合、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>