mirror of
https://github.com/php/php-src.git
synced 2024-11-27 11:53:33 +08:00
- Implement public/protected/private methods.
- Prevent instantiation of classes with abstract methods. Based in part on Marcus's patch.
This commit is contained in:
parent
e0a972c061
commit
e062dffe6c
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -123,6 +123,8 @@ struct _zend_compiler_globals {
|
||||
zend_bool increment_lineno;
|
||||
|
||||
zend_llist import_commands;
|
||||
|
||||
int access_type;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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); }
|
||||
;
|
||||
|
||||
|
@ -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" {
|
||||
|
Loading…
Reference in New Issue
Block a user