官方文檔宣稱 define 僅接受標量與 null,但原始碼實作支援實作 __toString 的物件。
<?php
class A {
public function __toString() {
return 'bar';
}
}
$a = new A();
define('foo', $a);
echo foo; // 輸出 bar
?>
關鍵邏輯在 switch (Z_TYPE_P(val)) 中的 IS_OBJECT 分支:
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");
// ... 返回 FALSE
get handler(取得物件值)cast_object handler 轉為字串cast_object 為 zend_std_cast_object_tostring,會呼叫 __toStringZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) {
switch (type) {
case IS_STRING:
ce = Z_OBJCE_P(readobj);
if (ce->__tostring &&
(zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
// 成功取得字串
}
return FAILURE;
}
return FAILURE;
}
define('CONST', $obj) 實際儲存的是 $obj->__toString() 的返回值