Index: zend_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_API.c,v retrieving revision 1.296.2.27.2.34.2.33 diff -u -r1.296.2.27.2.34.2.33 zend_API.c --- zend_API.c 25 Mar 2008 13:04:03 -0000 1.296.2.27.2.34.2.33 +++ zend_API.c 4 May 2008 20:19:34 -0000 @@ -1038,8 +1038,13 @@ zval *tmp; zend_object *object; - if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { - char *what = class_type->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "abstract class"; + if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_STATIC_CLASS)) { + char *what; + if (class_type->ce_flags & ZEND_ACC_INTERFACE) { + what = "interface"; + } else { + what = class_type->ce_flags & ZEND_ACC_STATIC_CLASS ? "static class" : "abstract class"; + } zend_error(E_ERROR, "Cannot instantiate %s %s", what, class_type->name); } Index: zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.647.2.27.2.41.2.60 diff -u -r1.647.2.27.2.41.2.60 zend_compile.c --- zend_compile.c 29 Apr 2008 08:15:16 -0000 1.647.2.27.2.41.2.60 +++ zend_compile.c 4 May 2008 20:19:34 -0000 @@ -2638,6 +2638,9 @@ if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) { zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name); } + if (!(ce->type == ZEND_INTERNAL_CLASS) && (ce->ce_flags & ZEND_ACC_STATIC_CLASS) && !(parent_ce->ce_flags & ZEND_ACC_STATIC_CLASS)) { + zend_error(E_COMPILE_ERROR, "Class %s may not strengthen interface. Parent class (%s) is non-static and %s is static", ce->name, parent_ce->name, ce->name); + } ce->parent = parent_ce; /* Inherit interfaces */ @@ -3283,6 +3286,15 @@ } +static void do_verify_static_class(TSRMLS_D) +{ + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + + opline->opcode = ZEND_VERIFY_STATIC_CLASS; + opline->op1 = CG(implementing_class); + SET_UNUSED(opline->op2); +} + void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRMLS_DC) { zend_class_entry *ce = CG(active_class_entry); @@ -3310,12 +3322,17 @@ ce->line_end = zend_get_compiled_lineno(TSRMLS_C); - if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) + if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_STATIC_CLASS)) && ((parent_token->op_type != IS_UNUSED) || (ce->num_interfaces > 0))) { zend_verify_abstract_class(ce TSRMLS_CC); if (ce->parent || ce->num_interfaces) { do_verify_abstract_class(TSRMLS_C); } + } else if (ce->ce_flags & ZEND_ACC_STATIC_CLASS) { + zend_verify_static_class(ce TSRMLS_CC); + if (ce->parent || ce->num_interfaces) { + do_verify_static_class(TSRMLS_C); + } } /* Inherit interfaces; reset number to zero, we need it for above check and * will restore it during actual implementation. Index: zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.316.2.8.2.12.2.21 diff -u -r1.316.2.8.2.12.2.21 zend_compile.h --- zend_compile.h 29 Mar 2008 11:52:10 -0000 1.316.2.8.2.12.2.21 +++ zend_compile.h 4 May 2008 20:19:34 -0000 @@ -119,6 +119,7 @@ #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS 0x20 #define ZEND_ACC_FINAL_CLASS 0x40 #define ZEND_ACC_INTERFACE 0x80 +#define ZEND_ACC_STATIC_CLASS 0x100000 /* op_array flags */ #define ZEND_ACC_INTERACTIVE 0x10 Index: zend_execute.h =================================================================== RCS file: /repository/ZendEngine2/zend_execute.h,v retrieving revision 1.84.2.4.2.8.2.9 diff -u -r1.84.2.4.2.8.2.9 zend_execute.h --- zend_execute.h 15 Apr 2008 15:52:36 -0000 1.84.2.4.2.8.2.9 +++ zend_execute.h 4 May 2008 20:19:34 -0000 @@ -305,6 +305,7 @@ ZEND_API void zend_timeout(int dummy); ZEND_API zend_class_entry *zend_fetch_class(const char *class_name, uint class_name_len, int fetch_type TSRMLS_DC); void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC); +void zend_verify_static_class(zend_class_entry *ce TSRMLS_DC); #ifdef ZEND_WIN32 void zend_init_timeout_thread(void); Index: zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.331.2.20.2.24.2.37 diff -u -r1.331.2.20.2.24.2.37 zend_execute_API.c --- zend_execute_API.c 29 Apr 2008 09:18:14 -0000 1.331.2.20.2.24.2.37 +++ zend_execute_API.c 4 May 2008 20:19:34 -0000 @@ -1688,35 +1688,37 @@ } /* }}} */ -#define MAX_ABSTRACT_INFO_CNT 3 -#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s" -#define DISPLAY_ABSTRACT_FN(idx) \ - ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \ - ai.afn[idx] ? "::" : "", \ - ai.afn[idx] ? ai.afn[idx]->common.function_name : "", \ - ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "") +#define MAX_INSPECTION_INFO_CNT 3 +#define MAX_INSPECTION_INFO_FMT "%s%s%s%s" +#define DISPLAY_INSPECTION_INFO_FN(idx) \ + cii.afn[idx] ? ZEND_FN_SCOPE_NAME(cii.afn[idx]) : "", \ + cii.afn[idx] ? "::" : "", \ + cii.afn[idx] ? cii.afn[idx]->common.function_name : "", \ + cii.afn[idx] && cii.afn[idx + 1] ? ", " : (cii.afn[idx] && cii.cnt > MAX_INSPECTION_INFO_CNT ? ", ..." : "") -typedef struct _zend_abstract_info { - zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1]; +typedef struct _zend_class_inspection_info { + zend_function *afn[MAX_INSPECTION_INFO_CNT + 1]; int cnt; int ctor; -} zend_abstract_info; + int ce_flag; + int ce_flag_condition; +} zend_class_inspection_info; -static int zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai TSRMLS_DC) /* {{{ */ +static int zend_verify_class_function(zend_function *fn, zend_class_inspection_info *cii TSRMLS_DC) /* {{{ */ { - if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { - if (ai->cnt < MAX_ABSTRACT_INFO_CNT) { - ai->afn[ai->cnt] = fn; + if ((fn->common.fn_flags & cii->ce_flag) == cii->ce_flag_condition) { + if (cii->cnt < MAX_INSPECTION_INFO_CNT) { + cii->afn[cii->cnt] = fn; } if (fn->common.fn_flags & ZEND_ACC_CTOR) { - if (!ai->ctor) { - ai->cnt++; - ai->ctor = 1; + if (!cii->ctor) { + cii->cnt++; + cii->ctor = 1; } else { - ai->afn[ai->cnt] = NULL; + cii->afn[cii->cnt] = NULL; } } else { - ai->cnt++; + cii->cnt++; } } return 0; @@ -1725,21 +1727,46 @@ void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC) /* {{{ */ { - zend_abstract_info ai; + zend_class_inspection_info cii; if ((ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) && !(ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { - memset(&ai, 0, sizeof(ai)); + memset(&cii, 0, sizeof(cii)); - zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_abstract_class_function, &ai TSRMLS_CC); + cii.ce_flag = ZEND_ACC_ABSTRACT; + cii.ce_flag_condition = 2; + zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_class_function, &cii TSRMLS_CC); + + if (cii.cnt) { + zend_error(E_ERROR, "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_INSPECTION_INFO_FMT MAX_INSPECTION_INFO_FMT MAX_INSPECTION_INFO_FMT ")", + ce->name, cii.cnt, + cii.cnt > 1 ? "s" : "", + DISPLAY_INSPECTION_INFO_FN(0), + DISPLAY_INSPECTION_INFO_FN(1), + DISPLAY_INSPECTION_INFO_FN(2) + ); + } + } +} +/* }}} */ + +void zend_verify_static_class(zend_class_entry *ce TSRMLS_DC) /* {{{ */ +{ + zend_class_inspection_info cii; - if (ai.cnt) { - zend_error(E_ERROR, "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")", - ce->name, ai.cnt, - ai.cnt > 1 ? "s" : "", - DISPLAY_ABSTRACT_FN(0), - DISPLAY_ABSTRACT_FN(1), - DISPLAY_ABSTRACT_FN(2) - ); + if (ce->ce_flags & ZEND_ACC_STATIC_CLASS) { + memset(&cii, 0, sizeof(cii)); + cii.ce_flag = ZEND_ACC_STATIC; + cii.ce_flag_condition = 0; + zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_class_function, &cii TSRMLS_CC); + + if (cii.cnt) { + zend_error(E_ERROR, "Static class %s contains %d non-static method%s that must be declared static (" MAX_INSPECTION_INFO_FMT MAX_INSPECTION_INFO_FMT MAX_INSPECTION_INFO_FMT ")", + ce->name, cii.cnt, + cii.cnt > 1 ? "s" : "", + DISPLAY_INSPECTION_INFO_FN(0), + DISPLAY_INSPECTION_INFO_FN(1), + DISPLAY_INSPECTION_INFO_FN(2) + ); } } } Index: zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.160.2.4.2.8.2.19 diff -u -r1.160.2.4.2.8.2.19 zend_language_parser.y --- zend_language_parser.y 28 Mar 2008 14:34:59 -0000 1.160.2.4.2.8.2.19 +++ zend_language_parser.y 4 May 2008 20:19:35 -0000 @@ -316,6 +316,8 @@ class_entry_type: T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 0; } + | T_STATIC T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_STATIC_CLASS; } + | T_ABSTRACT T_STATIC T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_STATIC_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } | T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } | T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; } ; Index: zend_vm_def.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_def.h,v retrieving revision 1.59.2.29.2.48.2.51 diff -u -r1.59.2.29.2.48.2.51 zend_vm_def.h --- zend_vm_def.h 30 Apr 2008 10:44:08 -0000 1.59.2.29.2.48.2.51 +++ zend_vm_def.h 4 May 2008 20:19:35 -0000 @@ -2697,13 +2697,13 @@ zval *object_zval; zend_function *constructor; - if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { + if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_STATIC_CLASS)) { char *class_type; if (EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) { class_type = "interface"; } else { - class_type = "abstract class"; + class_type = EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_STATIC_CLASS ? "static class" : "abstract class"; } zend_error_noreturn(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(opline->op1.u.var).class_entry->name); } @@ -4157,6 +4157,12 @@ ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(151, ZEND_VERIFY_STATIC_CLASS, ANY, ANY) +{ + zend_verify_static_class(EX_T(EX(opline)->op1.u.var).class_entry TSRMLS_CC); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) { int ret = zend_user_opcode_handlers[EX(opline)->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL); Index: zend_vm_execute.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_execute.h,v retrieving revision 1.62.2.30.2.49.2.50 diff -u -r1.62.2.30.2.49.2.50 zend_vm_execute.h --- zend_vm_execute.h 30 Apr 2008 10:44:08 -0000 1.62.2.30.2.49.2.50 +++ zend_vm_execute.h 4 May 2008 20:19:37 -0000 @@ -331,13 +331,13 @@ zval *object_zval; zend_function *constructor; - if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { + if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_STATIC_CLASS)) { char *class_type; if (EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) { class_type = "interface"; } else { - class_type = "abstract class"; + class_type = EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_STATIC_CLASS ? "static class" : "abstract class"; } zend_error_noreturn(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(opline->op1.u.var).class_entry->name); } @@ -549,6 +549,12 @@ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_verify_static_class(EX_T(EX(opline)->op1.u.var).class_entry TSRMLS_CC); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { int ret = zend_user_opcode_handlers[EX(opline)->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL); @@ -33292,31 +33298,31 @@ ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, + ZEND_VERIFY_STATIC_CLASS_SPEC_HANDLER, ZEND_JMP_SET_SPEC_CONST_HANDLER, ZEND_JMP_SET_SPEC_CONST_HANDLER, ZEND_JMP_SET_SPEC_CONST_HANDLER, Index: zend_vm_opcodes.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_opcodes.h,v retrieving revision 1.42.2.17.2.1.2.6 diff -u -r1.42.2.17.2.1.2.6 zend_vm_opcodes.h --- zend_vm_opcodes.h 28 Mar 2008 14:35:01 -0000 1.42.2.17.2.1.2.6 +++ zend_vm_opcodes.h 4 May 2008 20:19:37 -0000 @@ -151,4 +151,5 @@ #define ZEND_ISSET_ISEMPTY_PROP_OBJ 148 #define ZEND_HANDLE_EXCEPTION 149 #define ZEND_USER_OPCODE 150 +#define ZEND_VERIFY_STATIC_CLASS 151 #define ZEND_JMP_SET 152