define() vs const 该如何选择?
使用 define(),除非考虑到可读性、类常量、或关注微优化
1、在 PHP 中是使用 define() 函数来定义常量,PHP 5.3.0 以后,PHP 中也能够使用 const 关键字来声明常量了,一个常量一旦被定义,就不能再改变或者取消定义
2、常量只能包含标量数据(boolean,integer,float 和 string)。可以定义 resource 常量,但应尽量避免,因为会造成不可预料的结果
3、可以简单的通过指定其名字来取得常量的值,与变量不同,不应该在常量前面加上 $ 符号。如果常量名是动态的,也可以用函数 constant() 来获取常量的值。用 get_defined_constants() 可以获得所有已定义的常量列表
Note: 常量和(全局)变量在不同的名字空间中。这意味着例如 TRUE 和 $TRUE 是不同的
常量和变量有如下不同
常量前面没有美元符号($);
常量只能用 define() 函数定义,而不能通过赋值语句;
常量可以不用理会变量的作用域而在任何地方定义和访问;
常量一旦定义就不能被重新定义或者取消定义;
常量的值只能是标量。
define vs const
1、define() 在执行期定义常量,使用 const 关键字定义常量必须处于最顶端的作用区域,因为用此方法是在编译时定义的,这就意味着不能在函数内,循环内以及 if 语句之内用 const 来定义常量,这样 const 就有轻微的速度优势, 但不值得考虑这个问题
2、define() 将常量放入全局作用域,虽然你可以在常量名中包含命名空间, 这意味着你不能使用 define() 定义类常量
3、define() 允许你在常量名和常量值中使用表达式,而 const 则都不允许,这使得 define() 更加灵活
示例
1、const不能使用条件表达式定义常量. 如果要定义一个全局常量,只能在表达式外面
if (...) {
const FOO = 'BAR'; // invalid
}
// but
if (...) {
define('FOO', 'BAR'); // valid
}
2、const 可以使用一个静态标量 (number, string or other constant like true, false, null, __FILE__), 反之define()没有限制.不过从 PHP 5.6 之后可以使用常量表达式
const BIT_5 = 1 << 5; // valid since PHP 5.6, invalid previously
define('BIT_5', 1 << 5); // always valid
3、const 使用一个普通的常量名称 反之define() 可以使用任意的常量表达式
for ($i = 0; $i < 32; ++$i) {
define('BIT_' . $i, 1 << $i);
}
4、const总是大小写敏感的, 反之define() 允许你定义一个大小写不敏感的常量通过第三个参数
define('FOO', 'BAR', true);
echo FOO; // BAR
echo foo; // BAR
5、const simply reads nicer. It's a language construct instead of a function and also is consistent with how you define constants in classes,const defines a constant in the current namespace, while define() has to be passed the full namespace name:
namespace A\B\C;
// To define the constant A\B\C\FOO:
const FOO = 'BAR';
define('A\B\C\FOO', 'BAR');
6、Since PHP 5.6 const constants can also be arrays, while define() does not support arrays yet. However arrays will be supported for both cases in PHP 7.
const FOO = [1, 2, 3]; // valid in PHP 5.6
define('FOO', [1, 2, 3]); // invalid in PHP 5.6, valid in PHP 7.0
As consts are language constructs and defined at compile time they are a bit faster than define().
It is well known that PHP define() are slow when using a large number of constants. People have even invented things like apc_load_constants() and hidef to get around this.
consts make the definition of constants approximately twice as fast (on development machines with XDebug turned on even more). Lookup time on the other hand does not change (as both constant types share the same lookup table)
Finally, note that const can also be used within a class or interface to define a class constant or interface constant. define cannot be used for this purpose:
class Foo {
const BAR = 2; // valid
}
// but
class Baz {
define('QUX', 2); // invalid
}
Summary
Unless you need any type of conditional or expressional definition, use consts instead of define()s - simply for the sake of readability!
<?php
// 来看看这两种方法如何处理 namespaces
namespace MiddleEarth\Creatures\Dwarves;
const GIMLI_ID = 1;
define('MiddleEarth\Creatures\Elves\LEGOLAS_ID', 2); echo(\MiddleEarth\Creatures\Dwarves\GIMLI_ID); // 1
echo(\MiddleEarth\Creatures\Elves\LEGOLAS_ID); // 2; 注意:我们使用了 define() // Now let's declare some bit-shifted constants representing ways to enter Mordor.
define('TRANSPORT_METHOD_SNEAKING', 1 << 0); // OK!
const TRANSPORT_METHOD_WALKING = 1 << 1; //Compile error! const can't use expressions as values // 接下来, 条件常量。
define('HOBBITS_FRODO_ID', 1); if($isGoingToMordor){
define('TRANSPORT_METHOD', TRANSPORT_METHOD_SNEAKING); // OK!
const PARTY_LEADER_ID = HOBBITS_FRODO_ID // 编译错误: const 不能用于 if 块中
} // 最后, 类常量
class OneRing{
const MELTING_POINT_DEGREES = 1000000; // OK!
define('SHOW_ELVISH_DEGREES', 200); // 编译错误: 在类内不能使用 define()
}
?>
无论你选择哪一种,请保持一致
看一下define在内核中如何实现的
/* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false)
Define a new constant */
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;
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;
case IS_OBJECT:
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 = IS_INTERNED(name) ? name : zend_strndup(name, name_len);
if(c.name == NULL) {
RETURN_FALSE;
}
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;
}
}
/* }}} */
/* {{{ proto bool defined(string constant_name)
Check whether a constant exists */
ZEND_FUNCTION(defined)
{
char *name;
int name_len;
zval c;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
return;
}
if (zend_get_constant_ex(name, name_len, &c, NULL, ZEND_FETCH_CLASS_SILENT TSRMLS_CC)) {
zval_dtor(&c);
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
const
ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
{
char *lowercase_name = NULL;
char *name;
int ret = SUCCESS;
ulong chash = 0; #if 0
printf("Registering constant for module %d\n", c->module_number);
#endif if (!(c->flags & CONST_CS)) {
/* keep in mind that c->name_len already contains the '\0' */
lowercase_name = estrndup(c->name, c->name_len-1);
zend_str_tolower(lowercase_name, c->name_len-1);
lowercase_name = (char*)zend_new_interned_string(lowercase_name, c->name_len, 1 TSRMLS_CC);
name = lowercase_name;
chash = IS_INTERNED(lowercase_name) ? INTERNED_HASH(lowercase_name) : 0;
} else {
char *slash = strrchr(c->name, '\\');
if(slash) {
lowercase_name = estrndup(c->name, c->name_len-1);
zend_str_tolower(lowercase_name, slash-c->name);
lowercase_name = (char*)zend_new_interned_string(lowercase_name, c->name_len, 1 TSRMLS_CC);
name = lowercase_name; chash = IS_INTERNED(lowercase_name) ? INTERNED_HASH(lowercase_name) : 0;
} else {
name = c->name;
}
}
if (chash == 0) {
chash = zend_hash_func(name, c->name_len);
} /* Check if the user is trying to define the internal pseudo constant name __COMPILER_HALT_OFFSET__ */
if ((c->name_len == sizeof("__COMPILER_HALT_OFFSET__")
&& !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1))
|| zend_hash_quick_add(EG(zend_constants), name, c->name_len, chash, (void *) c, sizeof(zend_constant), NULL)==FAILURE) { /* The internal __COMPILER_HALT_OFFSET__ is prefixed by NULL byte */
if (c->name[0] == '\0' && c->name_len > sizeof("\0__COMPILER_HALT_OFFSET__")
&& memcmp(name, "\0__COMPILER_HALT_OFFSET__", sizeof("\0__COMPILER_HALT_OFFSET__")) == 0) {
name++;
}
zend_error(E_NOTICE,"Constant %s already defined", name);
str_free(c->name);
if (!(c->flags & CONST_PERSISTENT)) {
zval_dtor(&c->value);
}
ret = FAILURE;
}
if (lowercase_name && !IS_INTERNED(lowercase_name)) {
efree(lowercase_name);
}
return ret;
}
参考
define() vs const 该如何选择?的更多相关文章
- #define、const、typedef的区别
#define.const.typedef的区别 #define 并不是定义变量, 只是用来做文本替换 例如: #define PI 3.1415926 float angel; angel=30*P ...
- IOS 基础-define、const、extern、全局变量
这里介绍一下define.const.extern的用法.优劣以及要注意的地方. 1.define 宏define是定义一个变量,没有类型信息.define定义的常量在内存中有若干个拷贝. defin ...
- #define和const的简单区别
面试常问:宏#define和const有什么区别? 1.编译器处理方式 define宏是在预处理阶段展开 const常量是在编译阶段使用 2.类型和安全检查不同 define宏没有类型,不做安全检查, ...
- PHP中定义常量define与const
我们通常把不经常变的值定义成常量,常量一般用全部大写来表示,前面不加美元符号,也可减少团队开发的出错.那么define和const有什么区别呢? 1.const是一个语言结构:而define是一个函数 ...
- 宏定义define和const的区别
define和const都可以用来定义常量,define的格式为:#define 标识符 字符串,const在定义常量前面,const类型定以后不能被修改,区别主要有如下几点: 1.编译器处理方式不同 ...
- iOS学习——#define、const、typedef的区别
在iOS开发中经常遇到一些字段和类型的定义,例如配置生产和测试不同环境的参数等,这时候经常用到#define.const以及typedef.那么它们之间有什么区别呢?我们接下来一个一个具体了解下. 一 ...
- PHP中的Define和Const区别
我们经常把不经常变的值定义成常量,常量一般用全部大写来表示,前面不加美元符号,那么define和const有什么区别呢? 常量是一个简单的标识符.在脚本执行期间该值不能改变(除了所谓的魔术常量,他们其 ...
- c++中typedef、define、const、inline之间的区别
1.typedef和#define的区别 typedef int* pInt; , b = ; const pInt p1 = &a; //p1是常量指针 pInt const p2 = &a ...
- 在php中define和const定义常量的区别
define和const都可以用来定义常量,但是const定义常量的时候大小写敏感,而define可以通过设置第三个参数为true的时候来取消大小写敏感! 如图: 引用地址:点这里
随机推荐
- javax.mail 遇到501 mail from address must be same as authorization user 的問題
使用不同的兩個帳戶发送email时,第一个账户可以发送成功,但到第二个账户的时候就报出了501 mail from address must be same as authorization user ...
- Android中RelativeLayout和LinearLayout性能分析
先看一些现象吧:用eclipse或者Android studio,新建一个Activity自动生成的布局文件都是RelativeLayout,或许你会认为这是IDE的默认设置问题,其实不然,这是由 a ...
- jenkins error: "no valid crumb was included in the request"
一.问题描述(Problem Description): 在jenkins中创建新任务时候选择“拷贝已存在任务”,点击OK,跳转到下一步时候弹出如下错误信息:"No valid crumb ...
- 安装在virtualbox中的kali linux如何配置无线网卡
1.安装在virtualbox里的kali无法使用所在物理机的wifi 2.必须通过usb方式,如图所示 3.所使用的usb无线网卡必须是kali2.0支持的 4.我的型号是TL-WN823N 2.0 ...
- 【POJ】【3525】Most Distant Point from the Sea
二分+计算几何/半平面交 半平面交的学习戳这里:http://blog.csdn.net/accry/article/details/6070621 然而这题是要二分长度r……用每条直线的距离为r的平 ...
- xp局域网共享设置
xp在局域网内的每一台机子做以下一些设置:1.启用Guest(来宾)帐户:控制面板--用户帐户或者在管理工具--计算机管理--本地用户和组--右键Guest属性--去掉帐户已停用 前的勾.2.允许Gu ...
- 第四章 第一个rabbitmq程序
rabbitmq消息发送模型 要素: 生产者 消费者 交换器:生产者将消息发送到交换器 队列:交换器通过某种路由规则绑定到指定队列,将消息加入队列,消费者从队列消费消息 前提: 引入rabbitmq的 ...
- SqlServer2008安装时系统配置检查器重新启动计算机失败
系统:win7 64 旗舰版 软件版本:sqlserver 2008 在安装前执行:系统配置检查器 的时候报错 ‘重新启动计算机失败’,如下图 处理办法: RebootRequiredCheck ...
- Discuz常见大问题-如何开启和使用首页四格
在论坛-首页四格中,勾选开启首页四格,然后可以选择数据来源的板块 注意首页四格刷新是有时间的,5分钟左右,不是你这里更新完了帖子那里就有了(如果你自己建的网站,可能回复和热帖都还没有) 当然你也可以使 ...
- 深夜闲聊节目:华为 Mate7的指纹识别安全么?
许久没有写过不论什么东西,近期非常忙并且还要准备找工作之类的,唉... ....今天的文章也不说技术,仅仅是闲聊. 一.手机指纹识别一揽 打开非常多站点.论坛的科技栏目,充斥着各种手机讯息!仿佛手机已 ...