Skip to content

Commit fd42159

Browse files
committed
feat(reflection): add getLine / getFileName / isUserDefined to reflection attribute
1 parent 2508138 commit fd42159

6 files changed

+143
-12
lines changed

‎ext/reflection/php_reflection.c

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ typedef struct _attribute_reference {
147147
zend_attribute *data;
148148
zend_class_entry *scope;
149149
zend_string *filename;
150+
bool is_user_defined;
150151
uint32_t target;
151152
} attribute_reference;
152153

@@ -1116,7 +1117,7 @@ static void _extension_string(smart_str *str, zend_module_entry *module, char *i
11161117

11171118
/* {{{ reflection_attribute_factory */
11181119
static void reflection_attribute_factory(zval *object, HashTable *attributes, zend_attribute *data,
1119-
zend_class_entry *scope, uint32_t target, zend_string *filename)
1120+
zend_class_entry *scope, uint32_t target, zend_string *filename, bool is_user_defined)
11201121
{
11211122
reflection_object *intern;
11221123
attribute_reference *reference;
@@ -1129,14 +1130,15 @@ static void reflection_attribute_factory(zval *object, HashTable *attributes, ze
11291130
reference->scope = scope;
11301131
reference->filename = filename ? zend_string_copy(filename) : NULL;
11311132
reference->target = target;
1133+
reference->is_user_defined = is_user_defined;
11321134
intern->ptr = reference;
11331135
intern->ref_type = REF_TYPE_ATTRIBUTE;
11341136
ZVAL_STR_COPY(reflection_prop_name(object), data->name);
11351137
}
11361138
/* }}} */
11371139

11381140
static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *scope,
1139-
uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename) /* {{{ */
1141+
uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename, bool is_user_defined) /* {{{ */
11401142
{
11411143
ZEND_ASSERT(attributes != NULL);
11421144

@@ -1149,7 +1151,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
11491151

11501152
ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
11511153
if (attr->offset == offset && zend_string_equals(attr->lcname, filter)) {
1152-
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1154+
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename, is_user_defined);
11531155
add_next_index_zval(ret, &tmp);
11541156
}
11551157
} ZEND_HASH_FOREACH_END();
@@ -1181,7 +1183,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
11811183
}
11821184
}
11831185

1184-
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1186+
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename, is_user_defined);
11851187
add_next_index_zval(ret, &tmp);
11861188
} ZEND_HASH_FOREACH_END();
11871189

@@ -1190,7 +1192,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
11901192
/* }}} */
11911193

11921194
static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes,
1193-
uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */
1195+
uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename, bool is_user_defined) /* {{{ */
11941196
{
11951197
zend_string *name = NULL;
11961198
zend_long flags = 0;
@@ -1223,7 +1225,7 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut
12231225

12241226
array_init(return_value);
12251227

1226-
if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename)) {
1228+
if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename, is_user_defined)) {
12271229
RETURN_THROWS();
12281230
}
12291231
}
@@ -1956,7 +1958,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getAttributes)
19561958

19571959
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
19581960
fptr->common.attributes, 0, fptr->common.scope, target,
1959-
fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL);
1961+
fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL, ZEND_USER_CODE(fptr->type));
19601962
}
19611963
/* }}} */
19621964

@@ -2837,7 +2839,7 @@ ZEND_METHOD(ReflectionParameter, getAttributes)
28372839

28382840
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
28392841
attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER,
2840-
param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL);
2842+
param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL, ZEND_USER_CODE(param->fptr->type));
28412843
}
28422844

28432845
/* {{{ Returns whether this parameter is an optional parameter */
@@ -4021,7 +4023,7 @@ ZEND_METHOD(ReflectionClassConstant, getAttributes)
40214023

40224024
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
40234025
ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST,
4024-
ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL);
4026+
ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL, ref->ce->type == ZEND_USER_CLASS);
40254027
}
40264028
/* }}} */
40274029

@@ -4429,7 +4431,7 @@ ZEND_METHOD(ReflectionClass, getAttributes)
44294431

44304432
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
44314433
ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS,
4432-
ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL);
4434+
ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL, ce->type == ZEND_USER_CLASS);
44334435
}
44344436
/* }}} */
44354437

@@ -5866,7 +5868,7 @@ ZEND_METHOD(ReflectionProperty, getAttributes)
58665868

58675869
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
58685870
ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY,
5869-
ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL);
5871+
ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL, ref->prop->ce->type == ZEND_USER_CLASS);
58705872
}
58715873
/* }}} */
58725874

@@ -6681,6 +6683,53 @@ ZEND_METHOD(ReflectionAttribute, getArguments)
66816683
}
66826684
/* }}} */
66836685

6686+
/* {{{ Returns true if the attribute is defined by user land code, false otherwise */
6687+
ZEND_METHOD(ReflectionAttribute, isUserDefined)
6688+
{
6689+
reflection_object *intern;
6690+
attribute_reference *attr;
6691+
6692+
if (zend_parse_parameters_none() == FAILURE) {
6693+
RETURN_THROWS();
6694+
}
6695+
GET_REFLECTION_OBJECT_PTR(attr);
6696+
6697+
RETURN_BOOL(attr->is_user_defined);
6698+
}
6699+
/* }}} */
6700+
6701+
/* {{{ Returns the filename (if it exists : user land code) at which the attribute was defined */
6702+
ZEND_METHOD(ReflectionAttribute, getFileName)
6703+
{
6704+
reflection_object *intern;
6705+
attribute_reference *attr;
6706+
6707+
if (zend_parse_parameters_none() == FAILURE) {
6708+
RETURN_THROWS();
6709+
}
6710+
GET_REFLECTION_OBJECT_PTR(attr);
6711+
if (attr->filename != NULL) {
6712+
RETURN_STR_COPY(attr->filename);
6713+
}
6714+
RETURN_FALSE;
6715+
}
6716+
/* }}} */
6717+
6718+
/* {{{ Returns the line at which the attribute was defined */
6719+
ZEND_METHOD(ReflectionAttribute, getLine)
6720+
{
6721+
reflection_object *intern;
6722+
attribute_reference *attr;
6723+
6724+
if (zend_parse_parameters_none() == FAILURE) {
6725+
RETURN_THROWS();
6726+
}
6727+
GET_REFLECTION_OBJECT_PTR(attr);
6728+
6729+
RETURN_LONG(attr->data->lineno);
6730+
}
6731+
/* }}} */
6732+
66846733
static int call_attribute_constructor(
66856734
zend_attribute *attr, zend_class_entry *ce, zend_object *obj,
66866735
zval *args, uint32_t argc, HashTable *named_params, zend_string *filename)

‎ext/reflection/php_reflection.stub.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,9 @@ public function getTarget(): int {}
771771
public function isRepeated(): bool {}
772772
public function getArguments(): array {}
773773
public function newInstance(): object {}
774+
public function isUserDefined(): bool {}
775+
public function getFileName(): string|false {}
776+
public function getLine(): int {}
774777

775778
public function __toString(): string {}
776779

‎ext/reflection/php_reflection_arginfo.h

Lines changed: 14 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
ReflectionAttribute getFileName
3+
--FILE--
4+
<?php
5+
#[Attribute]
6+
class A {}
7+
8+
class Foo {
9+
#[A]
10+
public function bar() {}
11+
}
12+
13+
$rm = new ReflectionMethod(Foo::class, "bar");
14+
$attribute = $rm->getAttributes()[0];
15+
16+
if ($attribute->getFileName() === __FILE__) {
17+
echo "OK";
18+
} else {
19+
echo "FAIL";
20+
}
21+
22+
?>
23+
--EXPECT--
24+
OK
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
ReflectionAttribute getLines
3+
--FILE--
4+
<?php
5+
#[Attribute]
6+
class A {}
7+
8+
class Foo {
9+
#[A]
10+
public function bar() {}
11+
}
12+
13+
$rm = new ReflectionMethod(Foo::class, "bar");
14+
$attribute = $rm->getAttributes()[0];
15+
16+
var_dump($rm->getStartLine());
17+
var_dump($attribute->getLine());
18+
19+
?>
20+
--EXPECT--
21+
int(7)
22+
int(6)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
ReflectionAttribute isUserDefined
3+
--FILE--
4+
<?php
5+
#[Attribute]
6+
class A {}
7+
8+
class Foo {
9+
#[A]
10+
public function bar() {}
11+
}
12+
13+
$rm = new ReflectionMethod(Foo::class, "bar");
14+
$attribute = $rm->getAttributes()[0];
15+
16+
var_dump($attribute->isUserDefined());
17+
18+
?>
19+
--EXPECT--
20+
bool(true)

0 commit comments

Comments
 (0)