Permalink
Browse files

- Implement public/protected/private methods.

- Prevent instantiation of classes with abstract methods.
Based in part on Marcus's patch.
  • Loading branch information...
1 parent e0a972c commit e062dffe6c81751133121519a9ae3cbe854a509a @zsuraski zsuraski committed Dec 6, 2002
Showing with 268 additions and 64 deletions.
  1. +1 −0 Zend/zend.c
  2. +3 −0 Zend/zend.h
  3. +1 −0 Zend/zend_API.c
  4. +107 −23 Zend/zend_compile.c
  5. +18 −4 Zend/zend_compile.h
  6. +92 −8 Zend/zend_execute.c
  7. +2 −0 Zend/zend_globals.h
  8. +1 −0 Zend/zend_hash.h
  9. +38 −28 Zend/zend_language_parser.y
  10. +5 −1 Zend/zend_language_scanner.l
View
@@ -354,6 +354,7 @@ static void register_standard_class(void)
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);
}
View
@@ -295,13 +295,16 @@ typedef struct _zend_overloaded_element {
/* 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;
zend_uint name_length;
struct _zend_class_entry *parent;
int refcount;
zend_bool constants_updated;
+ zend_uint ce_flags;
HashTable function_table;
HashTable default_properties;
View
@@ -1236,6 +1236,7 @@ ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_c
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);
View
@@ -909,6 +909,16 @@ void zend_do_free(znode *op1 TSRMLS_DC)
}
}
+
+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;
@@ -950,6 +960,9 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
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);
@@ -1502,7 +1515,6 @@ ZEND_API void function_add_ref(zend_function *function)
}
}
-
static void do_inherit_parent_constructor(zend_class_entry *ce)
{
zend_function *function;
@@ -1529,27 +1541,75 @@ static void do_inherit_parent_constructor(zend_class_entry *ce)
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;
@@ -1560,14 +1620,17 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
/* 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);
}
@@ -1582,6 +1645,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze
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);
@@ -2055,6 +2119,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
}
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);
@@ -2134,7 +2199,8 @@ void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_le
*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;
@@ -2147,8 +2213,8 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ
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;
@@ -2162,7 +2228,7 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ
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;
@@ -2188,19 +2254,37 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ
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;
View
@@ -88,9 +88,21 @@ typedef struct _zend_brk_cont_element {
} 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! */
@@ -138,7 +150,7 @@ typedef struct _zend_internal_function {
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! */
@@ -295,6 +307,7 @@ void zend_do_add_char(znode *result, znode *op1, znode *op2 TSRMLS_DC);
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);
@@ -337,7 +350,8 @@ void zend_do_default_before_statement(znode *case_list, znode *default_token TSR
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);
Oops, something went wrong.

0 comments on commit e062dff

Please sign in to comment.