常量,顾名思义是一个常态的量值。它与值只绑定一次,它的做用在于有肋于增长程序的可读性和可靠性。 在PHP中,常量的名字是一个简单值的标识符,在脚本执行期间该值不能改变。和变量同样,常量默认为大小写敏感,可是按照咱们的习惯常量标识符老是大写的。 常量名和其它任何 PHP 标签遵循一样的命名规则。php
php 7 和以前的版本实现是不同的,下面先说下5.3.5的程序员
php中常量的存储结构定义是放在Zend/zend_constants.h文件的33行 安全
}zend_constant; php7
定义常量用到的函数是define,这个含糊的实现是在Zend/zend_builtin_functions.c 多线程
char *name;
int name_len;
zval *val;
zval *val_free = NULL;
zend_bool non_cs = 0;
int case_sensitive = CONST_CS;
zend_constant c;函数
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
return;
}ui
if(non_cs) {
case_sensitive = 0;
}spa
这里主要的一个函数是zend_parse_parameters,这个函数的功能就是将参数解出来。线程
详细说下这个函数,首先看下这个函数中比较怪异的参数 ZEND_NUM_ARGS() TSRMLS_CC,这连个参数之间是空格的而不是逗号,进程
其实这个看下TSRMLS_CC的宏定义就能明白
#define TSRMLS_CC , TSRMLS_C //线程安全模式
#define TSRMLS_CC // 非线程安全模式
也就是说在线程安全模式下,TSRMLS_CC会被替换成 , TSRMLS_C 而且最终会被替换成,tsrm_ls ,分线程安全模式下,其实就是个空格
下面对于tsrm_ls 这个变量作说明。
在php源码中常常会看到一些名词,TSRM即线程安全资源管理器(Thread Safe Resource Manager),它在源码的/TSRM目录下面。通常状况下,这个只会在被知名须要的时候才会被启用(好比,Apache2+worker MPM,一个基于线程的MPM),对于Win32下的Apache来讲,是基于多线程的,因此这个层在Win32下老是被启用的。ZTS即Zend线程安全(Zend Thread Safety),当TSRM被启用的时候,就会定义这个名为ZTS的宏。tsrm_ls 即TSRM存储器(TSRM Local Storage),这个是在扩展和Zend中真正被实际使用的指代TSRM存储的变量名。TSRMLS_开头的宏通常有四个用来根据ZTS宏被定义与否来实现TSRM。4个宏以下:
#define TSRMLS_C tsrm_ls
#define TSRMLS_D void *** tsrm_ls
#define TSRMLS_CC ,tsrm_ls
#define TSRMLS_DS ,void ***tsrm_ls //注意有个逗号
php源码用这么复杂的宏保证线程安全,这主要是由于全局变量的缘由。简单的说,咱们若是在两个函数中处理一个变量,一种方式是使用全局,好比:
#include <stdio.h>
char *message;
void output_func(void){
printf("%s\n", message);
}
int main(int argv, char *argv[]){
message = argv[0];
output_func();
return 0;
}
通常的单线 程模型好比PHP CLI方式,Apache1,或者Apache2+prefork MPM(也是一种多进程模型),能够放心的被使用,也不会出错。全局变量在MINIT/RINIT的时候被建立,而后在整个进程运行时/请求处理期都能被 访问到,而后在MSHUTDOW/RSHUTDOWN的时候被释放。可是在多线程的模型下,这种方式就不在安全了,好比Apache2+worker MPM和IIS。在这种状况下,全部的线程共享同一个进程的地址空间,也就说,多个线程共用一个全局变量,这个时候就会产生竞争。用C程序员的方式来讲: 这个时候的全局变量是非线程安全的。
为了解决这个问题,并和单线程模式兼容,Zend使用了称做“Non_global Globals”的机制。这个机制的主要思想就是,对于多线程模型来讲,每当一个新的线程被建立,就单独的分配一块内存,这块内存存储着一个全局变量的副 本。而这块内存会被一个Vector串起来,由Zend统一管理。
这个连接是一个例子 http://www.luojisiwei-inc.com/archives/521
说了一大堆,其实要说是define的参数解析。其实以后就是一个将解析的参数复制过程。看代码就很容易理解。
php 7 的define 内置函数解析,相对来讲有点区别
#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|b", &name, &val, &non_cs) == FAILURE) {
return;
}
#else
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(name)
Z_PARAM_ZVAL(val)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(non_cs)
ZEND_PARSE_PARAMETERS_END();
#endif
默认php 7 在zend_API 中是定义了使用FAST_ZPP
也就是说,php7时候用了新的参数解析方式
ZEND_PARSE_PARAMETERS_START(2, 3) 是检测参数个数
Z_PARAM_STR(name)
Z_PARAM_ZVAL(val) 这连个函数分别是调用不一样的宏,用参数赋值变量,这段代码用了大量的宏,一些变量在本宏中找不到的话,在前面的宏里面找找