Implemented the RFC Support Class Constant Visibility.

Squashed commit of the following:

commit f11ca0e7a5
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Tue Dec 8 12:38:42 2015 +0300

    Fixed test expectation

commit 211f873f54
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Tue Dec 8 12:28:38 2015 +0300

    Embed zend_class_constant.flags into zend_class_constants.value.u2.access_flags

commit 51deab84b2
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Mon Dec 7 11:18:55 2015 +0300

    Fixed issues found by Nikita

commit 544dbd5b47
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Sat Dec 5 02:41:05 2015 +0300

    Refactored immplementation of https://wiki.php.net/rfc/class_const_visibility
    @reeze created an RFC here and I emailed internals here and didn't get any responses positive/negative.
This commit is contained in:
Dmitry Stogov 2015-12-08 12:40:42 +03:00
parent a8b7d0c29d
commit a75c195000
40 changed files with 1143 additions and 126 deletions

View File

@ -1129,12 +1129,13 @@ ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */
zend_class_entry **scope = EG(current_execute_data) ? &EG(scope) : &CG(active_class_entry);
zend_class_entry *old_scope = *scope;
zend_class_entry *ce;
zend_class_constant *c;
zval *val;
zend_property_info *prop_info;
*scope = class_type;
ZEND_HASH_FOREACH_VAL(&class_type->constants_table, val) {
ZVAL_DEREF(val);
ZEND_HASH_FOREACH_PTR(&class_type->constants_table, c) {
val = &c->value;
if (Z_CONSTANT_P(val)) {
if (UNEXPECTED(zval_update_constant_ex(val, 1, class_type) != SUCCESS)) {
return FAILURE;
@ -3737,16 +3738,49 @@ ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *nam
}
/* }}} */
ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value) /* {{{ */
ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment) /* {{{ */
{
zend_class_constant *c;
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
if (access_type != ZEND_ACC_PUBLIC) {
zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface constant %s::%s must be public", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
}
if (zend_string_equals_literal_ci(name, "class")) {
zend_error((ce->type == ZEND_INTERNAL_CLASS) ? E_CORE_ERROR : E_COMPILE_ERROR,
"A class constant must not be called 'class'; it is reserved for class name fetching");
}
if (ce->type == ZEND_INTERNAL_CLASS) {
c = pemalloc(sizeof(zend_class_constant), 1);
} else {
c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
}
ZVAL_COPY_VALUE(&c->value, value);
Z_ACCESS_FLAGS(c->value) = access_type;
c->doc_comment = doc_comment;
c->ce = ce;
if (Z_CONSTANT_P(value)) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
return zend_hash_str_update(&ce->constants_table, name, name_length, value) ?
return zend_hash_add_ptr(&ce->constants_table, name, c) ?
SUCCESS : FAILURE;
}
/* }}} */
ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value) /* {{{ */
{
int ret;
zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS);
ret = zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(key);
return ret;
}
/* }}} */
ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length) /* {{{ */
{
zval constant;

View File

@ -324,6 +324,7 @@ ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name
ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type);
ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type);
ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment);
ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value);
ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length);
ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value);

View File

@ -124,7 +124,6 @@ enum _zend_ast_kind {
ZEND_AST_SWITCH,
ZEND_AST_SWITCH_CASE,
ZEND_AST_DECLARE,
ZEND_AST_CONST_ELEM,
ZEND_AST_USE_TRAIT,
ZEND_AST_TRAIT_PRECEDENCE,
ZEND_AST_METHOD_REFERENCE,
@ -142,6 +141,7 @@ enum _zend_ast_kind {
ZEND_AST_CATCH,
ZEND_AST_PARAM,
ZEND_AST_PROP_ELEM,
ZEND_AST_CONST_ELEM,
/* 4 child nodes */
ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT,

View File

@ -97,6 +97,12 @@ static void zend_destroy_property_info_internal(zval *zv) /* {{{ */
}
/* }}} */
static void zend_destroy_class_constant_internal(zval *zv) /* {{{ */
{
free(Z_PTR_P(zv));
}
/* }}} */
static zend_string *zend_new_interned_string_safe(zend_string *str) /* {{{ */ {
zend_string *interned_str;
@ -1437,14 +1443,15 @@ static zend_bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_a
static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */
{
uint32_t fetch_type = zend_get_class_fetch_type(class_name);
zend_class_constant *cc;
zval *c;
if (class_name_refers_to_active_ce(class_name, fetch_type)) {
c = zend_hash_find(&CG(active_class_entry)->constants_table, name);
cc = zend_hash_find_ptr(&CG(active_class_entry)->constants_table, name);
} else if (fetch_type == ZEND_FETCH_CLASS_DEFAULT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
zend_class_entry *ce = zend_hash_find_ptr_lc(CG(class_table), ZSTR_VAL(class_name), ZSTR_LEN(class_name));
if (ce) {
c = zend_hash_find(&ce->constants_table, name);
cc = zend_hash_find_ptr(&ce->constants_table, name);
} else {
return 0;
}
@ -1456,8 +1463,14 @@ static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name,
return 0;
}
if (!cc || !zend_verify_const_access(cc, CG(active_class_entry))) {
return 0;
}
c = &cc->value;
/* Substitute case-sensitive (or lowercase) persistent class constants */
if (c && Z_TYPE_P(c) < IS_OBJECT) {
if (Z_TYPE_P(c) < IS_OBJECT) {
ZVAL_DUP(zv, c);
return 1;
}
@ -1638,7 +1651,6 @@ again:
ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers) /* {{{ */
{
zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0;
dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR);
ce->refcount = 1;
ce->ce_flags = ZEND_ACC_CONSTANTS_UPDATED;
@ -1650,7 +1662,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
ce->default_properties_table = NULL;
ce->default_static_members_table = NULL;
zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : NULL), persistent_hashes, 0);
zend_hash_init_ex(&ce->constants_table, 8, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
zend_hash_init_ex(&ce->constants_table, 8, NULL, (persistent_hashes ? zend_destroy_class_constant_internal : NULL), persistent_hashes, 0);
zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0);
if (ce->type == ZEND_INTERNAL_CLASS) {
@ -5183,25 +5195,28 @@ void zend_compile_class_const_decl(zend_ast *ast) /* {{{ */
zend_ast *const_ast = list->child[i];
zend_ast *name_ast = const_ast->child[0];
zend_ast *value_ast = const_ast->child[1];
zend_ast *doc_comment_ast = const_ast->child[2];
zend_string *name = zend_ast_get_str(name_ast);
zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
zval value_zv;
if (zend_string_equals_literal_ci(name, "class")) {
zend_error(E_COMPILE_ERROR,
"A class constant must not be called 'class'; it is reserved for class name fetching");
if (UNEXPECTED(ast->attr & (ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT|ZEND_ACC_FINAL))) {
if (ast->attr & ZEND_ACC_STATIC) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'static' as constant modifier");
} else if (ast->attr & ZEND_ACC_ABSTRACT) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'abstract' as constant modifier");
} else if (ast->attr & ZEND_ACC_FINAL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'final' as constant modifier");
}
}
zend_const_expr_to_zval(&value_zv, value_ast);
name = zend_new_interned_string_safe(name);
if (zend_hash_add(&ce->constants_table, name, &value_zv) == NULL) {
if (zend_declare_class_constant_ex(ce, name, &value_zv, ast->attr, doc_comment) != SUCCESS) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redefine class constant %s::%s",
ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
if (Z_CONSTANT(value_zv)) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
}
}
/* }}} */

