/* handlers */
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
+ zend_class_entry **interfaces;
+ zend_uint num_interfaces;
+
/* old handlers */
#if 0
void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
{
zval **obj, **class_name;
char *lcname;
- zend_class_entry *ce = NULL;
+ zend_class_entry *instance_ce;
+ zend_class_entry **ce;
+ zend_bool retval;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &obj, &class_name)==FAILURE) {
ZEND_WRONG_PARAM_COUNT();
lcname = estrndup(Z_STRVAL_PP(class_name), Z_STRLEN_PP(class_name));
zend_str_tolower(lcname, Z_STRLEN_PP(class_name));
- if (only_subclass)
- ce = Z_OBJCE_PP(obj)->parent;
- else
- ce = Z_OBJCE_PP(obj);
- for (; ce != NULL; ce = ce->parent) {
- if ((ce->name_length == Z_STRLEN_PP(class_name)) && !memcmp(ce->name, lcname, ce->name_length)) {
- efree(lcname);
- RETURN_TRUE;
+ if (zend_hash_find(EG(class_table), lcname, Z_STRLEN_PP(class_name)+1, (void **) &ce)==FAILURE) {
+ efree(lcname);
+ retval = 0;
+ } else {
+ if (only_subclass) {
+ instance_ce = Z_OBJCE_PP(obj)->parent;
+ } else {
+ instance_ce = Z_OBJCE_PP(obj);
+ }
+
+ if (instanceof_function(instance_ce, *ce TSRMLS_CC)) {
+ retval = 1;
+ } else {
+ retval = 0;
}
}
+
efree(lcname);
- RETURN_FALSE;
+
+ RETURN_BOOL(retval);
}
void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body TSRMLS_DC)
{
+ char *method_type;
+
+ if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
+ modifiers->u.constant.value.lval |= ZEND_ACC_ABSTRACT;
+ method_type = "Interface";
+ } else {
+ method_type = "Abstract";
+ }
+
if (modifiers->u.constant.value.lval & ZEND_ACC_ABSTRACT) {
- if (body->u.constant.value.lval & ZEND_ACC_ABSTRACT) {
+ if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_RAISE_ABSTRACT_ERROR;
SET_UNUSED(opline->op2);
} else {
/* we had code in the function body */
- zend_error(E_COMPILE_ERROR, "Abstract function %s() cannot contain body", function_name->u.constant.value.str.val);
+ zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
}
} else {
- if (body->u.constant.value.lval & ZEND_ACC_ABSTRACT) {
- zend_error(E_COMPILE_ERROR, "Non-abstract method %s() must contain body", function_name->u.constant.value.str.val);
+ if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
+ zend_error(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
}
}
}
return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL));
}
+
void zend_do_begin_import(TSRMLS_D)
{
zend_llist_init(&CG(import_commands), sizeof(zend_op), NULL, 0);
}
+
void zend_do_import(int type, znode *what TSRMLS_DC)
{
zend_op opline;
zend_llist_add_element(&CG(import_commands), &opline);
}
+
void zend_do_end_import(znode *import_from TSRMLS_DC)
{
zend_llist_element *le;
zend_op *opline, *opline_ptr;
-
le = CG(import_commands).head;
}
-
void zend_do_begin_variable_parse(TSRMLS_D)
{
zend_llist fetch_list;
}
-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_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC)
{
zend_op_array op_array;
char *name = function_name->u.constant.value.str.val;
int name_len = function_name->u.constant.value.str.len;
int function_begin_line = function_token->u.opline_num;
+ zend_uint fn_flags;
+
+ if (is_method) {
+ if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
+ if (!(fn_flags_znode->u.constant.value.lval & ZEND_ACC_PUBLIC)) {
+ zend_error(E_COMPILE_ERROR, "Access type for interface method %s::%s() must be omitted or declared public", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
+ }
+ fn_flags_znode->u.constant.value.lval |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */
+ }
+ fn_flags = fn_flags_znode->u.constant.value.lval; /* must be done *after* the above check */
+ } else {
+ fn_flags = 0;
+ }
function_token->u.op_array = CG(active_op_array);
zend_str_tolower(name, name_len);
&& (child_op_array == parent_op_array)) {
zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
} else {
- zend_error(E_COMPILE_ERROR, "Cannot redeclare %s()", name);
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name);
}
}
void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
{
+ if ((ce->ce_flags & ZEND_ACC_INTERFACE)
+ && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
+ zend_error(E_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name);
+ }
+
ce->parent = parent_ce;
/* Inherit properties */
do_inherit_parent_constructor(ce);
}
+
+void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface)
+{
+ zend_hash_merge(&ce->constants_table, &iface->constants_table, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0);
+ zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
+}
+
+
static void create_class(HashTable *class_table, char *name, int name_length, zend_class_entry **ce TSRMLS_DC)
{
zend_class_entry *new_class_entry;
#include "../TSRM/tsrm_strtok_r.h"
-static int create_nested_class(HashTable *class_table, char *path, zend_class_entry *new_ce TSRMLS_DC)
+static zend_class_entry *create_nested_class(HashTable *class_table, char *path, zend_class_entry *new_ce TSRMLS_DC)
{
char *cur, *temp;
char *last;
if (zend_hash_add(&ce->class_table, last, strlen(last)+1, &new_ce, sizeof(zend_class_entry *), NULL) == FAILURE) {
new_ce->refcount--;
zend_error(E_COMPILE_ERROR, "Cannot redeclare class '%s' - class or namespace with this name already exist.", last);
- return FAILURE;
+ return NULL;
}
- return SUCCESS;
+ return new_ce;
}
ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time)
}
-ZEND_API int 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 *function_table, HashTable *class_table TSRMLS_DC)
{
zend_class_entry *ce, **pce;
if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) {
zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val);
- return FAILURE;
+ return NULL;
} else {
ce = *pce;
}
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);
- return FAILURE;
+ return NULL;
} else {
- return SUCCESS;
+ return ce;
}
}
-ZEND_API int 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 *function_table, HashTable *class_table, zend_class_entry *parent_ce TSRMLS_DC)
{
zend_class_entry *ce, **pce;
int found_ce;
if (found_ce == FAILURE) {
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", (*pce)->name);
- return FAILURE;
+ return NULL;
} else {
ce = *pce;
}
zend_hash_destroy(&ce->properties_info);
zend_hash_destroy(ce->static_members);
zend_hash_destroy(&ce->constants_table);
- return FAILURE;
+ return NULL;
}
- return SUCCESS;
+ return ce;
}
new_class_entry->name = class_name->u.constant.value.str.val;
new_class_entry->name_length = class_name->u.constant.value.str.len;
- new_class_entry->type = ZEND_USER_CLASS;
new_class_entry->parent = NULL;
+ new_class_entry->num_interfaces = 0;
+
zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
+ if (class_token->u.constant.value.lval == T_INTERFACE) {
+ new_class_entry->ce_flags |= ZEND_ACC_INTERFACE;
+ }
if (parent_class_name->op_type != IS_UNUSED) {
doing_inheritance = 1;
zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL);
CG(active_class_entry) = new_class_entry;
+
+ opline->result.u.var = get_temporary_variable(CG(active_op_array));
+ opline->result.op_type = IS_CONST;
+ CG(implementing_class) = opline->result;
}
void zend_do_end_class_declaration(znode *class_token TSRMLS_DC)
{
do_inherit_parent_constructor(CG(active_class_entry));
+ if (CG(active_class_entry)->num_interfaces > 0) {
+ CG(active_class_entry)->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*CG(active_class_entry)->num_interfaces);
+ }
CG(active_class_entry) = NULL;
}
+
+void zend_do_implements_interface(znode *interface_znode TSRMLS_DC)
+{
+ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+ opline->opcode = ZEND_ADD_INTERFACE;
+ opline->op1 = CG(implementing_class);
+ opline->op2 = *interface_znode;
+ opline->extended_value = CG(active_class_entry)->num_interfaces++;
+}
+
+
void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length)
{
char *prop_name;
HashTable *target_symbol_table;
zend_bool free_var_name = 0;
+ if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
+ zend_error(E_COMPILE_ERROR, "Interfaces may not include member variables");
+ }
+
if (access_type & ZEND_ACC_ABSTRACT) {
zend_error(E_COMPILE_ERROR, "Properties cannot be declared abstract");
}
#define ZEND_ACC_STATIC 0x01
#define ZEND_ACC_ABSTRACT 0x02
#define ZEND_ACC_FINAL 0x04
+#define ZEND_ACC_INTERFACE 0x08
/* The order of those must be kept - public < protected < private */
#define ZEND_ACC_PUBLIC 0x10
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_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode 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);
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 int do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table TSRMLS_DC);
-ZEND_API int 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_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);
+void zend_do_implements_interface(znode *interface_znode TSRMLS_DC);
void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce);
+void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface);
void zend_do_early_binding(TSRMLS_D);
void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC);
#define ZEND_START_NAMESPACE 143
+#define ZEND_ADD_INTERFACE 144
+
/* end of block */
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 instantiate abstract class %s", EX_T(EX(opline)->op1.u.var).EA.class_entry->name);
+ char *class_type;
+
+ if (EX_T(EX(opline)->op1.u.var).EA.class_entry->ce_flags & ZEND_ACC_INTERFACE) {
+ class_type = "interface";
+ } else {
+ class_type = "abstract_class";
+ }
+ zend_error(E_ERROR, "Cannot instantiate %s %s", class_type, 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);
int zend_declare_class_handler(ZEND_OPCODE_HANDLER_ARGS)
{
- do_bind_class(EX(opline), EG(function_table), EG(class_table) TSRMLS_CC);
+ EX_T(EX(opline)->result.u.var).EA.class_entry = do_bind_class(EX(opline), EG(function_table), EG(class_table) TSRMLS_CC);
NEXT_OPCODE();
}
int zend_declare_inherited_class_handler(ZEND_OPCODE_HANDLER_ARGS)
{
- do_bind_inherited_class(EX(opline), EG(function_table), EG(class_table), EX_T(EX(opline)->extended_value).EA.class_entry TSRMLS_CC);
+ EX_T(EX(opline)->result.u.var).EA.class_entry = do_bind_inherited_class(EX(opline), EG(function_table), EG(class_table), EX_T(EX(opline)->extended_value).EA.class_entry TSRMLS_CC);
NEXT_OPCODE();
}
int zend_instanceof_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval *expr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
- instanceof_function(&EX_T(EX(opline)->result.u.var).tmp_var, expr,
- EX_T(EX(opline)->op2.u.var).EA.class_entry TSRMLS_CC);
+ zend_bool result;
+
+ if (Z_TYPE_P(expr) == IS_OBJECT) {
+ result = instanceof_function(Z_OBJCE_P(expr), EX_T(EX(opline)->op2.u.var).EA.class_entry TSRMLS_CC);
+ } else {
+ result = 0;
+ }
+ ZVAL_BOOL(&EX_T(EX(opline)->result.u.var).tmp_var, result);
FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1));
NEXT_OPCODE();
}
NEXT_OPCODE();
}
+
+int zend_add_interface_handler(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_class_entry *ce = EX_T(EX(opline)->op1.u.var).EA.class_entry;
+ zend_class_entry *iface = EX_T(EX(opline)->op2.u.var).EA.class_entry;
+
+ if (!(iface->ce_flags & ZEND_ACC_INTERFACE)) {
+ zend_error(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name);
+ }
+
+ ce->interfaces[EX(opline)->extended_value] = iface;
+
+ zend_do_implement_interface(ce, iface);
+
+ NEXT_OPCODE();
+}
+
void zend_init_opcodes_handlers()
{
zend_opcode_handlers[ZEND_NOP] = zend_nop_handler;
zend_opcode_handlers[ZEND_RAISE_ABSTRACT_ERROR] = zend_raise_abstract_error_handler;
zend_opcode_handlers[ZEND_START_NAMESPACE] = zend_start_namespace_handler;
+
+ zend_opcode_handlers[ZEND_ADD_INTERFACE] = zend_add_interface_handler;
}
/*
zend_bool increment_lineno;
zend_llist import_commands;
+ znode implementing_class;
zend_uint access_type;
};
%token T_ISSET
%token T_EMPTY
%token T_CLASS
+%token T_INTERFACE
%token T_EXTENDS
+%token T_IMPLEMENTS
%token T_OBJECT_OPERATOR
%token T_DOUBLE_ARROW
%token T_LIST
| T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); }
| ';' /* empty statement */
| T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}'
- T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+ T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
additional_catches
| T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
| T_IMPORT { zend_do_begin_import(TSRMLS_C); } import_rule T_FROM import_namespace { zend_do_end_import(&$5 TSRMLS_CC); } ';'
;
non_empty_additional_catches:
- non_empty_additional_catches T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
- | T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+ non_empty_additional_catches T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
+ | T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
;
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); }
+ T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, NULL TSRMLS_CC); }
'(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
;
unticked_class_declaration_statement:
- 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); }
+ class_entry_type T_STRING extends_from
+ { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
+ implements_list
+ '{'
+ class_statement_list
+ '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
+;
+
+
+class_entry_type:
+ T_CLASS { $$.u.constant.value.lval = T_CLASS; }
+ | T_INTERFACE { $$.u.constant.value.lval = T_INTERFACE; }
;
namespace_declaration_statement:
extends_from:
/* empty */ { $$.op_type = IS_UNUSED; }
- | T_EXTENDS catch_class_entry { $$ = $2; }
+ | T_EXTENDS fully_qualified_class_name { $$ = $2; }
+;
+
+implements_list:
+ /* empty */
+ | T_IMPLEMENTS interface_list
;
-declaration_class_name:
- namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class_name(&$$, &$1, &$3, 0 TSRMLS_CC); }
- |
+interface_list:
+ fully_qualified_class_name { zend_do_implements_interface(&$1 TSRMLS_CC); }
+ | interface_list ',' fully_qualified_class_name { zend_do_implements_interface(&$3 TSRMLS_CC); }
;
foreach_optional_arg:
class_statement:
variable_modifiers { CG(access_type) = $1.u.constant.value.lval; } class_variable_declaration ';'
| class_constant_declaration ';'
- | 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); } '('
+ | 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 TSRMLS_CC); } '('
parameter_list ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
;
| T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, NULL, NULL TSRMLS_CC); }
;
-catch_class_entry:
+fully_qualified_class_name:
namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); }
| T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
;
return T_CLASS;
}
+<ST_IN_SCRIPTING>"interface" {
+ return T_INTERFACE;
+}
+
<ST_IN_SCRIPTING>"extends" {
return T_EXTENDS;
}
+<ST_IN_SCRIPTING>"implements" {
+ return T_IMPLEMENTS;
+}
+
<ST_IN_SCRIPTING>"namespace" {
return T_NAMESPACE;
}
FREE_HASHTABLE(ce->static_members);
zend_hash_destroy(&ce->constants_table);
zend_hash_destroy(&ce->class_table);
+ if (ce->num_interfaces > 0) {
+ efree(ce->interfaces);
+ }
efree(ce);
break;
case ZEND_INTERNAL_CLASS:
}
-ZEND_API int instanceof_function(zval *result, zval *op1, zend_class_entry *class TSRMLS_DC)
+ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC)
{
- if (Z_TYPE_P(op1) == IS_OBJECT) {
- zend_class_entry *ce;
- for (ce = Z_OBJCE_P(op1); ce != NULL; ce = ce->parent) {
- if (ce == class) {
- ZVAL_BOOL(result, 1);
- return SUCCESS;
+ zend_uint i;
+
+ while (instance_ce) {
+ if (instance_ce == ce) {
+ return 1;
+ }
+ for (i=0; i<instance_ce->num_interfaces; i++) {
+
+ if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
+ return 1;
}
}
+ instance_ce = instance_ce->parent;
}
- ZVAL_BOOL(result, 0);
- return SUCCESS;
+
+ return 0;
}
#define LOWER_CASE 1
ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
-ZEND_API int instanceof_function(zval *result, zval *op1, zend_class_entry *ce TSRMLS_DC);
+ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC);
static inline zend_bool is_numeric_string(char *str, int length, long *lval, double *dval, zend_bool allow_errors)
{