/* registers all functions in *library_functions in the function hash */
-int zend_register_functions(zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC)
+int zend_register_functions(zend_class_entry *scope, zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC)
{
zend_function_entry *ptr = functions;
zend_function function;
internal_function->handler = ptr->handler;
internal_function->arg_types = ptr->func_arg_types;
internal_function->function_name = ptr->fname;
- internal_function->scope = NULL;
- internal_function->is_static = 0;
+ internal_function->scope = scope;
+ internal_function->fn_flags = 0;
if (!internal_function->handler) {
zend_error(error_type, "Null function defined as active function");
zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);
#if 0
zend_printf("%s: Registering module %d\n", module->name, module->module_number);
#endif
- if (module->functions && zend_register_functions(module->functions, NULL, module->type TSRMLS_CC)==FAILURE) {
+ if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type TSRMLS_CC)==FAILURE) {
zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name);
return FAILURE;
}
zend_hash_init(&class_entry->class_table, 10, NULL, ZEND_CLASS_DTOR, 1);
if (class_entry->builtin_functions) {
- zend_register_functions(class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
+ zend_register_functions(class_entry, class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
}
zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, &class_entry, sizeof(zend_class_entry *), NULL);
return FAILURE;
}
disabled_function[0].fname = function_name;
- return zend_register_functions(disabled_function, CG(function_table), MODULE_PERSISTENT TSRMLS_CC);
+ return zend_register_functions(NULL, disabled_function, CG(function_table), MODULE_PERSISTENT TSRMLS_CC);
}
zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char **callable_name)
/* End of parameter parsing API -- andrei */
-int zend_register_functions(zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC);
+int zend_register_functions(zend_class_entry *scope, zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC);
void zend_unregister_functions(zend_function_entry *functions, int count, HashTable *function_table TSRMLS_DC);
ZEND_API int zend_register_module(zend_module_entry *module_entry);
int zend_startup_builtin_functions(TSRMLS_D)
{
- return zend_register_functions(builtin_functions, NULL, MODULE_PERSISTENT TSRMLS_CC);
+ return zend_register_functions(NULL, builtin_functions, NULL, MODULE_PERSISTENT TSRMLS_CC);
}
}
}
-void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, int is_static TSRMLS_DC)
+void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, int fn_flags TSRMLS_DC)
{
zend_op_array op_array;
char *name = function_name->u.constant.value.str.val;
op_array.function_name = name;
op_array.arg_types = NULL;
op_array.return_reference = return_reference;
- op_array.is_static = is_static;
+ op_array.fn_flags = fn_flags;
op_array.scope = CG(active_class_entry);
ce->__call = ce->parent->__call;
}
+static zend_bool do_inherit_method_check(zend_function *child, zend_function *parent) {
+ register zend_uint child_flags = child->common.fn_flags;
+ register zend_uint parent_flags = parent->common.fn_flags;
+
+ /* You cannot change from static to non static and vice versa.
+ */
+ if ((child_flags&FN_IS_STATIC) != (parent_flags&FN_IS_STATIC)) {
+ if (child->common.fn_flags & FN_IS_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));
+ } 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));
+ }
+ }
+ /* Disallow makeing an inherited method abstract.
+ */
+ 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));
+ }
+ return SUCCESS;
+}
+
void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
{
- zend_function tmp_zend_function;
zval *tmp;
/* Perform inheritance */
/* 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(&ce->function_table, &parent_ce->function_table, (void (*)(void *)) function_add_ref, &tmp_zend_function, sizeof(zend_function), 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);
ce->parent = parent_ce;
if (!ce->handle_property_get)
ce->handle_property_get = parent_ce->handle_property_get;
} zend_brk_cont_element;
+#define FN_IS_STATIC 0x00000001
+
+#define FN_ABSTRACT 0x00000002
+
struct _zend_op_array {
zend_uchar type; /* MUST be the first element of this struct! */
zend_uchar *arg_types; /* MUST be the second element of this struct! */
char *function_name; /* MUST be the third element of this struct! */
zend_class_entry *scope; /* MUST be the fourth element of this struct! */
- zend_bool is_static; /* MUST be the fifth element of this struct! */
+ int fn_flags; /* MUST be the fifth element of this struct! */
zend_uint *refcount;
zend_uchar *arg_types; /* MUST be the second element of this struct! */
char *function_name; /* MUST be the third element of this struct! */
zend_class_entry *scope; /* MUST be the fourth element of this struct! */
- zend_bool is_static; /* MUST be the fifth element of this struct! */
+ int fn_flags; /* MUST be the fifth 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 : "")
+
typedef union _zend_function {
zend_uchar type; /* MUST be the first element of this struct! */
zend_uchar *arg_types;
char *function_name;
zend_class_entry *scope;
- zend_bool is_static;
+ int fn_flags;
} common;
zend_op_array op_array;
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);
-void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, int is_static TSRMLS_DC);
+void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, int 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);
int zend_do_begin_function_call(znode *function_name TSRMLS_DC);
if (EX(object) && EX(object)->type == IS_OBJECT) {
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);
+ }
} else {
- zend_error(E_ERROR, "Call to a member function on a non-object");
- }
- if (!EX(fbc)) {
- zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval);
+ zend_error(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
}
- if (EX(fbc)->common.is_static) {
+ if (EX(fbc)->common.fn_flags & FN_IS_STATIC) {
EX(object) = NULL;
} else {
if (!PZVAL_IS_REF(EX(object))) {
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()", function_name_strval);
+ zend_error(E_ERROR, "Call to undefined function: %s::%s()", ce->name, function_name_strval);
}
if (!is_const) {
EX(fbc) = function;
- if (function->common.is_static) {
+ if (function->common.fn_flags & FN_IS_STATIC) {
EX(object) = NULL;
} else {
if ((EX(object) = EG(This))) {
#define IS_OVERLOADED_OBJECT 1
#define IS_STRING_OFFSET 2
+/* The following tries to resolve the classname of a zval of type object.
+ * Since it is slow it should be only used in error messages.
+ */
+#define Z_OBJ_CLASS_NAME_P(zval) ((zval) && (zval)->type == IS_OBJECT && Z_OBJ_HT_P(zval)->get_class_entry != NULL && Z_OBJ_HT_P(zval)->get_class_entry(zval TSRMLS_CC) ? Z_OBJ_HT_P(zval)->get_class_entry(zval TSRMLS_CC)->name : "")
+
END_EXTERN_C()
#endif /* ZEND_EXECUTE_H */
| 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); } '('
parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 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, $1.u.constant.value.lval 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 = 1; }
+ T_STATIC { $$.u.constant.value.lval = FN_IS_STATIC; }
| /* empty */ { $$.u.constant.value.lval = 0; }
;
call_user_call->type = ZEND_INTERNAL_FUNCTION;
call_user_call->handler = zend_std_call_user_call;
call_user_call->arg_types = NULL;
- call_user_call->scope = NULL;
- call_user_call->is_static = 0;
+ call_user_call->scope = zobj->ce;
+ call_user_call->fn_flags = 0;
call_user_call->function_name = estrndup(method_name, method_len);
free_alloca(lc_method_name);