php define的第二个参数使用方法
2015-01-24信息快讯网
今天阅读php源码,发现define的第二个参数其实也可以是一个对象,我们来看看如何使用。
看手册说define定义的常量只允许:仅允许标量和 null。标量的类型是 integer, float,string 或者 boolean。 也能够定义常量值的类型为 resource ,但并不推荐这么做,可能会导致未知状况的发生。
今天阅读php源码,发现define的第二个参数其实也可以是一个对象。
先贴一段示例:
class A { public function __toString() { return 'bar'; } } $a = new A(); define('foo', $a); echo foo; // 输出bar
接着来看看php中的define究竟是如何实现的:
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种手段:
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中:
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。
PHP 面向对象程序设计(oop)学习笔记(一) - 抽象类、对象接口、instanceof 和契约式编程
在PHP中运行Linux命令并启动SSH服务的例子
php调用nginx的mod_zip模块打包ZIP文件
教你如何在CI框架中使用 .htaccess 隐藏url中index.php
PHP、Nginx、Apache中禁止网页被iframe引用的方法
PHP异常Parse error: syntax error, unexpected T_VAR错误解决方法
PHP FATAL ERROR: CALL TO UNDEFINED FUNCTION BCMUL()解决办法
PHP_NETWORK_GETADDRESSES: GETADDRINFO FAILED问题解决办法
php实现telnet功能示例
php警告Creating default object from empty value 问题的解决方法
分享下页面关键字抓取components.arrow.com站点代码
php preg_replace替换实例讲解
Linux编译升级php的详细方法
mac下安装nginx和php
php cURL和Rolling cURL并发方式比较
简单实用的.net DataTable导出Execl
php模拟ping命令(php exec函数的使用方法)
关于php程序报date()警告的处理(date_default_timezone_set)
PHP中include与require使用方法区别详解
php修改NetBeans默认字体的大小
如何使用PHP实现javascript的escape和unescape函数
浅析memcache启动以及telnet命令详解
解析php中static,const与define的使用区别
解析php中const与define的应用区别
探讨php define()函数及defined()函数使用详解
深入php define()函数以及defined()函数的用法详解