PHP中define常量的实现

43 篇文章 0 订阅
在应用中经常使用define来定义一些常用的参数信息,来增加程序的可读性和可靠性。


在PHP中,常量的名字是一个简单的标识符,执行周期中不能改变,并且默认情况下是大小写敏感的。通常常量总是大写的。

注:define中的第三个参数可以设置是否常量名大小写敏感


一、常量的内部结构

typedef struct _zend_constant {
    zval value; /* zval结构,PHP内部变量的存储结构 */
    int flags;  /* 常量的标记如 CONST_PERSISTENT | CONST_CS */
    char *name; /* 常量名称 */
    uint name_len;  /* 常量名称字符长度 */
    int module_number;  /* 模块号 */
} zend_constant;

二、PHP中定义常量

<?php
define('DATABASE', 'MYSQL');
define('DATABASE_USER', 'ROOT');
define('DATABASE_PASSWORD', 'PASSWORD');

三、分析opcode

# php -dvld.active=1 index.php
打印出opchode,如下图


注,查看opcode扩展VLD安装可以阅读 《通过VLD扩展分析PHP opcode

这里介绍出现的了三条指令,SEND_VAL、DO_FCALL、RETURN
SEND_VAL:传递参数的固定值,操作码65
RETURN:从函数中返回结果,操作码62
DO_FCALL:调用函数,操作码60

更多指令说明:http://php.net/manual/en/internals2.opcodes.list.php


四、通过ZEND VM执行opcode

void zif_define(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used )

ZEND_FUNCTION(define)
{
	char *name;
	int name_len;
	zval *val;
	zval *val_free = NULL;
	zend_bool non_cs = 0;//接收第三个参数,是否大小写敏感,默认不敏感
	int case_sensitive = CONST_CS;
	zend_constant c;	//PHP中常量对应的结构体变量

	/*
	 * sz|b function define(string, zval [, boolean])
	 * 这个参数表示定义接收的参数,s为字符串,z为zval,b为boolean
	 * */
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
		return;
	}

	if(non_cs) {
		case_sensitive = 0;
	}

	/* class constant, check if there is name and make sure class is valid & exists */
	if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) {
		zend_error(E_WARNING, "Class constants cannot be defined or redefined");
		RETURN_FALSE;
	}

repeat:
	switch (Z_TYPE_P(val)) {
		case IS_LONG:
		case IS_DOUBLE:
		case IS_STRING:
		case IS_BOOL:
		case IS_RESOURCE:
		case IS_NULL:
			break;
		//上面,允许integer, float,string 或者 boolean和 null
		case IS_OBJECT:
			/* 如果传入的是对象, 通过判断是否定义__tostring()魔术方法,重新设置val值
			 * 可以看出,define已经接受对象作为参数,前提条件是定义了__tostring(),并且返回的值也是integer, float,string 或者 boolean和 null
			 * 此时,这里的版本是php5.3.8
			 * */
			if (!val_free) {
				if (Z_OBJ_HT_P(val)->get) {
					val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
					goto repeat;
				} else if (Z_OBJ_HT_P(val)->cast_object) {
					ALLOC_INIT_ZVAL(val_free);
					if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) {
						val = val_free;
						break;
					}
				}
			}
			/* no break */
		default:
			//其他类型则提示错误
			zend_error(E_WARNING,"Constants may only evaluate to scalar values");
			if (val_free) {
				zval_ptr_dtor(&val_free);
			}
			RETURN_FALSE;
	}
	
	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;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值