源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

php define的第二个参数使用方法

  • 时间:2020-04-21 18:46 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:php define的第二个参数使用方法
看手册说define定义的常量只允许: 仅允许标量和 null。标量的类型是 integer, float,string 或者 boolean。 也能够定义常量值的类型为 resource ,但并不推荐这么做,可能会导致未知状况的发生。 今天阅读php源码,发现define的第二个参数其实也可以是一个对象。 先贴一段示例:
[u]复制代码[/u] 代码如下:
class A {     public function __toString() {         return 'bar';     } } $a = new A(); define('foo', $a); echo foo; // 输出bar
接着来看看php中的define究竟是如何实现的:
[u]复制代码[/u] 代码如下:
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;     // 接收3个参数,string,zval,bool     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;     }     // 如果define类常量,则报错     if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) {         zend_error(E_WARNING, "Class constants cannot be defined or redefined");         RETURN_FALSE;     }     // 获取真正的值,用val保存 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 = 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;     } }
注意以repeat开始的一段循环,还用到了goto语句T_T 这段代码的作用为: 对于int,float,string,bool,resource,null,则实际定义的常量时直接使用这些值 对于object,则需要将object转成上述6个类型之一(如果转型之后依然是object,则继续转型) 如何将object成6个类型之一呢?从代码上看有2种手段:
[u]复制代码[/u] 代码如下:
if (Z_OBJ_HT_P(val)->get) {     val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);     goto repeat; } // __toString()方法会在cast_object中被调用 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;     } }
1,Z_OBJ_HT_P(val)->get ,宏展开之后为(*val).value.obj.handlers->get 2,Z_OBJ_HT_P(val)->cast_object,宏展开之后为(*val).value.obj.handlers->cast_object handlers是一个包含很多函数指针的结构体,具体定义参见_zend_object_handlers 。该结构体中的函数指针均用于操作object,比如读取/修改对象属性、获取/调用对象方法等等…get和cast_object也是其中之一。 对于一般的对象,php提供了标准的cast_object函数zend_std_cast_object_tostring,代码位于php-src/zend/zend-object-handlers.c中:
[u]复制代码[/u] 代码如下:
ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */ {     zval *retval;     zend_class_entry *ce;     switch (type) {         case IS_STRING:             ce = Z_OBJCE_P(readobj);             // 如果用户的class中定义了__toString,则尝试调用             if (ce->__tostring &&                 (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {                 ……             }             return FAILURE;         ……     }     return FAILURE; }
从上述具体实现来看,默认的cast_object就是去寻找class中的__tostring方法然后调用… 回到刚开始的例子,define(‘foo', $a) ,由于$a是A的实例,并且class A中定义了__toString,因此实际上foo常量就等于toString的返回值bar。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部