- Implement public/protected/private methods.

- Prevent instantiation of classes with abstract methods.
Based in part on Marcus's patch.
This commit is contained in:
Zeev Suraski 2002-12-06 17:09:44 +00:00
parent e0a972c061
commit e062dffe6c
10 changed files with 269 additions and 65 deletions

View File

@ -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 File

@ -295,6 +295,8 @@ 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;
@ -302,6 +304,7 @@ struct _zend_class_entry {
struct _zend_class_entry *parent;
int refcount;
zend_bool constants_updated;
zend_uint ce_flags;
HashTable function_table;
HashTable default_properties;

View File

@ -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 File

@ -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 File

@ -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);

View File

@ -2251,6 +2251,55 @@ int zend_init_ctor_call_handler(ZEND_OPCODE_HANDLER_ARGS)
NEXT_OPCODE();
}
/* Ensures that we're allowed to call a private method.
* Will update EX(fbc) with the correct handler as necessary.
*/
inline int zend_check_private(zend_execute_data *execute_data, zend_class_entry *ce, int fn_flags, char *function_name_strval, int function_name_strlen TSRMLS_DC)
{
if (!ce) {
return 0;
}
/* We may call a private function in one of two cases:
* 1. The scope of the function is the same as the class entry of our object
* 2. The class of our object is different, but a private function exists
* in one of the ancestor that corresponds to our object's ce.
*/
if (EX(fbc)->common.scope == ce) {
/* rule #1 checks out ok, allow the function call */
return 1;
}
/* Check rule #2 */
while (ce) {
if (ce == EG(scope)) {
if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==SUCCESS
&& EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE
&& EX(fbc)->common.scope == EG(scope)) {
return 1;
}
break;
}
ce = ce->parent;
}
return 0;
}
/* Ensures that we're allowed to call a protected method.
*/
inline int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope, int fn_flags)
{
while (ce) {
if (ce==scope) {
return 1;
}
ce = ce->parent;
}
return 0;
}
int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval *function_name;
@ -2268,15 +2317,33 @@ int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
EX(object) = get_obj_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R TSRMLS_CC);
if (EX(object) && EX(object)->type == IS_OBJECT) {
/* First, locate the function. */
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);
zend_error(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
}
if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) {
/* No further checks necessary, most common case */
} else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) {
/* Ensure that if we're calling a private function, we're allowed to do so.
*/
if (!zend_check_private(execute_data, EX(object)->value.obj.handlers->get_class_entry(EX(object) TSRMLS_CC), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) {
zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
}
} else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) {
/* Ensure that if we're calling a protected function, we're allowed to do so.
*/
if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) {
zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
}
}
} else {
zend_error(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
}
if (EX(fbc)->common.fn_flags & FN_STATIC) {
if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
EX(object) = NULL;
} else {
if (!PZVAL_IS_REF(EX(object))) {
@ -2305,7 +2372,6 @@ int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval *function_name;
zend_function *function;
zval tmp;
zend_class_entry *ce;
zend_bool is_const;
@ -2335,8 +2401,25 @@ int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
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::%s()", ce->name, function_name_strval);
if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==FAILURE) {
zend_error(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);
}
EX(calling_scope) = EX(fbc)->common.scope;
if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) {
/* No further checks necessary, most common case */
} else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) {
/* Ensure that if we're calling a private function, we're allowed to do so.
*/
if (!zend_check_private(execute_data, EG(scope), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) {
zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
}
} else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) {
/* Ensure that if we're calling a protected function, we're allowed to do so.
*/
if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) {
zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
}
}
if (!is_const) {
@ -2344,9 +2427,7 @@ int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2));
}
EX(fbc) = function;
if (function->common.fn_flags & FN_STATIC) {
if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
EX(object) = NULL;
} else {
if ((EX(object) = EG(This))) {
@ -2916,6 +2997,9 @@ int zend_switch_free_handler(ZEND_OPCODE_HANDLER_ARGS)
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 instanciate abstract class %s", 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);
object_init_ex(EX_T(EX(opline)->result.u.var).var.ptr, EX_T(EX(opline)->op1.u.var).EA.class_entry);

View File

@ -123,6 +123,8 @@ struct _zend_compiler_globals {
zend_bool increment_lineno;
zend_llist import_commands;
int access_type;
};

View File

@ -39,6 +39,7 @@ typedef int (*compare_func_t)(const void *, const void * TSRMLS_DC);
typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC);
typedef void (*dtor_func_t)(void *pDest);
typedef void (*copy_ctor_func_t)(void *pElement);
typedef void (*copy_ctor_param_func_t)(void *pElement, void *pParam);
struct _hashtable;

View File

@ -110,10 +110,7 @@
%token T_THROW
%token T_USE
%token T_GLOBAL
%token T_STATIC
%token T_ABSTRACT
%token T_PRIVATE
%token T_PROTECTED
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
%token T_VAR
%token T_UNSET
%token T_ISSET
@ -273,6 +270,12 @@ class_declaration_statement:
;
is_reference:
/* empty */ { $$.op_type = ZEND_RETURN_VAL; }
| '&' { $$.op_type = ZEND_RETURN_REF; }
;
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); }
'(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
@ -437,46 +440,53 @@ class_statement_list:
class_statement:
class_variable_declaration ';'
variable_modifier { CG(access_type) = $1.u.constant.value.lval; } class_variable_declaration ';'
| class_constant_declaration ';'
| 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); } '('
| 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); } '('
parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); }
| T_ABSTRACT method_modifiers T_FUNCTION { $3.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$3, &$6, 1, $5.op_type, $2.u.constant.value.lval | ZEND_ACC_ABSTRACT TSRMLS_CC); } '('
parameter_list ')' { zend_do_abstract_method(TSRMLS_C); zend_do_end_function_declaration(&$3 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, 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 = FN_STATIC; }
| /* empty */ { $$.u.constant.value.lval = 0; }
variable_modifier:
access_modifier { $$ = $1; }
| T_VAR { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; }
| T_STATIC { $$.u.constant.value.lval = ZEND_ACC_STATIC; }
;
is_reference:
/* empty */ { $$.op_type = ZEND_RETURN_VAL; }
| '&' { $$.op_type = ZEND_RETURN_REF; }
method_modifiers:
/* empty */ { $$.u.constant.value.lval = 0; }
| non_empty_method_modifiers { $$ = $1; }
;
non_empty_method_modifiers:
T_STATIC { $$.u.constant.value.lval = ZEND_ACC_STATIC; }
| access_modifier { $$ = $1; }
| non_empty_method_modifiers T_STATIC { $$.u.constant.value.lval = $1.u.constant.value.lval | ZEND_ACC_STATIC; }
| non_empty_method_modifiers access_modifier { $$.u.constant.value.lval = zend_do_verify_access_types(&$1, &$2); }
;
access_modifier:
T_PUBLIC { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; }
| T_PROTECTED { $$.u.constant.value.lval = ZEND_ACC_PROTECTED; }
| T_PRIVATE { $$.u.constant.value.lval = ZEND_ACC_PRIVATE; }
;
class_variable_declaration:
class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL, $1.op_type TSRMLS_CC); }
| class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5, $1.op_type TSRMLS_CC); }
| class_declaration_type T_VARIABLE { $$ = $1; zend_do_declare_property(&$2, NULL, $1.op_type TSRMLS_CC); }
| class_declaration_type T_VARIABLE '=' static_scalar { $$ = $1; zend_do_declare_property(&$2, &$4, $1.op_type TSRMLS_CC); }
;
class_declaration_type:
T_VAR { $$.op_type = T_VAR; }
| T_STATIC { $$.op_type = T_STATIC; }
| T_PRIVATE { $$.op_type = T_PRIVATE; }
| T_PROTECTED { $$.op_type = T_PROTECTED; }
class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL TSRMLS_CC); }
| class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5 TSRMLS_CC); }
| T_VARIABLE { zend_do_declare_property(&$1, NULL TSRMLS_CC); }
| T_VARIABLE '=' static_scalar { zend_do_declare_property(&$1, &$3 TSRMLS_CC); }
;
class_constant_declaration:
| T_CONST ',' T_STRING '=' static_scalar { zend_do_declare_property(&$3, &$5, T_CONST TSRMLS_CC); }
| T_CONST T_STRING '=' static_scalar { zend_do_declare_property(&$2, &$4, T_CONST TSRMLS_CC); }
class_constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); }
| T_CONST T_STRING '=' static_scalar { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); }
;
echo_expr_list:
| echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
| expr { zend_do_echo(&$1 TSRMLS_CC); }
;

View File

@ -730,6 +730,10 @@ NEWLINE ("\r"|"\n"|"\r\n")
return T_ABSTRACT;
}
<ST_IN_SCRIPTING>"final" {
return T_FINAL;
}
<ST_IN_SCRIPTING>"private" {
return T_PRIVATE;
}
@ -739,7 +743,7 @@ NEWLINE ("\r"|"\n"|"\r\n")
}
<ST_IN_SCRIPTING>"public" {
return T_VAR;
return T_PUBLIC;
}
<ST_IN_SCRIPTING>"unset" {