It also made pg_meta_data() return "is enum" always.
(Yasuo)
+- Core
+ . Expose get_debug_info class hook as __debugInfo() magic method. (Sara)
+
13 Feb 2014, PHP 5.6.0 Alpha 2
- Core:
. Added T_POW (**) operator
--- /dev/null
+--TEST--
+Testing __debugInfo() magic method
+--FILE--
+<?php
+
+class Foo {
+ public $d = 4;
+ protected $e = 5;
+ private $f = 6;
+
+ public function __debugInfo() {
+ return ['a'=>1, "\0*\0b"=>2, "\0Foo\0c"=>3];
+ }
+}
+
+$f = new Foo;
+var_dump($f);
+--EXPECT--
+object(Foo)#1 (3) {
+ ["a"]=>
+ int(1)
+ ["b":protected]=>
+ int(2)
+ ["c":"Foo":private]=>
+ int(3)
+}
union _zend_function *__call;
union _zend_function *__callstatic;
union _zend_function *__tostring;
+ union _zend_function *__debugInfo;
union _zend_function *serialize_func;
union _zend_function *unserialize_func;
!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && fptr->common.num_args != 0
) {
zend_error(error_type, "Method %s::%s() cannot take arguments", ce->name, ZEND_TOSTRING_FUNC_NAME);
+ } else if (name_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME) - 1 &&
+ !memcmp(lcname, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && fptr->common.num_args != 0) {
+ zend_error(error_type, "Method %s::%s() cannot take arguments", ce->name, ZEND_DEBUGINFO_FUNC_NAME);
}
}
/* }}} */
int count=0, unload=0;
HashTable *target_function_table = function_table;
int error_type;
- zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL;
+ zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL;
const char *lowercase_name;
int fname_len;
const char *lc_class_name = NULL;
__unset = reg_function;
} else if ((fname_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME) - 1)) {
__isset = reg_function;
+ } else if ((fname_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME) - 1)) {
+ __debugInfo = reg_function;
} else {
reg_function = NULL;
}
scope->__set = __set;
scope->__unset = __unset;
scope->__isset = __isset;
+ scope->__debugInfo = __debugInfo;
if (ctor) {
ctor->common.fn_flags |= ZEND_ACC_CTOR;
if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
}
__isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
}
+ if (__debugInfo) {
+ if (__debugInfo->common.fn_flags & ZEND_ACC_STATIC) {
+ zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __debugInfo->common.function_name);
+ }
+ }
efree((char*)lc_class_name);
}
return SUCCESS;
class_container.__set = handle_propset; \
class_container.__unset = handle_propunset; \
class_container.__isset = handle_propisset; \
+ class_container.__debugInfo = NULL; \
class_container.serialize_func = NULL; \
class_container.unserialize_func = NULL; \
class_container.serialize = NULL; \
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
}
+
+ } else if ((name_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __debugInfo() must have public visibility and cannot be static");
+ }
}
} else {
char *class_lcname;
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
}
+ } else if ((name_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __debugInfo() must have public visibility and cannot be static");
+ }
+ CG(active_class_entry)->__debugInfo = (zend_function *) CG(active_op_array);
} else if (!(fn_flags & ZEND_ACC_STATIC)) {
CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
}
ce->__callstatic = fe;
} else if (!strncmp(mname, ZEND_TOSTRING_FUNC_NAME, mname_len)) {
ce->__tostring = fe;
+ } else if (!strncmp(mname, ZEND_DEBUGINFO_FUNC_NAME, mname_len)) {
+ ce->__debugInfo = fe;
} else if (ce->name_length + 1 == mname_len) {
char *lowercase_name = emalloc(ce->name_length + 1);
zend_str_tolower_copy(lowercase_name, ce->name, ce->name_length);
#define ZEND_TOSTRING_FUNC_NAME "__tostring"
#define ZEND_AUTOLOAD_FUNC_NAME "__autoload"
#define ZEND_INVOKE_FUNC_NAME "__invoke"
+#define ZEND_DEBUGINFO_FUNC_NAME "__debuginfo"
/* The following constants may be combined in CG(compiler_options)
* to change the default compiler behavior */
ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
{
- *is_temp = 0;
- return zend_std_get_properties(object TSRMLS_CC);
+ zend_class_entry *ce = Z_OBJCE_P(object);
+ zval *retval = NULL;
+
+ if (!ce->__debugInfo) {
+ *is_temp = 0;
+ return Z_OBJ_HANDLER_P(object, get_properties)
+ ? Z_OBJ_HANDLER_P(object, get_properties)(object TSRMLS_CC)
+ : NULL;
+ }
+
+ zend_call_method_with_0_params(&object, ce, &ce->__debugInfo, ZEND_DEBUGINFO_FUNC_NAME, &retval);
+ if (retval && Z_TYPE_P(retval) == IS_ARRAY) {
+ HashTable *ht = Z_ARRVAL_P(retval);
+ if (Z_REFCOUNT_P(retval) <= 1) {
+ *is_temp = 1;
+ efree(retval);
+ return ht;
+ } else {
+ *is_temp = 0;
+ zval_ptr_dtor(&retval);
+ }
+ return ht;
+ }
+ if (retval && Z_TYPE_P(retval) == IS_NULL) {
+ zval ret;
+ array_init(&ret);
+ *is_temp = 1;
+ return Z_ARRVAL(ret);
+ }
+
+ zend_error_noreturn(E_ERROR, ZEND_DEBUGINFO_FUNC_NAME "() must return an array");
}
/* }}} */
zend_std_compare_objects, /* compare_objects */
zend_std_cast_object_tostring, /* cast_object */
NULL, /* count_elements */
- NULL, /* get_debug_info */
+ zend_std_get_debug_info, /* get_debug_info */
zend_std_get_closure, /* get_closure */
zend_std_get_gc, /* get_gc */
NULL, /* do_operation */