}
-ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time)
+ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_bool compile_time)
{
zend_function *function;
}
-ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table TSRMLS_DC)
+ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC)
{
zend_class_entry *ce, **pce;
ce->refcount++;
if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
ce->refcount--;
- zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ if (!compile_time) {
+ /* If we're in compile time, in practice, it's quite possible
+ * that we'll never reach this class declaration at runtime,
+ * so we shut up about it. This allows the if (!defined('FOO')) { return; }
+ * approach to work.
+ */
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ }
return NULL;
} else {
+ zend_verify_abstract_class(ce TSRMLS_CC);
return ce;
}
}
-ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce TSRMLS_DC)
+
+ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC)
{
zend_class_entry *ce, **pce;
int found_ce;
found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce);
if (found_ce == FAILURE) {
- zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ if (!compile_time) {
+ /* If we're in compile time, in practice, it's quite possible
+ * that we'll never reach this class declaration at runtime,
+ * so we shut up about it. This allows the if (!defined('FOO')) { return; }
+ * approach to work.
+ */
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
+ }
return NULL;
} else {
ce = *pce;
void zend_do_early_binding(TSRMLS_D)
{
zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
+ HashTable *table;
while (opline->opcode == ZEND_TICKS && opline > CG(active_op_array)->opcodes) {
opline--;
}
- if (do_bind_function(opline, CG(function_table), CG(class_table), 1) == FAILURE) {
- return;
+ switch (opline->opcode) {
+ case ZEND_DECLARE_FUNCTION:
+ if (do_bind_function(opline, CG(function_table), 1) == FAILURE) {
+ return;
+ }
+ table = CG(function_table);
+ break;
+ case ZEND_VERIFY_ABSTRACT_CLASS: {
+ zend_op *verify_abstract_class_op = opline;
+
+ opline--;
+ if (opline->opcode == ZEND_DECLARE_CLASS) {
+ if (do_bind_class(opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
+ return;
+ }
+ } else if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS) {
+ zval *parent_name = &(opline-1)->op2.u.constant;
+ zend_class_entry **pce;
+
+ if (zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) {
+ return;
+ }
+ if (do_bind_inherited_class(opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) {
+ return;
+ }
+ } else {
+ /* We currently don't early-bind classes that implement interfaces */
+ return;
+ }
+ table = CG(class_table);
+ /* clear the verify_abstract_class op */
+ init_op(verify_abstract_class_op TSRMLS_CC);
+ SET_UNUSED(verify_abstract_class_op->op1);
+ SET_UNUSED(verify_abstract_class_op->op2);
+ verify_abstract_class_op->opcode = ZEND_NOP;
+ }
+
+ break;
+ default:
+ zend_error(E_COMPILE_ERROR, "Invalid binding type");
+ return;
}
- zend_hash_del(CG(function_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len);
+ zend_hash_del(table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len);
zval_dtor(&opline->op1.u.constant);
zval_dtor(&opline->op2.u.constant);
opline->opcode = ZEND_NOP;
void zend_do_end_catch(znode *try_token TSRMLS_DC);
void zend_do_throw(znode *expr TSRMLS_DC);
-ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time);
-ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table TSRMLS_DC);
-ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce TSRMLS_DC);
+ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_bool compile_time);
+ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC);
+ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC);
ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC);
ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC);
void zend_do_implements_interface(znode *interface_znode TSRMLS_DC);
int zend_declare_class_handler(ZEND_OPCODE_HANDLER_ARGS)
{
- EX_T(opline->result.u.var).class_entry = do_bind_class(opline, EG(function_table), EG(class_table) TSRMLS_CC);
+ EX_T(opline->result.u.var).class_entry = do_bind_class(opline, EG(class_table), 0 TSRMLS_CC);
NEXT_OPCODE();
}
int zend_declare_inherited_class_handler(ZEND_OPCODE_HANDLER_ARGS)
{
- EX_T(opline->result.u.var).class_entry = do_bind_inherited_class(opline, EG(function_table), EG(class_table), EX_T(opline->extended_value).class_entry TSRMLS_CC);
+ EX_T(opline->result.u.var).class_entry = do_bind_inherited_class(opline, EG(class_table), EX_T(opline->extended_value).class_entry, 0 TSRMLS_CC);
NEXT_OPCODE();
}
int zend_declare_function_handler(ZEND_OPCODE_HANDLER_ARGS)
{
- do_bind_function(opline, EG(function_table), EG(class_table), 0);
+ do_bind_function(opline, EG(function_table), 0);
NEXT_OPCODE();
}
}
-#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 ? ", ..." : "")
-
-
-typedef struct _zend_abstract_info {
- zend_function *afn[MAX_ABSTRACT_INFO_CNT+1];
- int cnt;
-} zend_abstract_info;
-
-
-int zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai TSRMLS_DC)
-{
- if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
- if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
- ai->afn[ai->cnt] = fn;
- }
- ai->cnt++;
- }
- return 0;
-}
-
-
int zend_verify_abstract_class_handler(ZEND_OPCODE_HANDLER_ARGS)
{
- zend_class_entry *ce = EX_T(opline->op1.u.var).class_entry;
- zend_abstract_info ai;
-
- if ((ce->ce_flags & ZEND_ACC_ABSTRACT) && !(ce->ce_flags & ZEND_ACC_ABSTRACT_CLASS)) {
- memset(&ai, 0, sizeof(ai));
-
- zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_abstract_class_function, &ai TSRMLS_CC);
-
- zend_error(E_ERROR, "Class %s contains %d abstract methods and must therefore be declared abstract (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
- ce->name, ai.cnt,
- DISPLAY_ABSTRACT_FN(0),
- DISPLAY_ABSTRACT_FN(1),
- DISPLAY_ABSTRACT_FN(2)
- );
- }
-
+ zend_verify_abstract_class(EX_T(opline->op1.u.var).class_entry TSRMLS_CC);
NEXT_OPCODE();
}
ZEND_API zend_class_entry *zend_fetch_class(char *class_name, uint class_name_len, int fetch_type TSRMLS_DC);
void zend_throw_exception_internal(zval *exception TSRMLS_DC);
ZEND_API void zend_clear_exception(TSRMLS_D);
-
+void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC);
#ifdef ZEND_WIN32
void zend_init_timeout_thread();
void zend_assign_to_variable_reference(znode *result, zval **variable_ptr_ptr, zval **value_ptr_ptr, temp_variable *Ts TSRMLS_DC);
-#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 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 ? ", ..." : "")
+
+typedef struct _zend_abstract_info {
+ zend_function *afn[MAX_ABSTRACT_INFO_CNT+1];
+ int cnt;
+} zend_abstract_info;
+
+
+static int zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai TSRMLS_DC)
+{
+ if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+ if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
+ ai->afn[ai->cnt] = fn;
+ }
+ ai->cnt++;
+ }
+ return 0;
+}
+
+
+void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_abstract_info ai;
+
+ if ((ce->ce_flags & ZEND_ACC_ABSTRACT) && !(ce->ce_flags & ZEND_ACC_ABSTRACT_CLASS)) {
+ memset(&ai, 0, sizeof(ai));
+
+ zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_abstract_class_function, &ai TSRMLS_CC);
+
+ zend_error(E_ERROR, "Class %s contains %d abstract methods and must therefore be declared abstract (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
+ ce->name, ai.cnt,
+ DISPLAY_ABSTRACT_FN(0),
+ DISPLAY_ABSTRACT_FN(1),
+ DISPLAY_ABSTRACT_FN(2)
+ );
+ }
+}
+
+
/*
* Local variables:
* tab-width: 4
top_statement:
statement
| function_declaration_statement { zend_do_early_binding(TSRMLS_C); }
- | class_declaration_statement
+ | class_declaration_statement { zend_do_early_binding(TSRMLS_C); }
;