View File

@ -310,6 +310,12 @@ typedef struct _zend_property_info {
#define OBJ_PROP_TO_NUM(offset) \
((offset - OBJ_PROP_TO_OFFSET(0)) / sizeof(zval))
typedef struct _zend_class_constant {
zval value; /* access flags are stored in reserved: zval.u2.access_flags */
zend_string *doc_comment;
zend_class_entry *ce;
} zend_class_constant;
/* arg_info for internal functions */
typedef struct _zend_internal_arg_info {
const char *name;

View File

@ -251,6 +251,18 @@ static zend_constant *zend_get_special_constant(const char *name, size_t name_le
}
}
ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry *scope) /* {{{ */
{
if (Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PUBLIC) {
return 1;
} else if (Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PRIVATE) {
return (c->ce == scope);
} else {
ZEND_ASSERT(Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PROTECTED);
return zend_check_protected(c->ce, scope);
}
}
/* }}} */
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
{
@ -360,16 +372,23 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope,
}
free_alloca(lcname, use_heap);
if (ce) {
ret_constant = zend_hash_find(&ce->constants_table, constant_name);
if (ret_constant == NULL) {
zend_class_constant *c = zend_hash_find_ptr(&ce->constants_table, constant_name);
if (c == NULL) {
if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
zend_throw_error(NULL, "Undefined class constant '%s::%s'", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
zend_string_release(class_name);
zend_string_free(constant_name);
return NULL;
}
} else if (Z_ISREF_P(ret_constant)) {
ret_constant = Z_REFVAL_P(ret_constant);
ret_constant = NULL;
} else {
if (!zend_verify_const_access(c, scope)) {
zend_throw_error(NULL, "Cannot access %s const %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
zend_string_release(class_name);
zend_string_free(constant_name);
return NULL;
}
ret_constant = &c->value;
}
}
zend_string_release(class_name);

View File

@ -65,6 +65,7 @@ int zend_startup_constants(void);
int zend_shutdown_constants(void);
void zend_register_standard_constants(void);
void clean_non_persistent_constants(void);
ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry *ce);
ZEND_API zval *zend_get_constant(zend_string *name);
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len);
ZEND_API zval *zend_get_constant_ex(zend_string *name, zend_class_entry *scope, uint32_t flags);

View File

@ -698,21 +698,29 @@ ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_
}
/* }}} */
static void do_inherit_class_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
{
if (!zend_hash_exists(&ce->constants_table, name)) {
if (!Z_ISREF_P(zv)) {
if (parent_ce->type == ZEND_INTERNAL_CLASS) {
ZVAL_NEW_PERSISTENT_REF(zv, zv);
} else {
ZVAL_NEW_REF(zv, zv);
zend_class_constant *c = zend_hash_find_ptr(&ce->constants_table, name);
if (c != NULL) {
if (UNEXPECTED((Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PPP_MASK) > (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PPP_MASK))) {
zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s",
ZSTR_VAL(ce->name), ZSTR_VAL(name), zend_visibility_string(Z_ACCESS_FLAGS(parent_const->value)), ZSTR_VAL(ce->parent->name), (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PUBLIC) ? "" : " or weaker");
}
}
if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
} else if (!(Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PRIVATE)) {
if (Z_CONSTANT(parent_const->value)) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
Z_ADDREF_P(zv);
_zend_hash_append(&ce->constants_table, name, zv);
if (Z_REFCOUNTED(parent_const->value)) {
Z_ADDREF(parent_const->value);
}
if (ce->type & ZEND_INTERNAL_CLASS) {
c = pemalloc(sizeof(zend_class_constant), 1);
} else {
c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
}
memcpy(c, parent_const, sizeof(zend_class_constant));
_zend_hash_append_ptr(&ce->constants_table, name, c);
}
}
/* }}} */
@ -722,7 +730,6 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
zend_property_info *property_info;
zend_function *func;
zend_string *key;
zval *zv;
if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) {
/* Interface can only inherit other interfaces */
@ -859,12 +866,14 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
}
if (zend_hash_num_elements(&parent_ce->constants_table)) {
zend_class_constant *c;
zend_hash_extend(&ce->constants_table,
zend_hash_num_elements(&ce->constants_table) +
zend_hash_num_elements(&parent_ce->constants_table), 0);
ZEND_HASH_FOREACH_STR_KEY_VAL(&parent_ce->constants_table, key, zv) {
do_inherit_class_constant(key, zv, ce, parent_ce);
ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
do_inherit_class_constant(key, c, ce);
} ZEND_HASH_FOREACH_END();
}
@ -894,14 +903,12 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
}
/* }}} */
static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zval *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zend_class_constant *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
{
zval *old_constant;
zend_class_constant *old_constant;
if ((old_constant = zend_hash_find(child_constants_table, name)) != NULL) {
if (!Z_ISREF_P(old_constant) ||
!Z_ISREF_P(parent_constant) ||
Z_REFVAL_P(old_constant) != Z_REFVAL_P(parent_constant)) {
if ((old_constant = zend_hash_find_ptr(child_constants_table, name)) != NULL) {
if (old_constant->ce != parent_constant->ce) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", ZSTR_VAL(name), ZSTR_VAL(iface->name));
}
return 0;
@ -910,21 +917,16 @@ static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zva
}
/* }}} */
static void do_inherit_iface_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
{
if (do_inherit_constant_check(&ce->constants_table, zv, name, iface)) {
if (!Z_ISREF_P(zv)) {
if (iface->type == ZEND_INTERNAL_CLASS) {
ZVAL_NEW_PERSISTENT_REF(zv, zv);
} else {
ZVAL_NEW_REF(zv, zv);
if (do_inherit_constant_check(&ce->constants_table, c, name, iface)) {
if (Z_REFCOUNTED(c->value)) {
Z_ADDREF(c->value);
}
}
Z_ADDREF_P(zv);
if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
if (Z_CONSTANT(c->value)) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
zend_hash_update(&ce->constants_table, name, zv);
zend_hash_update_ptr(&ce->constants_table, name, c);
}
}
/* }}} */
@ -936,7 +938,7 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
zend_function *func;
zend_string *key;
zval *zv;
zend_class_constant *c;
for (i = 0; i < ce->num_interfaces; i++) {
if (ce->interfaces[i] == NULL) {
@ -952,8 +954,8 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
}
if (ignore) {
/* Check for attempt to redeclare interface constants */
ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, zv) {
do_inherit_constant_check(&iface->constants_table, zv, key, iface);
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
do_inherit_constant_check(&iface->constants_table, c, key, iface);
} ZEND_HASH_FOREACH_END();
} else {
if (ce->num_interfaces >= current_iface_num) {
@ -965,8 +967,8 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
}
ce->interfaces[ce->num_interfaces++] = iface;
ZEND_HASH_FOREACH_STR_KEY_VAL(&iface->constants_table, key, zv) {
do_inherit_iface_constant(key, zv, ce, iface);
ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
do_inherit_iface_constant(key, c, ce, iface);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {

View File

@ -701,8 +701,8 @@ class_statement_list:
class_statement:
variable_modifiers property_list ';'
{ $$ = $2; $$->attr = $1; }
| T_CONST class_const_list ';'
{ $$ = $2; RESET_DOC_COMMENT(); }
| method_modifiers T_CONST class_const_list ';'
{ $$ = $3; $$->attr = $1; }
| T_USE name_list trait_adaptations
{ $$ = zend_ast_create(ZEND_AST_USE_TRAIT, $2, $3); }
| method_modifiers function returns_ref identifier '(' parameter_list ')'
@ -810,11 +810,11 @@ class_const_list:
;
class_const_decl:
identifier '=' expr { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3); }
identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); }
;
const_decl:
T_STRING '=' expr { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3); }
T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); }
;
echo_expr_list:

View File

@ -287,7 +287,17 @@ ZEND_API void destroy_zend_class(zval *zv)
zend_hash_destroy(&ce->properties_info);
zend_string_release(ce->name);
zend_hash_destroy(&ce->function_table);
if (zend_hash_num_elements(&ce->constants_table)) {
zend_class_constant *c;
ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
zval_ptr_dtor(&c->value);
if (c->doc_comment && c->ce == ce) {
zend_string_release(c->doc_comment);
}
} ZEND_HASH_FOREACH_END();
zend_hash_destroy(&ce->constants_table);
}
if (ce->num_interfaces > 0 && ce->interfaces) {
efree(ce->interfaces);
}
@ -322,7 +332,17 @@ ZEND_API void destroy_zend_class(zval *zv)
zend_hash_destroy(&ce->properties_info);
zend_string_release(ce->name);
zend_hash_destroy(&ce->function_table);
if (zend_hash_num_elements(&ce->constants_table)) {
zend_class_constant *c;
ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
zval_internal_ptr_dtor(&c->value);
if (c->doc_comment && c->ce == ce) {
zend_string_release(c->doc_comment);
}
} ZEND_HASH_FOREACH_END();
zend_hash_destroy(&ce->constants_table);
}
if (ce->num_interfaces > 0) {
free(ce->interfaces);
}

