Skip to content

Commit fa8f991

Browse files
author
rjhdby
committed
Class extension functions
1 parent 7eb255e commit fa8f991

File tree

7 files changed

+59
-6
lines changed

7 files changed

+59
-6
lines changed

Zend/zend.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,9 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
637637
compiler_globals->static_members_table = NULL;
638638
}
639639
compiler_globals->script_encoding_list = NULL;
640+
641+
compiler_globals->class_extension_functions = (HashTable *) malloc(sizeof(HashTable));
642+
zend_hash_init_ex(compiler_globals->class_extension_functions, 8, NULL, NULL, 1, 1);
640643
}
641644
/* }}} */
642645

@@ -661,6 +664,8 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
661664
pefree((char*)compiler_globals->script_encoding_list, 1);
662665
}
663666
compiler_globals->last_static_member = 0;
667+
668+
zend_hash_destroy(compiler_globals->class_extension_functions);
664669
}
665670
/* }}} */
666671

Zend/zend_ast.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,7 @@ static ZEND_COLD void zend_ast_export_stmt(smart_str *str, zend_ast *ast, int in
11171117
case ZEND_AST_FOREACH:
11181118
case ZEND_AST_FUNC_DECL:
11191119
case ZEND_AST_METHOD:
1120+
case ZEND_AST_METHOD_EX:
11201121
case ZEND_AST_CLASS:
11211122
case ZEND_AST_USE_TRAIT:
11221123
case ZEND_AST_NAMESPACE:
@@ -1315,6 +1316,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
13151316
case ZEND_AST_FUNC_DECL:
13161317
case ZEND_AST_CLOSURE:
13171318
case ZEND_AST_METHOD:
1319+
case ZEND_AST_METHOD_EX:
13181320
decl = (zend_ast_decl *) ast;
13191321
if (decl->flags & ZEND_ACC_PUBLIC) {
13201322
smart_str_appends(str, "public ");

Zend/zend_ast.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ enum _zend_ast_kind {
4141
ZEND_AST_FUNC_DECL,
4242
ZEND_AST_CLOSURE,
4343
ZEND_AST_METHOD,
44+
ZEND_AST_METHOD_EX,
4445
ZEND_AST_CLASS,
4546

4647
/* list nodes */

Zend/zend_compile.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,7 +2287,7 @@ static inline zend_bool zend_is_unticked_stmt(zend_ast *ast) /* {{{ */
22872287
{
22882288
return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL
22892289
|| ast->kind == ZEND_AST_PROP_DECL || ast->kind == ZEND_AST_CLASS_CONST_DECL
2290-
|| ast->kind == ZEND_AST_USE_TRAIT || ast->kind == ZEND_AST_METHOD;
2290+
|| ast->kind == ZEND_AST_USE_TRAIT || ast->kind == ZEND_AST_METHOD || ast->kind == ZEND_AST_METHOD_EX;
22912291
}
22922292
/* }}} */
22932293

@@ -5634,9 +5634,8 @@ void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
56345634
}
56355635
/* }}} */
56365636

5637-
void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
5637+
void zend_begin_method_decl_ex(zend_class_entry *ce, zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
56385638
{
5639-
zend_class_entry *ce = CG(active_class_entry);
56405639
zend_bool in_interface = (ce->ce_flags & ZEND_ACC_INTERFACE) != 0;
56415640
zend_bool in_trait = (ce->ce_flags & ZEND_ACC_TRAIT) != 0;
56425641
zend_bool is_public = (op_array->fn_flags & ZEND_ACC_PUBLIC) != 0;
@@ -5677,7 +5676,11 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
56775676

56785677
if (zend_hash_add_ptr(&ce->function_table, lcname, op_array) == NULL) {
56795678
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::%s()",
5680-
ZSTR_VAL(ce->name), ZSTR_VAL(name));
5679+
ZSTR_VAL(ce->name), ZSTR_VAL(name));
5680+
}
5681+
5682+
if (ce->type == ZEND_INTERNAL_CLASS) {
5683+
zend_hash_add_ptr(CG(class_extension_functions), lcname, ce);
56815684
}
56825685

56835686
if (in_interface) {
@@ -5810,6 +5813,20 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
58105813
}
58115814
/* }}} */
58125815

5816+
void zend_begin_method_decl_ex2(zend_string *class_name, zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
5817+
{
5818+
zend_class_entry *ce = zend_lookup_class(class_name);
5819+
zend_begin_method_decl_ex(ce, op_array, name, has_body);
5820+
}
5821+
/* }}} */
5822+
5823+
void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_bool has_body) /* {{{ */
5824+
{
5825+
zend_class_entry *ce = CG(active_class_entry);
5826+
zend_begin_method_decl_ex(ce, op_array, name, has_body);
5827+
}
5828+
/* }}} */
5829+
58135830
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, zend_bool toplevel) /* {{{ */
58145831
{
58155832
zend_ast *params_ast = decl->child[0];
@@ -5876,10 +5893,17 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
58765893
{
58775894
zend_ast_decl *decl = (zend_ast_decl *) ast;
58785895
zend_ast *params_ast = decl->child[0];
5879-
zend_ast *uses_ast = decl->child[1];
5896+
zend_ast *uses_ast;
58805897
zend_ast *stmt_ast = decl->child[2];
58815898
zend_ast *return_type_ast = decl->child[3];
58825899
zend_bool is_method = decl->kind == ZEND_AST_METHOD;
5900+
zend_bool is_ex_method = decl->kind == ZEND_AST_METHOD_EX;
5901+
5902+
if(is_ex_method){
5903+
uses_ast = NULL;
5904+
} else {
5905+
uses_ast = decl->child[1];
5906+
}
58835907

58845908
zend_op_array *orig_op_array = CG(active_op_array);
58855909
zend_op_array *op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
@@ -5901,6 +5925,10 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
59015925
if (is_method) {
59025926
zend_bool has_body = stmt_ast != NULL;
59035927
zend_begin_method_decl(op_array, decl->name, has_body);
5928+
} else if (is_ex_method){
5929+
zend_bool has_body = stmt_ast != NULL;
5930+
zend_string * class_name = zend_ast_get_str(decl->child[1]);
5931+
zend_begin_method_decl_ex2(class_name, op_array, decl->name, has_body);
59045932
} else {
59055933
zend_begin_func_decl(result, op_array, decl, toplevel);
59065934
if (uses_ast) {
@@ -8122,6 +8150,7 @@ void zend_compile_stmt(zend_ast *ast) /* {{{ */
81228150
break;
81238151
case ZEND_AST_FUNC_DECL:
81248152
case ZEND_AST_METHOD:
8153+
case ZEND_AST_METHOD_EX:
81258154
zend_compile_func_decl(NULL, ast, 0);
81268155
break;
81278156
case ZEND_AST_PROP_DECL:

Zend/zend_execute_API.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@ void shutdown_executor(void) /* {{{ */
275275
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
276276
} zend_end_try();
277277

278+
zend_class_entry *temp_ce;
279+
280+
ZEND_HASH_FOREACH_STR_KEY_PTR(CG(class_extension_functions), key, temp_ce) {
281+
zend_hash_del(&temp_ce->function_table, key);
282+
zend_string_release_ex(key, 0);
283+
} ZEND_HASH_FOREACH_END();
284+
278285
if (fast_shutdown) {
279286
/* Fast Request Shutdown
280287
* =====================

Zend/zend_globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ struct _zend_compiler_globals {
125125
zval **static_members_table;
126126
int last_static_member;
127127
#endif
128+
HashTable * class_extension_functions;
128129
};
129130

130131

Zend/zend_language_parser.y

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
224224
/* Token used to force a parse error from the lexer */
225225
%token T_ERROR
226226

227-
%type <ast> top_statement namespace_name name statement function_declaration_statement
227+
%type <ast> top_statement namespace_name name statement function_declaration_statement class_extension_function_declaration_statement
228228
%type <ast> class_declaration_statement trait_declaration_statement
229229
%type <ast> interface_declaration_statement interface_extends_list
230230
%type <ast> group_use_declaration inline_use_declarations inline_use_declaration
@@ -308,6 +308,7 @@ name:
308308
top_statement:
309309
statement { $$ = $1; }
310310
| function_declaration_statement { $$ = $1; }
311+
| class_extension_function_declaration_statement { $$ = $1; }
311312
| class_declaration_statement { $$ = $1; }
312313
| trait_declaration_statement { $$ = $1; }
313314
| interface_declaration_statement { $$ = $1; }
@@ -489,6 +490,13 @@ function_declaration_statement:
489490
zend_ast_get_str($3), $6, NULL, $11, $8); CG(extra_fn_flags) = $9; }
490491
;
491492

493+
class_extension_function_declaration_statement:
494+
function returns_ref namespace_name T_OBJECT_OPERATOR T_STRING backup_doc_comment '(' parameter_list ')'
495+
return_type backup_fn_flags method_body backup_fn_flags
496+
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD_EX, $2 | ZEND_ACC_PUBLIC | $13, $1, $6,
497+
zend_ast_get_str($5), $8, $3, $12, $10); CG(extra_fn_flags) = $11; }
498+
;
499+
492500
is_reference:
493501
/* empty */ { $$ = 0; }
494502
| '&' { $$ = ZEND_PARAM_REF; }

0 commit comments

Comments
 (0)