Last active
August 29, 2015 14:15
-
-
Save dstogov/dbf2a8f46e43719bd2c2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--TEST-- | |
001 Annotations | |
--FILE-- | |
<?php | |
<check> | |
<optimization_level(2)> | |
<requires($a >= 0)> | |
<requires($b >= 0)> | |
<ensures($ret >= 0)> | |
function foo($a, $b) { | |
return $a + $b; | |
} | |
$r = new ReflectionFunction('foo'); | |
var_dump($r->getAnnotations()); | |
?> | |
--EXPECT-- | |
array(4) { | |
["check"]=> | |
bool(true) | |
["optimization_level"]=> | |
int(2) | |
["requires"]=> | |
array(2) { | |
[0]=> | |
AST | |
[1]=> | |
AST | |
} | |
["ensures"]=> | |
AST | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y | |
index 009d7ba..c71af8a 100644 | |
--- a/Zend/zend_language_parser.y | |
+++ b/Zend/zend_language_parser.y | |
@@ -58,6 +58,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); | |
%destructor { zend_ast_destroy($$); } <ast> | |
%destructor { if ($$) zend_string_release($$); } <str> | |
+%destructor { if ($$) zend_hash_destroy($$); FREE_HASHTABLE($$); } <hash> | |
%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE | |
%left ',' | |
@@ -225,14 +226,14 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); | |
%token T_POW "** (T_POW)" | |
%token T_POW_EQUAL "**= (T_POW_EQUAL)" | |
-%type <ast> top_statement namespace_name name statement function_declaration_statement | |
+%type <ast> top_statement namespace_name name statement annotated_statement function_declaration_statement | |
%type <ast> class_declaration_statement trait_declaration_statement | |
%type <ast> interface_declaration_statement interface_extends_list | |
%type <ast> use_declaration const_decl inner_statement | |
%type <ast> expr optional_expr while_statement for_statement foreach_variable | |
%type <ast> foreach_statement declare_statement finally_statement unset_variable variable | |
%type <ast> extends_from parameter optional_type argument expr_without_variable global_var | |
-%type <ast> static_var class_statement trait_adaptation trait_precedence trait_alias | |
+%type <ast> static_var class_statement annotated_class_statement trait_adaptation trait_precedence trait_alias | |
%type <ast> absolute_trait_method_reference trait_method_reference property echo_expr | |
%type <ast> new_expr class_name class_name_reference simple_variable internal_functions_in_yacc | |
%type <ast> exit_expr scalar backticks_expr lexical_var function_call member_name | |
@@ -255,6 +256,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); | |
%type <str> backup_doc_comment | |
+%type <hash> backup_annotations | |
+ | |
%% /* Rules */ | |
start: | |
@@ -277,12 +280,28 @@ name: | |
| T_NS_SEPARATOR namespace_name { $$ = $2; $$->attr = ZEND_NAME_FQ; } | |
; | |
-top_statement: | |
- statement { $$ = $1; } | |
- | function_declaration_statement { $$ = $1; } | |
+ | |
+annotation: | |
+ '<' T_STRING '>' { zend_add_annotation($2, NULL); } | |
+ | '<' T_STRING '(' expr ')' '>' { zend_add_annotation($2, $4); } | |
+; | |
+ | |
+annotations: | |
+ annotations annotation | |
+ | annotation | |
+; | |
+ | |
+annotated_statement: | |
+ function_declaration_statement { $$ = $1; } | |
| class_declaration_statement { $$ = $1; } | |
| trait_declaration_statement { $$ = $1; } | |
| interface_declaration_statement { $$ = $1; } | |
+; | |
+ | |
+top_statement: | |
+ statement { $$ = $1; } | |
+ | annotated_statement { $$ = $1; } | |
+ | annotations annotated_statement { $$ = $2; } | |
| T_HALT_COMPILER '(' ')' ';' | |
{ $$ = zend_ast_create(ZEND_AST_HALT_COMPILER, | |
zend_ast_create_zval_from_long(zend_get_scanned_file_offset())); | |
@@ -334,11 +353,9 @@ inner_statement_list: | |
inner_statement: | |
- statement { $$ = $1; } | |
- | function_declaration_statement { $$ = $1; } | |
- | class_declaration_statement { $$ = $1; } | |
- | trait_declaration_statement { $$ = $1; } | |
- | interface_declaration_statement { $$ = $1; } | |
+ statement { $$ = $1; } | |
+ | annotated_statement { $$ = $1; } | |
+ | annotations annotated_statement { $$ = $2; } | |
| T_HALT_COMPILER '(' ')' ';' | |
{ $$ = NULL; zend_error_noreturn(E_COMPILE_ERROR, | |
"__HALT_COMPILER() can only be used from the outermost scope"); } | |
@@ -406,9 +423,9 @@ unset_variable: | |
function_declaration_statement: | |
function returns_ref T_STRING '(' parameter_list ')' return_type | |
- backup_doc_comment '{' inner_statement_list '}' | |
- { $$ = zend_ast_create_decl(ZEND_AST_FUNC_DECL, $2, $1, $8, | |
- zend_ast_get_str($3), $5, NULL, $10, $7); } | |
+ backup_doc_comment backup_annotations '{' inner_statement_list '}' | |
+ { $$ = zend_ast_create_decl(ZEND_AST_FUNC_DECL, $2, $1, $8, $9, | |
+ zend_ast_get_str($3), $5, NULL, $11, $7); } | |
; | |
is_reference: | |
@@ -423,11 +440,11 @@ is_variadic: | |
class_declaration_statement: | |
class_modifiers T_CLASS { $<num>$ = CG(zend_lineno); } | |
- T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' | |
- { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $<num>3, $7, zend_ast_get_str($4), $5, $6, $9, NULL); } | |
+ T_STRING extends_from implements_list backup_doc_comment backup_annotations '{' class_statement_list '}' | |
+ { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $<num>3, $7, $8, zend_ast_get_str($4), $5, $6, $10, NULL); } | |
| T_CLASS { $<num>$ = CG(zend_lineno); } | |
- T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' | |
- { $$ = zend_ast_create_decl(ZEND_AST_CLASS, 0, $<num>2, $6, zend_ast_get_str($3), $4, $5, $8, NULL); } | |
+ T_STRING extends_from implements_list backup_doc_comment backup_annotations '{' class_statement_list '}' | |
+ { $$ = zend_ast_create_decl(ZEND_AST_CLASS, 0, $<num>2, $6, $7, zend_ast_get_str($3), $4, $5, $9, NULL); } | |
; | |
class_modifiers: | |
@@ -442,14 +459,14 @@ class_modifier: | |
trait_declaration_statement: | |
T_TRAIT { $<num>$ = CG(zend_lineno); } | |
- T_STRING backup_doc_comment '{' class_statement_list '}' | |
- { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $<num>2, $4, zend_ast_get_str($3), NULL, NULL, $6, NULL); } | |
+ T_STRING backup_doc_comment backup_annotations '{' class_statement_list '}' | |
+ { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $<num>2, $4, $5, zend_ast_get_str($3), NULL, NULL, $7, NULL); } | |
; | |
interface_declaration_statement: | |
T_INTERFACE { $<num>$ = CG(zend_lineno); } | |
- T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}' | |
- { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $<num>2, $5, zend_ast_get_str($3), NULL, $4, $7, NULL); } | |
+ T_STRING interface_extends_list backup_doc_comment backup_annotations '{' class_statement_list '}' | |
+ { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $<num>2, $5, $6, zend_ast_get_str($3), NULL, $4, $8, NULL); } | |
; | |
extends_from: | |
@@ -629,18 +646,22 @@ class_statement_list: | |
{ $$ = zend_ast_create_list(0, ZEND_AST_STMT_LIST); } | |
; | |
- | |
-class_statement: | |
+annotated_class_statement: | |
variable_modifiers property_list ';' | |
{ $$ = zend_ast_append_doc_comment($2); $$->attr = $1; } | |
+ | method_modifiers function returns_ref T_STRING '(' parameter_list ')' | |
+ return_type backup_doc_comment backup_annotations method_body | |
+ { $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1, $2, $9, $10, | |
+ zend_ast_get_str($4), $6, NULL, $11, $8); } | |
+; | |
+ | |
+class_statement: | |
+ annotated_class_statement { $$ = $1; } | |
+ | annotations annotated_class_statement { $$ = $2; } | |
| T_CONST class_const_list ';' | |
{ $$ = $2; RESET_DOC_COMMENT(); } | |
| T_USE name_list trait_adaptations | |
{ $$ = zend_ast_create(ZEND_AST_USE_TRAIT, $2, $3); } | |
- | method_modifiers function returns_ref T_STRING '(' parameter_list ')' | |
- return_type backup_doc_comment method_body | |
- { $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1, $2, $9, | |
- zend_ast_get_str($4), $6, NULL, $10, $8); } | |
; | |
name_list: | |
@@ -873,15 +894,15 @@ expr_without_variable: | |
| T_YIELD expr { $$ = zend_ast_create(ZEND_AST_YIELD, $2, NULL); } | |
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = zend_ast_create(ZEND_AST_YIELD, $4, $2); } | |
| function returns_ref '(' parameter_list ')' lexical_vars return_type | |
- backup_doc_comment '{' inner_statement_list '}' | |
- { $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $2, $1, $8, | |
+ backup_doc_comment backup_annotations '{' inner_statement_list '}' | |
+ { $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $2, $1, $8, $9, | |
zend_string_init("{closure}", sizeof("{closure}") - 1, 0), | |
- $4, $6, $10, $7); } | |
+ $4, $6, $11, $7); } | |
| T_STATIC function returns_ref '(' parameter_list ')' lexical_vars | |
- return_type backup_doc_comment '{' inner_statement_list '}' | |
- { $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $3 | ZEND_ACC_STATIC, $2, $9, | |
+ return_type backup_doc_comment backup_annotations '{' inner_statement_list '}' | |
+ { $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $3 | ZEND_ACC_STATIC, $2, $9, $10, | |
zend_string_init("{closure}", sizeof("{closure}") - 1, 0), | |
- $5, $7, $11, $8); } | |
+ $5, $7, $12, $8); } | |
; | |
function: | |
@@ -892,6 +913,10 @@ backup_doc_comment: | |
/* empty */ { $$ = CG(doc_comment); CG(doc_comment) = NULL; } | |
; | |
+backup_annotations: | |
+ /* empty */ { $$ = CG(annotations); CG(annotations) = NULL; } | |
+; | |
+ | |
returns_ref: | |
/* empty */ { $$ = 0; } | |
| '&' { $$ = ZEND_ACC_RETURN_REFERENCE; } | |
diff --git a/Zend/zend.h b/Zend/zend.h | |
index 9d65675..7968749 100644 | |
--- a/Zend/zend.h | |
+++ b/Zend/zend.h | |
@@ -181,6 +181,7 @@ struct _zend_class_entry { | |
uint32_t line_start; | |
uint32_t line_end; | |
zend_string *doc_comment; | |
+ HashTable *annotations; | |
} user; | |
struct { | |
const struct _zend_function_entry *builtin_functions; | |
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h | |
index 0a4c146..4501b88 100644 | |
--- a/Zend/zend_compile.h | |
+++ b/Zend/zend_compile.h | |
@@ -48,6 +48,11 @@ | |
zend_string_release(CG(doc_comment)); \ | |
CG(doc_comment) = NULL; \ | |
} \ | |
+ if (CG(annotations)) { \ | |
+ zend_hash_destroy(CG(annotations)); \ | |
+ FREE_HASHTABLE(CG(annotations)); \ | |
+ CG(annotations) = NULL; \ | |
+ } \ | |
} while (0) | |
typedef struct _zend_op_array zend_op_array; | |
@@ -119,6 +124,7 @@ static zend_always_inline znode *zend_ast_get_znode(zend_ast *ast) { | |
typedef union _zend_parser_stack_elem { | |
zend_ast *ast; | |
zend_string *str; | |
+ HashTable *hash; | |
zend_ulong num; | |
} zend_parser_stack_elem; | |
@@ -266,6 +272,7 @@ typedef struct _zend_property_info { | |
uint32_t flags; | |
zend_string *name; | |
zend_string *doc_comment; | |
+ HashTable *annotations; | |
zend_class_entry *ce; | |
} zend_property_info; | |
@@ -347,6 +354,7 @@ struct _zend_op_array { | |
uint32_t line_start; | |
uint32_t line_end; | |
zend_string *doc_comment; | |
+ HashTable *annotations; | |
uint32_t early_binding; /* the linked list of delayed declarations */ | |
int last_literal; | |
@@ -649,6 +657,7 @@ zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right); | |
uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag); | |
uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag); | |
zend_ast *zend_ast_append_doc_comment(zend_ast *list); | |
+void zend_add_annotation(zend_ast *name, zend_ast *value); | |
void zend_handle_encoding_declaration(zend_ast *ast); | |
/* parser-driven code generators */ | |
diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h | |
index a9d5842..392c1f3 100644 | |
--- a/Zend/zend_ast.h | |
+++ b/Zend/zend_ast.h | |
@@ -182,6 +182,7 @@ typedef struct _zend_ast_decl { | |
uint32_t flags; | |
unsigned char *lex_pos; | |
zend_string *doc_comment; | |
+ HashTable *annotations; | |
zend_string *name; | |
zend_ast *child[4]; | |
} zend_ast_decl; | |
@@ -195,7 +196,7 @@ ZEND_API zend_ast *zend_ast_create_ex(zend_ast_kind kind, zend_ast_attr attr, .. | |
ZEND_API zend_ast *zend_ast_create(zend_ast_kind kind, ...); | |
ZEND_API zend_ast *zend_ast_create_decl( | |
- zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment, | |
+ zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment, HashTable *annotations, | |
zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3 | |
); | |
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h | |
index abebb19..11f6f64 100644 | |
--- a/Zend/zend_globals.h | |
+++ b/Zend/zend_globals.h | |
@@ -108,6 +108,7 @@ struct _zend_compiler_globals { | |
znode implementing_class; | |
zend_string *doc_comment; | |
+ HashTable *annotations; | |
uint32_t compiler_options; /* set of ZEND_COMPILE_* constants */ | |
diff --git a/Zend/zend_API.c b/Zend/zend_API.c | |
index fe6ae33..6aa7633 100644 | |
--- a/Zend/zend_API.c | |
+++ b/Zend/zend_API.c | |
@@ -3481,6 +3481,7 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z | |
property_info->name = zend_new_interned_string(property_info->name); | |
property_info->flags = access_type; | |
property_info->doc_comment = doc_comment; | |
+ property_info->annotations = NULL; // TODO: add annotations support??? | |
property_info->ce = ce; | |
zend_hash_update_ptr(&ce->properties_info, name, property_info); | |
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c | |
index 242c99f..fee6d1f 100644 | |
--- a/Zend/zend_ast.c | |
+++ b/Zend/zend_ast.c | |
@@ -66,7 +66,7 @@ ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr) { | |
} | |
ZEND_API zend_ast *zend_ast_create_decl( | |
- zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment, | |
+ zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment, HashTable *annotations, | |
zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3 | |
) { | |
zend_ast_decl *ast; | |
@@ -79,6 +79,7 @@ ZEND_API zend_ast *zend_ast_create_decl( | |
ast->flags = flags; | |
ast->lex_pos = LANG_SCNG(yy_text); | |
ast->doc_comment = doc_comment; | |
+ ast->annotations = annotations; | |
ast->name = name; | |
ast->child[0] = child0; | |
ast->child[1] = child1; | |
@@ -394,6 +395,10 @@ static void zend_ast_destroy_ex(zend_ast *ast, zend_bool free) { | |
if (decl->doc_comment) { | |
zend_string_release(decl->doc_comment); | |
} | |
+ if (decl->annotations) { | |
+ zend_hash_destroy(decl->annotations); | |
+ FREE_HASHTABLE(decl->annotations); | |
+ } | |
zend_ast_destroy_ex(decl->child[0], free); | |
zend_ast_destroy_ex(decl->child[1], free); | |
zend_ast_destroy_ex(decl->child[2], free); | |
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c | |
index 3605525..fef93fb 100644 | |
--- a/Zend/zend_compile.c | |
+++ b/Zend/zend_compile.c | |
@@ -79,6 +79,10 @@ static void zend_destroy_property_info(zval *zv) /* {{{ */ | |
if (property_info->doc_comment) { | |
zend_string_release(property_info->doc_comment); | |
} | |
+ if (property_info->annotations) { | |
+ zend_hash_destroy(property_info->annotations); | |
+ FREE_HASHTABLE(property_info->annotations); | |
+ } | |
} | |
/* }}} */ | |
@@ -1429,6 +1433,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify | |
} else { | |
ce->static_members_table = ce->default_static_members_table; | |
ce->info.user.doc_comment = NULL; | |
+ ce->info.user.annotations = NULL; | |
} | |
ce->default_properties_count = 0; | |
@@ -1519,10 +1524,53 @@ zend_ast *zend_ast_append_doc_comment(zend_ast *list) /* {{{ */ | |
CG(doc_comment) = NULL; | |
} | |
+ if (CG(annotations)) { | |
+ // TODO: Annotations support | |
+ } | |
+ | |
return list; | |
} | |
/* }}} */ | |
+void zend_add_annotation(zend_ast *name, zend_ast *value) /* {{{ */ | |
+{ | |
+ zval *old, *val, tmp; | |
+ zend_string *key = zend_ast_get_str(name); | |
+ | |
+ if (!CG(annotations)) { | |
+ ALLOC_HASHTABLE(CG(annotations)); | |
+ zend_hash_init(CG(annotations), 8, NULL, ZVAL_PTR_DTOR, 0); | |
+ } | |
+ if (value) { | |
+ if (value->kind == ZEND_AST_ZVAL) { | |
+ val = zend_ast_get_zval(value); | |
+ } else { | |
+ ZVAL_NEW_AST(&tmp, value); | |
+ val = &tmp; | |
+ } | |
+ } else { | |
+ ZVAL_TRUE(&tmp); | |
+ val = &tmp; | |
+ } | |
+ | |
+ old = zend_hash_find(CG(annotations), key); | |
+ if (old) { | |
+ zval arr; | |
+ | |
+ if (Z_TYPE_P(old) != IS_ARRAY) { | |
+ array_init(&arr); | |
+ zend_hash_next_index_insert_new(Z_ARRVAL(arr), old); | |
+ if (Z_REFCOUNTED_P(old)) Z_ADDREF_P(old); | |
+ zend_hash_update(CG(annotations), key, &arr); | |
+ old = &arr; | |
+ } | |
+ zend_hash_next_index_insert_new(Z_ARRVAL_P(old), val); | |
+ } else { | |
+ zend_hash_add_new(CG(annotations), key, val); | |
+ } | |
+} | |
+/* }}} */ | |
+ | |
void zend_verify_namespace(void) /* {{{ */ | |
{ | |
if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { | |
@@ -4269,6 +4317,9 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */ | |
if (decl->doc_comment) { | |
op_array->doc_comment = zend_string_copy(decl->doc_comment); | |
} | |
+ if (decl->annotations) { | |
+ op_array->annotations = zend_array_dup(decl->annotations); | |
+ } | |
if (decl->kind == ZEND_AST_CLOSURE) { | |
op_array->fn_flags |= ZEND_ACC_CLOSURE; | |
} | |
@@ -4625,6 +4676,9 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ | |
if (decl->doc_comment) { | |
ce->info.user.doc_comment = zend_string_copy(decl->doc_comment); | |
} | |
+ if (decl->annotations) { | |
+ ce->info.user.annotations = zend_array_dup(decl->annotations); | |
+ } | |
if (extends_ast) { | |
if (!zend_is_const_default_class_ref(extends_ast)) { | |
diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l | |
index 0081192..015ca90 100644 | |
--- a/Zend/zend_language_scanner.l | |
+++ b/Zend/zend_language_scanner.l | |
@@ -178,6 +178,7 @@ void startup_scanner(void) | |
{ | |
CG(parse_error) = 0; | |
CG(doc_comment) = NULL; | |
+ CG(annotations) = NULL; | |
zend_stack_init(&SCNG(state_stack), sizeof(int)); | |
zend_ptr_stack_init(&SCNG(heredoc_label_stack)); | |
} | |
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c | |
index c1e3adb..2f4a669 100644 | |
--- a/Zend/zend_opcode.c | |
+++ b/Zend/zend_opcode.c | |
@@ -66,6 +66,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz | |
op_array->function_name = NULL; | |
op_array->filename = zend_get_compiled_filename(); | |
op_array->doc_comment = NULL; | |
+ op_array->annotations = NULL; | |
op_array->arg_info = NULL; | |
op_array->num_args = 0; | |
@@ -269,6 +270,10 @@ ZEND_API void destroy_zend_class(zval *zv) | |
if (ce->info.user.doc_comment) { | |
zend_string_release(ce->info.user.doc_comment); | |
} | |
+ if (ce->info.user.annotations) { | |
+ zend_hash_destroy(ce->info.user.annotations); | |
+ FREE_HASHTABLE(ce->info.user.annotations); | |
+ } | |
_destroy_zend_class_traits_info(ce); | |
@@ -357,6 +362,10 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) | |
if (op_array->doc_comment) { | |
zend_string_release(op_array->doc_comment); | |
} | |
+ if (op_array->annotations) { | |
+ zend_hash_destroy(op_array->annotations); | |
+ FREE_HASHTABLE(op_array->annotations); | |
+ } | |
if (op_array->brk_cont_array) { | |
efree(op_array->brk_cont_array); | |
} | |
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c | |
index 1f16c4d..8fe52f3 100644 | |
--- a/ext/reflection/php_reflection.c | |
+++ b/ext/reflection/php_reflection.c | |
@@ -1837,6 +1837,25 @@ ZEND_METHOD(reflection_function, getDocComment) | |
} | |
/* }}} */ | |
+/* {{{ proto public mixed ReflectionFunction::getAnnotations() | |
+ Returns the annotations for this function */ | |
+ZEND_METHOD(reflection_function, getAnnotations) | |
+{ | |
+ reflection_object *intern; | |
+ zend_function *fptr; | |
+ | |
+ if (zend_parse_parameters_none() == FAILURE) { | |
+ return; | |
+ } | |
+ GET_REFLECTION_OBJECT_PTR(fptr); | |
+ if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.annotations) { | |
+ ZVAL_ARR(return_value, zend_array_dup(fptr->op_array.annotations)); | |
+ return; | |
+ } | |
+ RETURN_NULL(); | |
+} | |
+/* }}} */ | |
+ | |
/* {{{ proto public array ReflectionFunction::getStaticVariables() | |
Returns an associative array containing this function's static variables and their values */ | |
ZEND_METHOD(reflection_function, getStaticVariables) | |
@@ -5741,6 +5760,7 @@ static const zend_function_entry reflection_function_abstract_functions[] = { | |
ZEND_ME(reflection_function, getClosureThis, arginfo_reflection__void, 0) | |
ZEND_ME(reflection_function, getClosureScopeClass, arginfo_reflection__void, 0) | |
ZEND_ME(reflection_function, getDocComment, arginfo_reflection__void, 0) | |
+ ZEND_ME(reflection_function, getAnnotations, arginfo_reflection__void, 0) | |
ZEND_ME(reflection_function, getEndLine, arginfo_reflection__void, 0) | |
ZEND_ME(reflection_function, getExtension, arginfo_reflection__void, 0) | |
ZEND_ME(reflection_function, getExtensionName, arginfo_reflection__void, 0) | |
diff --git a/ext/standard/var.c b/ext/standard/var.c | |
index 5e986d45..2f9d280 100644 | |
--- a/ext/standard/var.c | |
+++ b/ext/standard/var.c | |
@@ -199,6 +199,9 @@ again: | |
struc = Z_REFVAL_P(struc); | |
goto again; | |
break; | |
+ case IS_CONSTANT_AST: | |
+ php_printf("%sAST\n", COMMON); | |
+ break; | |
default: | |
php_printf("%sUNKNOWN:0\n", COMMON); | |
break; | |
@@ -361,6 +364,9 @@ again: | |
} | |
struc = Z_REFVAL_P(struc); | |
goto again; | |
+ case IS_CONSTANT_AST: | |
+ php_printf("%sAST\n", COMMON); | |
+ break; | |
default: | |
php_printf("%sUNKNOWN:0\n", COMMON); | |
break; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment