- Prevent instantiation of classes with abstract methods.
Based in part on Marcus's patch.
zend_standard_class_def->handle_property_set = NULL;
zend_standard_class_def->refcount = 1;
zend_standard_class_def->constants_updated = 0;
+ zend_standard_class_def->ce_flags = 0;
zend_hash_add(GLOBAL_CLASS_TABLE, "stdclass", sizeof("stdclass"), &zend_standard_class_def, sizeof(zend_class_entry *), NULL);
}
/* A lot of stuff needs shifiting around in order to include zend_compile.h here */
union _zend_function;
+#define ZEND_CE_ABSTRACT ZEND_ACC_ABSTRACT /* same as ZEND_ACC_ABSTRACT */
+
struct _zend_class_entry {
char type;
char *name;
struct _zend_class_entry *parent;
int refcount;
zend_bool constants_updated;
+ zend_uint ce_flags;
HashTable function_table;
HashTable default_properties;
class_entry->parent = NULL;
class_entry->refcount = 1;
class_entry->constants_updated = 0;
+ class_entry->ce_flags = 0;
zend_hash_init(&class_entry->default_properties, 0, NULL, ZVAL_PTR_DTOR, 1);
zend_hash_init(&class_entry->private_properties, 0, NULL, ZVAL_PTR_DTOR, 1);
zend_hash_init(&class_entry->protected_properties, 0, NULL, ZVAL_PTR_DTOR, 1);
}
}
+
+int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier)
+{
+ if (current_access_type->u.constant.value.lval & ZEND_FN_PPP_MASK) {
+ zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
+ }
+ return (current_access_type->u.constant.value.lval | new_modifier->u.constant.value.lval);
+}
+
+
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags TSRMLS_DC)
{
zend_op_array op_array;
zend_error(E_COMPILE_ERROR, "Cannot redeclare %s()", name);
}
}
+ if (fn_flags & ZEND_ACC_ABSTRACT) {
+ CG(active_class_entry)->ce_flags |= ZEND_ACC_ABSTRACT;
+ }
if ((short_class_name_length == name_len) && (!memcmp(short_class_name, name, name_len))) {
CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
}
}
-
static void do_inherit_parent_constructor(zend_class_entry *ce)
{
zend_function *function;
ce->__call = ce->parent->__call;
}
-static zend_bool do_inherit_method_check(zend_function *child, zend_function *parent) {
+
+char *zend_visibility_string(zend_uint fn_flags)
+{
+ if (fn_flags & ZEND_ACC_PRIVATE) {
+ return "private";
+ }
+ if (fn_flags & ZEND_ACC_PROTECTED) {
+ return "protected";
+ }
+ if (fn_flags & ZEND_ACC_PUBLIC) {
+ return "public";
+ }
+ return "";
+}
+
+
+static void do_inherit_method(zend_function *function)
+{
+ /* The class entry of the derived function intentionally remains the same
+ * as that of the parent class. That allows us to know in which context
+ * we're running, and handle private method calls properly.
+ */
+ if (function->common.fn_flags & ZEND_ACC_ABSTRACT) {
+ function->op_array.scope->ce_flags |= ZEND_ACC_ABSTRACT;
+ }
+ function_add_ref(function);
+}
+
+
+static zend_bool do_inherit_method_check(zend_function *child, zend_function *parent)
+{
zend_uint child_flags = child->common.fn_flags;
zend_uint parent_flags = parent->common.fn_flags;
+ /* we do not inherit private methods */
+/* assert(!(parent_flags & ZEND_ACC_PRIVATE)); */
+
/* You cannot change from static to non static and vice versa.
*/
- if ((child_flags & FN_STATIC) != (parent_flags & FN_STATIC)) {
- if (child->common.fn_flags & FN_STATIC) {
- zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child));
+ if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
+ if (child->common.fn_flags & ZEND_ACC_STATIC) {
+ zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
} else {
- zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child));
+ zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
}
}
- /* Disallow makeing an inherited method abstract.
+ /* Disallow making an inherited method abstract.
+ * Also check the visibility and copy it if needed. This must be done last
+ * since we may change the child flags here.
+ * Again first detect more than one error to make normal operation faster.
*/
- if (child_flags & FN_ABSTRACT) {
- zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s() abstract in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child));
+ if ((child_flags & (ZEND_FN_PPP_MASK|ZEND_ACC_ABSTRACT)) != (parent_flags & ZEND_FN_PPP_MASK)) {
+ if (child_flags & ZEND_ACC_ABSTRACT) {
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
+ }
+ if (!(child_flags & ZEND_FN_PPP_MASK) || (((child_flags|parent_flags) & ZEND_FN_PPP_MASK) == ZEND_ACC_PUBLIC)) {
+ /* this is no error since we copy visibility here */
+ /* child->common.fn_flags &= ~ZEND_FN_PPP_MASK; do not clear added public */
+ child->common.fn_flags |= parent_flags & ZEND_FN_PPP_MASK;
+ } else {
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare %s %s::%s() as %s %s::%s()",
+ zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), parent->common.function_name,
+ zend_visibility_string(child_flags), ZEND_FN_SCOPE_NAME(child), child->common.function_name);
+ }
}
return SUCCESS;
}
+
void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
{
zval *tmp;
/* STATIC_MEMBERS_FIXME */
/* zend_hash_merge(ce->static_members, parent_ce->static_members, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); */
zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
- zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (void (*)(void *)) function_add_ref, sizeof(zend_function), (zend_bool (*)(void *, void *))do_inherit_method_check);
+ zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (zend_bool (*)(void *, void *)) do_inherit_method_check);
ce->parent = parent_ce;
- if (!ce->handle_property_get)
- ce->handle_property_get = parent_ce->handle_property_get;
- if (!ce->handle_property_set)
+ if (!ce->handle_property_get) {
+ ce->handle_property_get = parent_ce->handle_property_get;
+ }
+ if (!ce->handle_property_set) {
ce->handle_property_set = parent_ce->handle_property_set;
- if (!ce->handle_function_call)
+ }
+ if (!ce->handle_function_call) {
ce->handle_function_call = parent_ce->handle_function_call;
+ }
do_inherit_parent_constructor(ce);
}
new_class_entry->name_length = name_length;
new_class_entry->refcount = 1;
new_class_entry->constants_updated = 0;
+ new_class_entry->ce_flags = 0;
zend_str_tolower(new_class_entry->name, new_class_entry->name_length);
}
new_class_entry->refcount = 1;
new_class_entry->constants_updated = 0;
+ new_class_entry->ce_flags = 0;
zend_str_tolower(new_class_entry->name, new_class_entry->name_length);
*dest_length = prop_name_length;
}
-void zend_do_declare_property(znode *var_name, znode *value, int declaration_type TSRMLS_DC)
+
+void zend_do_declare_property(znode *var_name, znode *value TSRMLS_DC)
{
zval *property;
property->type = IS_NULL;
}
- switch (declaration_type) {
- case T_PRIVATE:
+ switch (CG(access_type)) {
+ case ZEND_ACC_PRIVATE:
{
char *priv_name;
int priv_name_length;
zend_hash_update(&CG(active_class_entry)->private_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
break;
}
- case T_PROTECTED:
+ case ZEND_ACC_PROTECTED:
{
char *prot_name;
int prot_name_length;
efree(prot_name);
break;
}
- case T_VAR:
+ case ZEND_ACC_PUBLIC:
zend_hash_update(&CG(active_class_entry)->default_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
break;
- case T_STATIC:
+ case ZEND_ACC_STATIC:
zend_hash_update(CG(active_class_entry)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
break;
- case T_CONST:
- zend_hash_update(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
- break;
}
FREE_PNODE(var_name);
}
+
+void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC)
+{
+ zval *property;
+
+ ALLOC_ZVAL(property);
+
+ if (value) {
+ *property = value->u.constant;
+ } else {
+ INIT_PZVAL(property);
+ property->type = IS_NULL;
+ }
+
+ zend_hash_update(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
+
+ FREE_PNODE(var_name);
+}
+
+
+
void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC)
{
zend_op opline;
} zend_brk_cont_element;
-#define FN_STATIC 0x01
+#define ZEND_ACC_STATIC 0x01
+#define ZEND_ACC_ABSTRACT 0x02
-#define FN_ABSTRACT 0x02
+/* No visibility is the same as public visibility.
+ * For inheritance no visibility means inheriting the visibility.
+ */
+#define ZEND_ACC_PUBLIC 0x10
+#define ZEND_ACC_PROTECTED 0x20
+#define ZEND_ACC_PRIVATE 0x40
+
+/* AND mask for accessing only public/protected/private of fn_flags
+ */
+#define ZEND_FN_PPP_MASK 0xF0
+
+char *zend_visibility_string(zend_uint fn_flags);
struct _zend_op_array {
zend_uchar type; /* MUST be the first element of this struct! */
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
} zend_internal_function;
-#define FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? (function)->common.scope->name : "")
+#define ZEND_FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? (function)->common.scope->name : "")
typedef union _zend_function {
zend_uchar type; /* MUST be the first element of this struct! */
void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC);
void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC);
+int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier);
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags TSRMLS_DC);
void zend_do_end_function_declaration(znode *function_token TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, zend_uchar pass_type TSRMLS_DC);
void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znode *parent_class_name TSRMLS_DC);
void zend_do_end_class_declaration(znode *class_token TSRMLS_DC);
-void zend_do_declare_property(znode *var_name, znode *value, int declaration_type TSRMLS_DC);
+void zend_do_declare_property(znode *var_name, znode *value TSRMLS_DC);
+void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC);
void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC);
NEXT_OPCODE();
}
+
+/* Ensures that we're allowed to call a private method.
+ * Will update EX(fbc) with the correct handler as necessary.
+ */
+inline int zend_check_private(zend_execute_data *execute_data, zend_class_entry *ce, int fn_flags, char *function_name_strval, int function_name_strlen TSRMLS_DC)
+{
+ if (!ce) {
+ return 0;
+ }
+
+ /* We may call a private function in one of two cases:
+ * 1. The scope of the function is the same as the class entry of our object
+ * 2. The class of our object is different, but a private function exists
+ * in one of the ancestor that corresponds to our object's ce.
+ */
+ if (EX(fbc)->common.scope == ce) {
+ /* rule #1 checks out ok, allow the function call */
+ return 1;
+ }
+
+ /* Check rule #2 */
+ while (ce) {
+ if (ce == EG(scope)) {
+ if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==SUCCESS
+ && EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE
+ && EX(fbc)->common.scope == EG(scope)) {
+ return 1;
+ }
+ break;
+ }
+ ce = ce->parent;
+ }
+ return 0;
+}
+
+/* Ensures that we're allowed to call a protected method.
+ */
+inline int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope, int fn_flags)
+{
+ while (ce) {
+ if (ce==scope) {
+ return 1;
+ }
+ ce = ce->parent;
+ }
+ return 0;
+}
+
+
int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval *function_name;
EX(object) = get_obj_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R TSRMLS_CC);
if (EX(object) && EX(object)->type == IS_OBJECT) {
+
+ /* First, locate the function. */
EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
if (!EX(fbc)) {
- zend_error(E_ERROR, "Call to undefined function: %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
+ zend_error(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
+ }
+
+ if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) {
+ /* No further checks necessary, most common case */
+ } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) {
+ /* Ensure that if we're calling a private function, we're allowed to do so.
+ */
+ if (!zend_check_private(execute_data, EX(object)->value.obj.handlers->get_class_entry(EX(object) TSRMLS_CC), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) {
+ zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+ }
+ } else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) {
+ /* Ensure that if we're calling a protected function, we're allowed to do so.
+ */
+ if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) {
+ zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+ }
}
} else {
zend_error(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
}
- if (EX(fbc)->common.fn_flags & FN_STATIC) {
+ if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
EX(object) = NULL;
} else {
if (!PZVAL_IS_REF(EX(object))) {
int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval *function_name;
- zend_function *function;
zval tmp;
zend_class_entry *ce;
zend_bool is_const;
EX(calling_scope) = ce;
- if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) {
- zend_error(E_ERROR, "Call to undefined function: %s::%s()", ce->name, function_name_strval);
+ if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==FAILURE) {
+ zend_error(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);
+ }
+ EX(calling_scope) = EX(fbc)->common.scope;
+
+ if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) {
+ /* No further checks necessary, most common case */
+ } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) {
+ /* Ensure that if we're calling a private function, we're allowed to do so.
+ */
+ if (!zend_check_private(execute_data, EG(scope), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) {
+ zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+ }
+ } else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) {
+ /* Ensure that if we're calling a protected function, we're allowed to do so.
+ */
+ if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) {
+ zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+ }
}
if (!is_const) {
FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2));
}
- EX(fbc) = function;
-
- if (function->common.fn_flags & FN_STATIC) {
+ if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
EX(object) = NULL;
} else {
if ((EX(object) = EG(This))) {
int zend_new_handler(ZEND_OPCODE_HANDLER_ARGS)
{
+ if (EX_T(EX(opline)->op1.u.var).EA.class_entry->ce_flags & ZEND_ACC_ABSTRACT) {
+ zend_error(E_ERROR, "Cannot instanciate abstract class %s", EX_T(EX(opline)->op1.u.var).EA.class_entry->name);
+ }
EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
ALLOC_ZVAL(EX_T(EX(opline)->result.u.var).var.ptr);
object_init_ex(EX_T(EX(opline)->result.u.var).var.ptr, EX_T(EX(opline)->op1.u.var).EA.class_entry);
zend_bool increment_lineno;
zend_llist import_commands;
+
+ int access_type;
};
typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC);
typedef void (*dtor_func_t)(void *pDest);
typedef void (*copy_ctor_func_t)(void *pElement);
+typedef void (*copy_ctor_param_func_t)(void *pElement, void *pParam);
struct _hashtable;
%token T_THROW
%token T_USE
%token T_GLOBAL
-%token T_STATIC
-%token T_ABSTRACT
-%token T_PRIVATE
-%token T_PROTECTED
+%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
%token T_VAR
%token T_UNSET
%token T_ISSET
;
+is_reference:
+ /* empty */ { $$.op_type = ZEND_RETURN_VAL; }
+ | '&' { $$.op_type = ZEND_RETURN_REF; }
+;
+
+
unticked_function_declaration_statement:
T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, 0 TSRMLS_CC); }
'(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
class_statement:
- class_variable_declaration ';'
+ variable_modifier { CG(access_type) = $1.u.constant.value.lval; } class_variable_declaration ';'
| class_constant_declaration ';'
- | is_static T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '('
+ | method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '('
parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); }
+ | T_ABSTRACT method_modifiers T_FUNCTION { $3.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$3, &$6, 1, $5.op_type, $2.u.constant.value.lval | ZEND_ACC_ABSTRACT TSRMLS_CC); } '('
+ parameter_list ')' { zend_do_abstract_method(TSRMLS_C); zend_do_end_function_declaration(&$3 TSRMLS_CC); } ';'
| T_CLASS T_STRING extends_from '{' { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } class_statement_list '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
- | T_ABSTRACT T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, FN_ABSTRACT TSRMLS_CC); } '('
- parameter_list ')' { zend_do_abstract_method(TSRMLS_C); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
;
-is_static:
- T_STATIC { $$.u.constant.value.lval = FN_STATIC; }
- | /* empty */ { $$.u.constant.value.lval = 0; }
+variable_modifier:
+ access_modifier { $$ = $1; }
+ | T_VAR { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; }
+ | T_STATIC { $$.u.constant.value.lval = ZEND_ACC_STATIC; }
;
-
-is_reference:
- /* empty */ { $$.op_type = ZEND_RETURN_VAL; }
- | '&' { $$.op_type = ZEND_RETURN_REF; }
+
+method_modifiers:
+ /* empty */ { $$.u.constant.value.lval = 0; }
+ | non_empty_method_modifiers { $$ = $1; }
;
-class_variable_declaration:
- class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL, $1.op_type TSRMLS_CC); }
- | class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5, $1.op_type TSRMLS_CC); }
- | class_declaration_type T_VARIABLE { $$ = $1; zend_do_declare_property(&$2, NULL, $1.op_type TSRMLS_CC); }
- | class_declaration_type T_VARIABLE '=' static_scalar { $$ = $1; zend_do_declare_property(&$2, &$4, $1.op_type TSRMLS_CC); }
+non_empty_method_modifiers:
+ T_STATIC { $$.u.constant.value.lval = ZEND_ACC_STATIC; }
+ | access_modifier { $$ = $1; }
+ | non_empty_method_modifiers T_STATIC { $$.u.constant.value.lval = $1.u.constant.value.lval | ZEND_ACC_STATIC; }
+ | non_empty_method_modifiers access_modifier { $$.u.constant.value.lval = zend_do_verify_access_types(&$1, &$2); }
;
-class_declaration_type:
- T_VAR { $$.op_type = T_VAR; }
- | T_STATIC { $$.op_type = T_STATIC; }
- | T_PRIVATE { $$.op_type = T_PRIVATE; }
- | T_PROTECTED { $$.op_type = T_PROTECTED; }
+access_modifier:
+ T_PUBLIC { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; }
+ | T_PROTECTED { $$.u.constant.value.lval = ZEND_ACC_PROTECTED; }
+ | T_PRIVATE { $$.u.constant.value.lval = ZEND_ACC_PRIVATE; }
+;
+
+class_variable_declaration:
+ class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL TSRMLS_CC); }
+ | class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5 TSRMLS_CC); }
+ | T_VARIABLE { zend_do_declare_property(&$1, NULL TSRMLS_CC); }
+ | T_VARIABLE '=' static_scalar { zend_do_declare_property(&$1, &$3 TSRMLS_CC); }
;
class_constant_declaration:
- | T_CONST ',' T_STRING '=' static_scalar { zend_do_declare_property(&$3, &$5, T_CONST TSRMLS_CC); }
- | T_CONST T_STRING '=' static_scalar { zend_do_declare_property(&$2, &$4, T_CONST TSRMLS_CC); }
+ class_constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); }
+ | T_CONST T_STRING '=' static_scalar { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); }
;
echo_expr_list:
- | echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
+ echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
| expr { zend_do_echo(&$1 TSRMLS_CC); }
;
return T_ABSTRACT;
}
+<ST_IN_SCRIPTING>"final" {
+ return T_FINAL;
+}
+
<ST_IN_SCRIPTING>"private" {
return T_PRIVATE;
}
}
<ST_IN_SCRIPTING>"public" {
- return T_VAR;
+ return T_PUBLIC;
}
<ST_IN_SCRIPTING>"unset" {