View File

@ -138,6 +138,7 @@ struct _zval_struct {
uint32_t num_args; /* arguments number for EX(This) */
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
uint32_t access_flags; /* class constant access flags */
} u2;
};
@ -361,6 +362,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
#define Z_FE_ITER(zval) (zval).u2.fe_iter_idx
#define Z_FE_ITER_P(zval_p) Z_FE_ITER(*(zval_p))
#define Z_ACCESS_FLAGS(zval) (zval).u2.access_flags
#define Z_ACCESS_FLAGS_P(zval_p) Z_ACCESS_FLAGS(*(zval_p))
#define Z_COUNTED(zval) (zval).value.counted
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))

View File

@ -5163,6 +5163,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED, CONST, CONST_FETCH)
ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED, CONST)
{
zend_class_entry *ce;
zend_class_constant *c;
zval *value;
USE_OPLINE
@ -5172,7 +5173,6 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED, CONST)
if (OP1_TYPE == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
ZVAL_DEREF(value);
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
#endif
@ -5200,13 +5200,16 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED, CONST)
ce = Z_CE_P(EX_VAR(opline->op1.var));
}
if ((value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce)) != NULL) {
ZVAL_DEREF(value);
break;
}
}
if (EXPECTED((value = zend_hash_find(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
ZVAL_DEREF(value);
if (EXPECTED((c = zend_hash_find_ptr(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
if (!zend_verify_const_access(c, EG(scope))) {
zend_throw_error(NULL, "Cannot access %s const %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(ce->name), Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
}
value = &c->value;
if (Z_CONSTANT_P(value)) {
EG(scope) = ce;
zval_update_constant_ex(value, 1, NULL);

View File

@ -5824,6 +5824,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CASE_SPEC_CONST_CONST_HANDLER(
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_class_entry *ce;
zend_class_constant *c;
zval *value;
USE_OPLINE
@ -5833,7 +5834,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
if (IS_CONST == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
ZVAL_DEREF(value);
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
#endif
@ -5861,13 +5861,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
ce = Z_CE_P(EX_VAR(opline->op1.var));
}
if ((value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce)) != NULL) {
ZVAL_DEREF(value);
break;
}
}
if (EXPECTED((value = zend_hash_find(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
ZVAL_DEREF(value);
if (EXPECTED((c = zend_hash_find_ptr(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
if (!zend_verify_const_access(c, EG(scope))) {
zend_throw_error(NULL, "Cannot access %s const %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(ce->name), Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
}
value = &c->value;
if (Z_CONSTANT_P(value)) {
EG(scope) = ce;
zval_update_constant_ex(value, 1, NULL);
@ -17546,6 +17549,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_class_entry *ce;
zend_class_constant *c;
zval *value;
USE_OPLINE
@ -17555,7 +17559,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
if (IS_VAR == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
ZVAL_DEREF(value);
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
#endif
@ -17583,13 +17586,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
ce = Z_CE_P(EX_VAR(opline->op1.var));
}
if ((value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce)) != NULL) {
ZVAL_DEREF(value);
break;
}
}
if (EXPECTED((value = zend_hash_find(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
ZVAL_DEREF(value);
if (EXPECTED((c = zend_hash_find_ptr(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
if (!zend_verify_const_access(c, EG(scope))) {
zend_throw_error(NULL, "Cannot access %s const %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(ce->name), Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
}
value = &c->value;
if (Z_CONSTANT_P(value)) {
EG(scope) = ce;
zval_update_constant_ex(value, 1, NULL);
@ -23883,8 +23889,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
object = Z_OBJ(EX(This));
}
if (!object) {
ce = object->ce;
} else {
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
/* Allowed for PHP 4 compatibility. */
zend_error(
@ -23969,6 +23975,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CON
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_class_entry *ce;
zend_class_constant *c;
zval *value;
USE_OPLINE
@ -23978,7 +23985,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
if (IS_UNUSED == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
ZVAL_DEREF(value);
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
#endif
@ -24006,13 +24012,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
ce = Z_CE_P(EX_VAR(opline->op1.var));
}
if ((value = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), ce)) != NULL) {
ZVAL_DEREF(value);
break;
}
}
if (EXPECTED((value = zend_hash_find(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
ZVAL_DEREF(value);
if (EXPECTED((c = zend_hash_find_ptr(&ce->constants_table, Z_STR_P(EX_CONSTANT(opline->op2)))) != NULL)) {
if (!zend_verify_const_access(c, EG(scope))) {
zend_throw_error(NULL, "Cannot access %s const %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(ce->name), Z_STRVAL_P(EX_CONSTANT(opline->op2)));
HANDLE_EXCEPTION();
}
value = &c->value;
if (Z_CONSTANT_P(value)) {
EG(scope) = ce;
zval_update_constant_ex(value, 1, NULL);
@ -25234,8 +25243,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
object = Z_OBJ(EX(This));
}
if (!object) {
ce = object->ce;
} else {
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
/* Allowed for PHP 4 compatibility. */
zend_error(
@ -26592,8 +26601,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
object = Z_OBJ(EX(This));
}
if (!object) {
ce = object->ce;
} else {
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
/* Allowed for PHP 4 compatibility. */
zend_error(
@ -28225,8 +28234,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
if (Z_OBJ(EX(This)) && instanceof_function(Z_OBJCE(EX(This)), ce)) {
object = Z_OBJ(EX(This));
}
if (!object) {
ce = object->ce;
} else {
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
/* Allowed for PHP 4 compatibility. */
zend_error(

View File

@ -324,11 +324,13 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
if (ce) {
uint32_t tv = ZEND_RESULT(opline).var;
zend_class_constant *cc;
zval *c, t;
if ((c = zend_hash_find(&ce->constants_table,
Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL) {
ZVAL_DEREF(c);
if ((cc = zend_hash_find_ptr(&ce->constants_table,
Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL &&
(Z_ACCESS_FLAGS(cc->value) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
c = &cc->value;
if (Z_TYPE_P(c) == IS_CONSTANT_AST) {
break;
}

View File

@ -230,6 +230,7 @@ static void zend_hash_clone_constants(HashTable *ht, HashTable *source)
{
Bucket *p, *q, *end;
zend_ulong nIndex;
zend_class_constant *c;
ht->nTableSize = source->nTableSize;
ht->nTableMask = source->nTableMask;
@ -265,8 +266,14 @@ static void zend_hash_clone_constants(HashTable *ht, HashTable *source)
q->key = p->key;
/* Copy data */
ZVAL_COPY_VALUE(&q->val, &p->val);
zend_clone_zval(&q->val);
c = ARENA_REALLOC(Z_PTR(p->val));
ZVAL_PTR(&q->val, c);
zend_clone_zval(&c->value);
if ((void*)c->ce >= ZCG(current_persistent_script)->arena_mem &&
(void*)c->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
c->ce = ARENA_REALLOC(c->ce);
}
}
}

View File

@ -508,6 +508,28 @@ static void zend_file_cache_serialize_prop_info(zval *zv,
}
}
static void zend_file_cache_serialize_class_constant(zval *zv,
zend_persistent_script *script,
zend_file_cache_metainfo *info,
void *buf)
{
if (!IS_SERIALIZED(Z_PTR_P(zv))) {
zend_class_constant *c;
SERIALIZE_PTR(Z_PTR_P(zv));
c = Z_PTR_P(zv);
UNSERIALIZE_PTR(c);
zend_file_cache_serialize_zval(&c->value, script, info, buf);
if (c->ce && !IS_SERIALIZED(c->ce)) {
SERIALIZE_PTR(c->ce);
}
if (c->doc_comment && !IS_SERIALIZED(c->doc_comment)) {
SERIALIZE_STR(c->doc_comment);
}
}
}
static void zend_file_cache_serialize_class(zval *zv,
zend_persistent_script *script,
zend_file_cache_metainfo *info,
@ -545,7 +567,7 @@ static void zend_file_cache_serialize_class(zval *zv,
p++;
}
}
zend_file_cache_serialize_hash(&ce->constants_table, script, info, buf, zend_file_cache_serialize_zval);
zend_file_cache_serialize_hash(&ce->constants_table, script, info, buf, zend_file_cache_serialize_class_constant);
SERIALIZE_STR(ce->info.user.filename);
SERIALIZE_STR(ce->info.user.doc_comment);
zend_file_cache_serialize_hash(&ce->properties_info, script, info, buf, zend_file_cache_serialize_prop_info);
@ -1055,6 +1077,26 @@ static void zend_file_cache_unserialize_prop_info(zval *zv,
}
}
static void zend_file_cache_unserialize_class_constant(zval *zv,
zend_persistent_script *script,
void *buf)
{
if (!IS_UNSERIALIZED(Z_PTR_P(zv))) {
zend_class_constant *c;
UNSERIALIZE_PTR(Z_PTR_P(zv));
c = Z_PTR_P(zv);
zend_file_cache_unserialize_class_constant(&c->value, script, buf);
if (c->ce && !IS_UNSERIALIZED(c->ce)) {
UNSERIALIZE_PTR(c->ce);
}
if (c->doc_comment && !IS_UNSERIALIZED(c->doc_comment)) {
UNSERIALIZE_STR(c->doc_comment);
}
}
}
static void zend_file_cache_unserialize_class(zval *zv,
zend_persistent_script *script,
void *buf)
@ -1090,7 +1132,7 @@ static void zend_file_cache_unserialize_class(zval *zv,
}
}
zend_file_cache_unserialize_hash(&ce->constants_table,
script, buf, zend_file_cache_unserialize_zval, NULL);
script, buf, zend_file_cache_unserialize_class_constant, NULL);
UNSERIALIZE_STR(ce->info.user.filename);
UNSERIALIZE_STR(ce->info.user.doc_comment);
zend_file_cache_unserialize_hash(&ce->properties_info,

View File

@ -716,6 +716,39 @@ static void zend_persist_property_info(zval *zv)
}
}
static void zend_persist_class_constant(zval *zv)
{
zend_class_constant *c = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
if (c) {
Z_PTR_P(zv) = c;
return;
}
memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_class_constant));
zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem));
c = Z_PTR_P(zv) = ZCG(arena_mem);
ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_constant)));
zend_persist_zval(&c->value);
c->ce = zend_shared_alloc_get_xlat_entry(c->ce);
if (c->doc_comment) {
if (ZCG(accel_directives).save_comments) {
zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
if (doc_comment) {
c->doc_comment = doc_comment;
} else {
zend_accel_store_string(c->doc_comment);
}
} else {
zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
if (!doc_comment) {
zend_shared_alloc_register_xlat_entry(c->doc_comment, c->doc_comment);
zend_string_release(c->doc_comment);
}
c->doc_comment = NULL;
}
}
}
static void zend_persist_class_entry(zval *zv)
{
zend_class_entry *ce = Z_PTR_P(zv);
@ -745,7 +778,7 @@ static void zend_persist_class_entry(zval *zv)
}
ce->static_members_table = NULL;
zend_hash_persist(&ce->constants_table, zend_persist_zval);
zend_hash_persist(&ce->constants_table, zend_persist_class_constant);
if (ce->info.user.filename) {
/* do not free! PHP has centralized filename storage, compiler will free it */

View File

@ -292,6 +292,21 @@ static void zend_persist_property_info_calc(zval *zv)
}
}
static void zend_persist_class_constant_calc(zval *zv)
{
zend_class_constant *c = Z_PTR_P(zv);
if (!zend_shared_alloc_get_xlat_entry(c)) {
zend_shared_alloc_register_xlat_entry(c, c);
ADD_ARENA_SIZE(sizeof(zend_class_constant));
zend_persist_zval_calc(&c->value);
if (ZCG(accel_directives).save_comments && c->doc_comment) {
ADD_STRING(c->doc_comment);
}
}
}
static void zend_persist_class_entry_calc(zval *zv)
{
zend_class_entry *ce = Z_PTR_P(zv);
@ -316,7 +331,7 @@ static void zend_persist_class_entry_calc(zval *zv)
zend_persist_zval_calc(&ce->default_static_members_table[i]);
}
}
zend_hash_persist_calc(&ce->constants_table, zend_persist_zval_calc);
zend_hash_persist_calc(&ce->constants_table, zend_persist_class_constant_calc);
if (ce->info.user.filename) {
ADD_STRING(ce->info.user.filename);

View File

@ -64,6 +64,7 @@ PHPAPI zend_class_entry *reflection_class_ptr;
PHPAPI zend_class_entry *reflection_object_ptr;
PHPAPI zend_class_entry *reflection_method_ptr;
PHPAPI zend_class_entry *reflection_property_ptr;
PHPAPI zend_class_entry *reflection_class_constant_ptr;
PHPAPI zend_class_entry *reflection_extension_ptr;
PHPAPI zend_class_entry *reflection_zend_extension_ptr;
@ -215,7 +216,8 @@ typedef enum {
REF_TYPE_PARAMETER,
REF_TYPE_TYPE,
REF_TYPE_PROPERTY,
REF_TYPE_DYNAMIC_PROPERTY
REF_TYPE_DYNAMIC_PROPERTY,
REF_TYPE_CLASS_CONSTANT
} reflection_type_t;
/* Struct for reflection objects */
@ -333,7 +335,7 @@ static void reflection_free_objects_storage(zend_object *object) /* {{{ */
efree(intern->ptr);
break;
case REF_TYPE_GENERATOR:
break;
case REF_TYPE_CLASS_CONSTANT:
case REF_TYPE_OTHER:
break;
}
@ -368,6 +370,7 @@ static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{
static void _const_string(string *str, char *name, zval *value, char *indent);
static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char* indent);
static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent);
static void _class_const_string(string *str, char *name, zend_class_constant *c, char* indent);
static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent);
static void _extension_string(string *str, zend_module_entry *module, char *indent);
static void _zend_extension_string(string *str, zend_extension *extension, char *indent);
@ -450,11 +453,11 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
string_printf(str, "%s - Constants [%d] {\n", indent, count);
if (count > 0) {
zend_string *key;
zval *value;
zend_class_constant *c;
ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, value) {
zval_update_constant_ex(value, 1, NULL);
_const_string(str, ZSTR_VAL(key), value, indent);
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
zval_update_constant_ex(&c->value, 1, NULL);
_class_const_string(str, ZSTR_VAL(key), c, indent);
} ZEND_HASH_FOREACH_END();
}
string_printf(str, "%s }\n", indent);
@ -627,6 +630,20 @@ static void _const_string(string *str, char *name, zval *value, char *indent)
}
/* }}} */
/* {{{ _class_const_string */
static void _class_const_string(string *str, char *name, zend_class_constant *c, char *indent)
{
char *type = zend_zval_type_name(&c->value);
char *visibility = zend_visibility_string(Z_ACCESS_FLAGS(c->value));
zend_string *value_str = zval_get_string(&c->value);
string_printf(str, "%s Constant [ %s %s %s ] { %s }\n",
indent, visibility, type, name, ZSTR_VAL(value_str));
zend_string_release(value_str);
}
/* }}} */
/* {{{ _get_recv_opcode */
static zend_op* _get_recv_op(zend_op_array *op_array, uint32_t offset)
{
@ -1356,6 +1373,27 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info
}
/* }}} */
/* {{{ reflection_class_constant_factory */
static void reflection_class_constant_factory(zend_class_entry *ce, zend_string *name_str, zend_class_constant *constant, zval *object)
{
reflection_object *intern;
zval name;
zval classname;
ZVAL_STR_COPY(&name, name_str);
ZVAL_STR_COPY(&classname, ce->name);
reflection_instantiate(reflection_class_constant_ptr, object);
intern = Z_REFLECTION_P(object);
intern->ptr = constant;
intern->ref_type = REF_TYPE_CLASS_CONSTANT;
intern->ce = constant->ce;
intern->ignore_visibility = 0;
reflection_update_property(object, "name", &name);
reflection_update_property(object, "class", &classname);
}
/* }}} */
/* {{{ _reflection_export */
static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_ptr, int ctor_argc)
{
@ -3668,6 +3706,197 @@ ZEND_METHOD(reflection_method, setAccessible)
}
/* }}} */
/* {{{ proto public void ReflectionClassConstant::__construct(mixed class, string name)
Constructor. Throws an Exception in case the given class constant does not exist */
ZEND_METHOD(reflection_class_constant, __construct)
{
zval *classname, *object, name, cname;
zend_string *constname;
reflection_object *intern;
zend_class_entry *ce;
zend_class_constant *constant = NULL;
if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zS", &classname, &constname) == FAILURE) {
return;
}
object = getThis();
intern = Z_REFLECTION_P(object);
if (intern == NULL) {
return;
}
/* Find the class entry */
switch (Z_TYPE_P(classname)) {
case IS_STRING:
if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Class %s does not exist", Z_STRVAL_P(classname));
return;
}
break;
case IS_OBJECT:
ce = Z_OBJCE_P(classname);
break;
default:
_DO_THROW("The parameter class is expected to be either a string or an object");
/* returns out of this function */
}
if ((constant = zend_hash_find_ptr(&ce->constants_table, constname)) == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
return;
}
ZVAL_STR_COPY(&name, constname);
ZVAL_STR_COPY(&cname, ce->name);
intern->ptr = constant;
intern->ref_type = REF_TYPE_CLASS_CONSTANT;
intern->ce = constant->ce;
intern->ignore_visibility = 0;
reflection_update_property(object, "name", &name);
reflection_update_property(object, "class", &cname);
}
/* }}} */
/* {{{ proto public string ReflectionClassConstant::__toString()
Returns a string representation */
ZEND_METHOD(reflection_class_constant, __toString)
{
reflection_object *intern;
zend_class_constant *ref;
string str;
zval name;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(ref);
string_init(&str);
_default_get_entry(getThis(), "name", sizeof("name")-1, &name);
_class_const_string(&str, Z_STRVAL(name), ref, "");
zval_ptr_dtor(&name);
RETURN_NEW_STR(str.buf);
}
/* }}} */
/* {{{ proto public string ReflectionClassConstant::getName()
Returns the constant' name */
ZEND_METHOD(reflection_class_constant, getName)
{
if (zend_parse_parameters_none() == FAILURE) {
return;
}
_default_get_entry(getThis(), "name", sizeof("name")-1, return_value);
}
/* }}} */
static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
{
reflection_object *intern;
zend_class_constant *ref;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(ref);
RETURN_BOOL(Z_ACCESS_FLAGS(ref->value) & mask);
}
/* }}} */
/* {{{ proto public bool ReflectionClassConstant::isPublic()
Returns whether this constant is public */
ZEND_METHOD(reflection_class_constant, isPublic)
{
_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC);
}
/* }}} */
/* {{{ proto public bool ReflectionClassConstant::isPrivate()
Returns whether this constant is private */
ZEND_METHOD(reflection_class_constant, isPrivate)
{
_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
}
/* }}} */
/* {{{ proto public bool ReflectionClassConstant::isProtected()
Returns whether this constant is protected */
ZEND_METHOD(reflection_class_constant, isProtected)
{
_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
}
/* }}} */
/* {{{ proto public int ReflectionClassConstant::getModifiers()
Returns a bitfield of the access modifiers for this constant */
ZEND_METHOD(reflection_class_constant, getModifiers)
{
reflection_object *intern;
zend_class_constant *ref;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(ref);
RETURN_LONG(Z_ACCESS_FLAGS(ref->value));
}
/* }}} */
/* {{{ proto public mixed ReflectionClassConstant::getValue()
Returns this constant's value */
ZEND_METHOD(reflection_class_constant, getValue)
{
reflection_object *intern;
zend_class_constant *ref;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(ref);
ZVAL_DUP(return_value, &ref->value);
}
/* }}} */
/* {{{ proto public ReflectionClass ReflectionClassConstant::getDeclaringClass()
Get the declaring class */
ZEND_METHOD(reflection_class_constant, getDeclaringClass)
{
reflection_object *intern;
zend_class_constant *ref;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(ref);
zend_reflection_class_factory(ref->ce, return_value);
}
/* }}} */
/* {{{ proto public string ReflectionClassConstant::getDocComment()
Returns the doc comment for this constant */
ZEND_METHOD(reflection_class_constant, getDocComment)
{
reflection_object *intern;
zend_class_constant *ref;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(ref);
if (ref->doc_comment) {
RETURN_STR_COPY(ref->doc_comment);
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto public static mixed ReflectionClass::export(mixed argument [, bool return]) throws ReflectionException
Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHOD(reflection_class, export)
@ -4414,6 +4643,8 @@ ZEND_METHOD(reflection_class, getConstants)
{
reflection_object *intern;
zend_class_entry *ce;
zend_string *key;
zend_class_constant *c;
zval *val;
if (zend_parse_parameters_none() == FAILURE) {
@ -4421,12 +4652,36 @@ ZEND_METHOD(reflection_class, getConstants)
}
GET_REFLECTION_OBJECT_PTR(ce);
array_init(return_value);
ZEND_HASH_FOREACH_VAL(&ce->constants_table, val) {
if (UNEXPECTED(zval_update_constant_ex(val, 1, ce) != SUCCESS)) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
if (UNEXPECTED(zval_update_constant_ex(&c->value, 1, ce) != SUCCESS)) {
zend_array_destroy(Z_ARRVAL_P(return_value));
return;
}
val = zend_hash_add_new(Z_ARRVAL_P(return_value), key, &c->value);
Z_TRY_ADDREF_P(val);
} ZEND_HASH_FOREACH_END();
}
/* }}} */
/* {{{ proto public array ReflectionClass::getReflectionConstants()
Returns an associative array containing this class' constants as ReflectionClassConstant objects */
ZEND_METHOD(reflection_class, getReflectionConstants)
{
reflection_object *intern;
zend_class_entry *ce;
zend_string *name;
zend_class_constant *constant;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(ce);
array_init(return_value);
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, name, constant) {
zval class_const;
reflection_class_constant_factory(ce, name, constant, &class_const);
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &class_const);
} ZEND_HASH_FOREACH_END();
zend_hash_copy(Z_ARRVAL_P(return_value), &ce->constants_table, zval_add_ref_unref);
}
/* }}} */
@ -4436,7 +4691,7 @@ ZEND_METHOD(reflection_class, getConstant)
{
reflection_object *intern;
zend_class_entry *ce;
zval *value;
zend_class_constant *c;
zend_string *name;
METHOD_NOTSTATIC(reflection_class_ptr);
@ -4445,15 +4700,36 @@ ZEND_METHOD(reflection_class, getConstant)
}
GET_REFLECTION_OBJECT_PTR(ce);
ZEND_HASH_FOREACH_VAL(&ce->constants_table, value) {
if (UNEXPECTED(zval_update_constant_ex(value, 1, ce) != SUCCESS)) {
ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
if (UNEXPECTED(zval_update_constant_ex(&c->value, 1, ce) != SUCCESS)) {
return;
}
} ZEND_HASH_FOREACH_END();
if ((value = zend_hash_find(&ce->constants_table, name)) == NULL) {
if ((c = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) {
RETURN_FALSE;
}
ZVAL_DUP(return_value, value);
ZVAL_DUP(return_value, &c->value);
}
/* }}} */
/* {{{ proto public mixed ReflectionClass::getReflectionConstant(string name)
Returns the class' constant as ReflectionClassConstant objects */
ZEND_METHOD(reflection_class, getReflectionConstant)
{
reflection_object *intern;
zend_class_entry *ce;
zend_class_constant *constant;
zend_string *name;
GET_REFLECTION_OBJECT_PTR(ce);
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
return;
}
if ((constant = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) {
RETURN_FALSE;
}
reflection_class_constant_factory(ce, name, constant, return_value);
}
/* }}} */
@ -5171,6 +5447,14 @@ ZEND_METHOD(reflection_property, export)
}
/* }}} */
/* {{{ proto public static mixed ReflectionClassConstant::export(mixed class, string name [, bool return]) throws ReflectionException
Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHOD(reflection_class_constant, export)
{
_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_class_constant_ptr, 2);
}
/* }}} */
/* {{{ proto public void ReflectionProperty::__construct(mixed class, string name)
Constructor. Throws an Exception in case the given property does not exist */
ZEND_METHOD(reflection_property, __construct)
@ -6334,7 +6618,9 @@ static const zend_function_entry reflection_class_functions[] = {
ZEND_ME(reflection_class, getProperties, arginfo_reflection_class_getProperties, 0)
ZEND_ME(reflection_class, hasConstant, arginfo_reflection_class_hasConstant, 0)
ZEND_ME(reflection_class, getConstants, arginfo_reflection__void, 0)
ZEND_ME(reflection_class, getReflectionConstants, arginfo_reflection__void, 0)
ZEND_ME(reflection_class, getConstant, arginfo_reflection_class_getConstant, 0)
ZEND_ME(reflection_class, getReflectionConstant, arginfo_reflection_class_getConstant, 0)
ZEND_ME(reflection_class, getInterfaces, arginfo_reflection__void, 0)
ZEND_ME(reflection_class, getInterfaceNames, arginfo_reflection__void, 0)
ZEND_ME(reflection_class, isInterface, arginfo_reflection__void, 0)
@ -6426,6 +6712,33 @@ static const zend_function_entry reflection_property_functions[] = {
PHP_FE_END
};
ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_class_constant_export, 0, 0, 2)
ZEND_ARG_INFO(0, class)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, return)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_class_constant___construct, 0, 0, 2)
ZEND_ARG_INFO(0, class)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
static const zend_function_entry reflection_class_constant_functions[] = {
ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
ZEND_ME(reflection_class_constant, export, arginfo_reflection_class_constant_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC)
ZEND_ME(reflection_class_constant, __construct, arginfo_reflection_class_constant___construct, 0)
ZEND_ME(reflection_class_constant, __toString, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, getName, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, getValue, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, isPublic, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, isPrivate, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, isProtected, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, getModifiers, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, getDeclaringClass, arginfo_reflection__void, 0)
ZEND_ME(reflection_class_constant, getDocComment, arginfo_reflection__void, 0)
PHP_FE_END
};
ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_parameter_export, 0, 0, 2)
ZEND_ARG_INFO(0, function)
ZEND_ARG_INFO(0, parameter)
@ -6622,6 +6935,13 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
zend_declare_property_string(reflection_property_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC);
zend_declare_property_string(reflection_property_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC);
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionClassConstant", reflection_class_constant_functions);
_reflection_entry.create_object = reflection_objects_new;
reflection_class_constant_ptr = zend_register_internal_class(&_reflection_entry);
zend_class_implements(reflection_class_constant_ptr, 1, reflector_ptr);
zend_declare_property_string(reflection_class_constant_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC);
zend_declare_property_string(reflection_class_constant_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC);
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_STATIC", ZEND_ACC_STATIC);
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PUBLIC", ZEND_ACC_PUBLIC);
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PROTECTED", ZEND_ACC_PROTECTED);

View File

@ -15,7 +15,7 @@ Class [ <user> class Foo ] {
@@ %s017.php 2-4
- Constants [1] {
Constant [ string test ] { ok }
Constant [ public string test ] { ok }
}
- Static properties [0] {

View File

@ -0,0 +1,194 @@
--TEST--
Test usage of ReflectionClassConstant methods __toString(), export(), getName(), getValue(), isPublic(), isPrivate(), isProtected(), getModifiers(), getDeclaringClass() and getDocComment().
--FILE--
<?php
function reflectClassConstant($base, $constant) {
$constInfo = new ReflectionClassConstant($base, $constant);
echo "**********************************\n";
$class = is_object($base) ? get_class($base) : $base;
echo "Reflecting on class constant $class::$constant\n\n";
echo "__toString():\n";
var_dump($constInfo->__toString());
echo "export():\n";
var_dump(ReflectionClassConstant::export($base, $constant, true));
echo "export():\n";
var_dump(ReflectionClassConstant::export($base, $constant, false));
echo "getName():\n";
var_dump($constInfo->getName());
echo "getValue():\n";
var_dump($constInfo->getValue());
echo "isPublic():\n";
var_dump($constInfo->isPublic());
echo "isPrivate():\n";
var_dump($constInfo->isPrivate());
echo "isProtected():\n";
var_dump($constInfo->isProtected());
echo "getModifiers():\n";
var_dump($constInfo->getModifiers());
echo "getDeclaringClass():\n";
var_dump($constInfo->getDeclaringClass());
echo "getDocComment():\n";
var_dump($constInfo->getDocComment());
echo "\n**********************************\n";
}
class TestClass {
public const /** My Doc comment */ PUB = true;
/** Another doc comment */
protected const PROT = 4;
private const PRIV = "keepOut";
}
$instance = new TestClass();
reflectClassConstant("TestClass", "PUB");
reflectClassConstant("TestClass", "PROT");
reflectClassConstant("TestClass", "PRIV");
reflectClassConstant($instance, "PRIV");
reflectClassConstant($instance, "BAD_CONST");
?>
--EXPECTF--
**********************************
Reflecting on class constant TestClass::PUB
__toString():
string(42) " Constant [ public boolean PUB ] { 1 }
"
export():
string(42) " Constant [ public boolean PUB ] { 1 }
"
export():
Constant [ public boolean PUB ] { 1 }
NULL
getName():
string(3) "PUB"
getValue():
bool(true)
isPublic():
bool(true)
isPrivate():
bool(false)
isProtected():
bool(false)
getModifiers():
int(256)
getDeclaringClass():
object(ReflectionClass)#3 (1) {
["name"]=>
string(9) "TestClass"
}
getDocComment():
string(21) "/** My Doc comment */"
**********************************
**********************************
Reflecting on class constant TestClass::PROT
__toString():
string(46) " Constant [ protected integer PROT ] { 4 }
"
export():
string(46) " Constant [ protected integer PROT ] { 4 }
"
export():
Constant [ protected integer PROT ] { 4 }
NULL
getName():
string(4) "PROT"
getValue():
int(4)
isPublic():
bool(false)
isPrivate():
bool(false)
isProtected():
bool(true)
getModifiers():
int(512)
getDeclaringClass():
object(ReflectionClass)#3 (1) {
["name"]=>
string(9) "TestClass"
}
getDocComment():
string(26) "/** Another doc comment */"
**********************************
**********************************
Reflecting on class constant TestClass::PRIV
__toString():
string(49) " Constant [ private string PRIV ] { keepOut }
"
export():
string(49) " Constant [ private string PRIV ] { keepOut }
"
export():
Constant [ private string PRIV ] { keepOut }
NULL
getName():
string(4) "PRIV"
getValue():
string(7) "keepOut"
isPublic():
bool(false)
isPrivate():
bool(true)
isProtected():
bool(false)
getModifiers():
int(1024)
getDeclaringClass():
object(ReflectionClass)#3 (1) {
["name"]=>
string(9) "TestClass"
}
getDocComment():
bool(false)
**********************************
**********************************
Reflecting on class constant TestClass::PRIV
__toString():
string(49) " Constant [ private string PRIV ] { keepOut }
"
export():
string(49) " Constant [ private string PRIV ] { keepOut }
"
export():
Constant [ private string PRIV ] { keepOut }
NULL
getName():
string(4) "PRIV"
getValue():
string(7) "keepOut"
isPublic():
bool(false)
isPrivate():
bool(true)
isProtected():
bool(false)
getModifiers():
int(1024)
getDeclaringClass():
object(ReflectionClass)#3 (1) {
["name"]=>
string(9) "TestClass"
}
getDocComment():
bool(false)
**********************************
Fatal error: Uncaught ReflectionException: Class Constant TestClass::BAD_CONST does not exist in %s:%d
Stack trace:
#0 %s(%d): ReflectionClassConstant->__construct(Object(TestClass), 'BAD_CONST')
#1 %s(%d): reflectClassConstant(Object(TestClass), 'BAD_CONST')
#2 {main}
thrown in %s on line %d

View File

@ -12,9 +12,9 @@ echo $rc;
Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {
- Constants [3] {
Constant [ integer IS_IMPLICIT_ABSTRACT ] { 16 }
Constant [ integer IS_EXPLICIT_ABSTRACT ] { 32 }
Constant [ integer IS_FINAL ] { 4 }
Constant [ public integer IS_IMPLICIT_ABSTRACT ] { 16 }
Constant [ public integer IS_EXPLICIT_ABSTRACT ] { 32 }
Constant [ public integer IS_FINAL ] { 4 }
}
- Static properties [0] {
@ -34,7 +34,7 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {
Property [ <default> public $name ]
}
- Methods [50] {
- Methods [52] {
Method [ <internal:Reflection> final private method __clone ] {
- Parameters [0] {
@ -175,6 +175,12 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {
}
}
Method [ <internal:Reflection> public method getReflectionConstants ] {
- Parameters [0] {
}
}
Method [ <internal:Reflection> public method getConstant ] {
- Parameters [1] {
@ -182,6 +188,13 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {
}
}
Method [ <internal:Reflection> public method getReflectionConstant ] {
- Parameters [1] {
Parameter #0 [ <required> $name ]
}
}
Method [ <internal:Reflection> public method getInterfaces ] {
- Parameters [0] {

View File

@ -9,7 +9,7 @@ var_dump($ext->getClasses());
?>
==DONE==
--EXPECT--
array(14) {
array(15) {
["ReflectionException"]=>
object(ReflectionClass)#2 (1) {
["name"]=>
@ -70,13 +70,18 @@ array(14) {
["name"]=>
string(18) "ReflectionProperty"
}
["ReflectionExtension"]=>
["ReflectionClassConstant"]=>
object(ReflectionClass)#14 (1) {
["name"]=>
string(23) "ReflectionClassConstant"
}
["ReflectionExtension"]=>
object(ReflectionClass)#15 (1) {
["name"]=>
string(19) "ReflectionExtension"
}
["ReflectionZendExtension"]=>
object(ReflectionClass)#15 (1) {
object(ReflectionClass)#16 (1) {
["name"]=>
string(23) "ReflectionZendExtension"
}

View File

@ -20,11 +20,11 @@ Class [ <user> class just_constants ] {
@@ %s %d-%d
- Constants [5] {
Constant [ boolean BOOLEAN_CONSTANT ] { 1 }
Constant [ null NULL_CONSTANT ] { }
Constant [ string STRING_CONSTANT ] { This is a string }
Constant [ integer INTEGER_CONSTANT ] { 1000 }
Constant [ float FLOAT_CONSTANT ] { 3.14159265 }
Constant [ public boolean BOOLEAN_CONSTANT ] { 1 }
Constant [ public null NULL_CONSTANT ] { }
Constant [ public string STRING_CONSTANT ] { This is a string }
Constant [ public integer INTEGER_CONSTANT ] { 1000 }
Constant [ public float FLOAT_CONSTANT ] { 3.14159265 }
}
- Static properties [0] {

View File

@ -31,7 +31,7 @@ Object of class [ <user> class foo extends foo2 ] {
@@ %s 7-21
- Constants [1] {
Constant [ string BAR ] { foo's bar }
Constant [ public string BAR ] { foo's bar }
}
- Static properties [0] {

View File

@ -0,0 +1,34 @@
--TEST--
Class constants and doc comments
--INI--
opcache.save_comments=1
--FILE--
<?php
class X {
/** comment X1 */
const X1 = 1;
const X2 = 2;
/** comment X3 */
const X3 = 3;
}
class Y extends X {
/** comment Y1 */
const Y1 = 1;
const Y2 = 2;
/** comment Y3 */
const Y3 = 3;
}
$r = new ReflectionClass('Y');
foreach ($r->getReflectionConstants() as $rc) {
echo $rc->getName() . " : " . $rc->getDocComment() . "\n";
}
?>
--EXPECT--
Y1 : /** comment Y1 */
Y2 :
Y3 : /** comment Y3 */
X1 : /** comment X1 */
X2 :
X3 : /** comment X3 */

View File

@ -0,0 +1,23 @@
--TEST--
Class public constant visibility
--FILE--
<?php
class A {
public const publicConst = 'publicConst';
static function staticConstDump() {
var_dump(self::publicConst);
}
function constDump() {
var_dump(self::publicConst);
}
}
var_dump(A::publicConst);
A::staticConstDump();
(new A())->constDump();
?>
--EXPECTF--
string(11) "publicConst"
string(11) "publicConst"
string(11) "publicConst"

View File

@ -0,0 +1,30 @@
--TEST--
Class protected constant visibility
--FILE--
<?php
class A {
protected const protectedConst = 'protectedConst';
static function staticConstDump() {
var_dump(self::protectedConst);
}
function constDump() {
var_dump(self::protectedConst);
}
}
A::staticConstDump();
(new A())->constDump();
constant('A::protectedConst');
?>
--EXPECTF--
string(14) "protectedConst"
string(14) "protectedConst"
Warning: constant(): Couldn't find constant A::protectedConst in %s on line 14
Fatal error: Uncaught Error: Cannot access protected const A::protectedConst in %s:14
Stack trace:
#0 %s(14): constant('A::protectedCon...')
#1 {main}
thrown in %s on line 14

View File

@ -0,0 +1,30 @@
--TEST--
Class private constant visibility
--FILE--
<?php
class A {
private const privateConst = 'privateConst';
static function staticConstDump() {
var_dump(self::privateConst);
}
function constDump() {
var_dump(self::privateConst);
}
}
A::staticConstDump();
(new A())->constDump();
constant('A::privateConst');
?>
--EXPECTF--
string(12) "privateConst"
string(12) "privateConst"
Warning: constant(): Couldn't find constant A::privateConst in %s on line 14
Fatal error: Uncaught Error: Cannot access private const A::privateConst in %s:14
Stack trace:
#0 %s(14): constant('A::privateConst')
#1 {main}
thrown in %s on line 14

View File

@ -0,0 +1,28 @@
--TEST--
Only public and protected class constants should be inherited
--FILE--
<?php
class A {
public const X = 1;
protected const Y = 2;
private const Z = 3;
}
class B extends A {
static public function checkConstants() {
var_dump(self::X);
var_dump(self::Y);
var_dump(self::Z);
}
}
B::checkConstants();
?>
--EXPECTF--
int(1)
int(2)
Fatal error: Uncaught Error: Undefined class constant 'Z' in %s:11
Stack trace:
#0 %s(15): B::checkConstants()
#1 {main}
thrown in %s on line 11

View File

@ -0,0 +1,10 @@
--TEST--
Static constants are not allowed
--FILE--
<?php
class A {
static const X = 1;
}
?>
--EXPECTF--
Fatal error: Cannot use 'static' as constant modifier in %s on line 3

View File

@ -0,0 +1,11 @@
--TEST--
Abstract constants are not allowed
--FILE--
<?php
class A {
abstract const X = 1;
}
?>
--EXPECTF--
Fatal error: Cannot use 'abstract' as constant modifier in %s on line 3

View File

@ -0,0 +1,10 @@
--TEST--
Final constants are not allowed
--FILE--
<?php
class A {
final const X = 1;
}
?>
--EXPECTF--
Fatal error: Cannot use 'final' as constant modifier in %s on line 3

View File

@ -0,0 +1,16 @@
--TEST--
Class private constant visibility error
--FILE--
<?php
class A {
private const privateConst = 'privateConst';
}
var_dump(A::privateConst);
?>
--EXPECTF--
Fatal error: Uncaught Error: Cannot access private const A::privateConst in %s:6
Stack trace:
#0 {main}
thrown in %s on line 6

View File

@ -0,0 +1,16 @@
--TEST--
Class protected constant visibility error
--FILE--
<?php
class A {
protected const protectedConst = 'protectedConst';
}
var_dump(A::protectedConst);
?>
--EXPECTF--
Fatal error: Uncaught Error: Cannot access protected const A::protectedConst in %s:6
Stack trace:
#0 {main}
thrown in %s on line 6

View File

@ -0,0 +1,16 @@
--TEST--
A redeclared class constant must have the same or higher visibility
--FILE--
<?php
class A {
public const publicConst = 0;
}
class B extends A {
protected const publicConst = 1;
}
--EXPECTF--
Fatal error: Access level to B::publicConst must be public (as in class A) in %s on line 9

View File

@ -0,0 +1,16 @@
--TEST--
A redeclared class constant must have the same or higher visibility
--FILE--
<?php
class A {
protected const protectedConst = 0;
}
class B extends A {
private const protectedConst = 1;
}
--EXPECTF--
Fatal error: Access level to B::protectedConst must be protected (as in class A) or weaker in %s on line 9

View File

@ -0,0 +1,12 @@
--TEST--
Ensure a interface can have public constants
--FILE--
<?php
interface IA {
public const FOO = 10;
}
echo "Done\n";
?>
--EXPECT--
Done

View File

@ -0,0 +1,10 @@
--TEST--
Ensure a interface can not have protected constants
--FILE--
<?php
interface A {
protected const FOO = 10;
}
--EXPECTF--
Fatal error: Access type for interface constant A::FOO must be public in %s on line 3

View File

@ -0,0 +1,10 @@
--TEST--
Ensure a interface can not have private constants
--FILE--
<?php
interface A {
private const FOO = 10;
}
--EXPECTF--
Fatal error: Access type for interface constant A::FOO must be public in %s on line 3