Skip to content

Implement PHP attributes #1878

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions Zend/tests/attributes_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
--TEST--
Basic attributes usage
--FILE--
<?php
// No attributes
function f0() {
}
$r = new ReflectionFunction("f0");
var_dump($r->getAttributes());

// Function attributes
<<TestFunction>>
function foo() {
}
$r = new ReflectionFunction("foo");
var_dump($r->getAttributes());

// Class attributes
<<TestClass>>
class Bar {
<<TestConst>>
const C = 2;
<<TestProp>>
public $x = 3;

}
$r = new ReflectionClass("Bar");
var_dump($r->getAttributes());
$r1 = $r->getReflectionConstant("C");
var_dump($r1->getAttributes());
$r2 = $r->getProperty("x");
var_dump($r2->getAttributes());

// Multiple attributes with multiple values
<<a1,a2(1),a3(1,2)>>
function f1() {}
$r = new ReflectionFunction("f1");
var_dump($r->getAttributes());

// Attributes with AST
<<a1,a2(1+"a"),a3(1+"b",2+"c"),a4(["a"=>1,"b"=>2])>>
function f2() {}
$r = new ReflectionFunction("f2");
var_dump($r->getAttributes());

// Attributes with namespaces
<<Foo\Bar>>
function f4() {
}
$r = new ReflectionFunction("f4");
var_dump($r->getAttributes());
?>
--EXPECT--
array(0) {
}
array(1) {
["TestFunction"]=>
array(0) {
}
}
array(1) {
["TestClass"]=>
array(0) {
}
}
array(1) {
["TestConst"]=>
array(0) {
}
}
array(1) {
["TestProp"]=>
array(0) {
}
}
array(3) {
["a1"]=>
array(0) {
}
["a2"]=>
array(1) {
[0]=>
int(1)
}
["a3"]=>
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
}
array(4) {
["a1"]=>
array(0) {
}
["a2"]=>
array(1) {
[0]=>
object(ast\Node)#4 (4) {
["kind"]=>
int(520)
["flags"]=>
int(1)
["lineno"]=>
NULL
["children"]=>
array(2) {
[0]=>
int(1)
[1]=>
string(1) "a"
}
}
}
["a3"]=>
array(2) {
[0]=>
object(ast\Node)#5 (4) {
["kind"]=>
int(520)
["flags"]=>
int(1)
["lineno"]=>
NULL
["children"]=>
array(2) {
[0]=>
int(1)
[1]=>
string(1) "b"
}
}
[1]=>
object(ast\Node)#6 (4) {
["kind"]=>
int(520)
["flags"]=>
int(1)
["lineno"]=>
NULL
["children"]=>
array(2) {
[0]=>
int(2)
[1]=>
string(1) "c"
}
}
}
["a4"]=>
array(1) {
[0]=>
object(ast\Node)#7 (4) {
["kind"]=>
int(130)
["flags"]=>
int(0)
["lineno"]=>
NULL
["children"]=>
array(2) {
[0]=>
object(ast\Node)#8 (4) {
["kind"]=>
int(525)
["flags"]=>
int(0)
["lineno"]=>
NULL
["children"]=>
array(2) {
[0]=>
int(1)
[1]=>
string(1) "a"
}
}
[1]=>
object(ast\Node)#9 (4) {
["kind"]=>
int(525)
["flags"]=>
int(0)
["lineno"]=>
NULL
["children"]=>
array(2) {
[0]=>
int(2)
[1]=>
string(1) "b"
}
}
}
}
}
}
array(1) {
["Foo\Bar"]=>
array(0) {
}
}
39 changes: 39 additions & 0 deletions Zend/tests/attributes_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
--TEST--
Doctrine-like attributes usage
--FILE--
<?php
namespace Doctrine\ORM {

class Entity {
private $name;
public function __construct($name) {
$this->name = $name;
}
}

function GetClassAttributes($class_name) {
$reflClass = new \ReflectionClass($class_name);
$attrs = $reflClass->getAttributes();
foreach ($attrs as $name => &$values) {
$name = "Doctrine\\" . $name;
$values = new $name(...$values);
}
return $attrs;
}
}

namespace {
<<ORM\Entity("user")>>
class User {}

var_dump(Doctrine\ORM\GetClassAttributes("User"));
}
?>
--EXPECT--
array(1) {
["ORM\Entity"]=>
object(Doctrine\ORM\Entity)#2 (1) {
["name":"Doctrine\ORM\Entity":private]=>
string(4) "user"
}
}
1 change: 1 addition & 0 deletions Zend/zend.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ struct _zend_class_entry {
uint32_t line_start;
uint32_t line_end;
zend_string *doc_comment;
HashTable *attributes;
} user;
struct {
const struct _zend_function_entry *builtin_functions;
Expand Down
10 changes: 6 additions & 4 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -3598,7 +3598,7 @@ ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */
}
/* }}} */

ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */
ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, HashTable *attributes) /* {{{ */
{
zend_property_info *property_info, *property_info_ptr;

Expand Down Expand Up @@ -3667,6 +3667,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->attributes = attributes;
property_info->ce = ce;
zend_hash_update_ptr(&ce->properties_info, name, property_info);

Expand All @@ -3677,7 +3678,7 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z
ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type) /* {{{ */
{
zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS);
int ret = zend_declare_property_ex(ce, key, property, access_type, NULL);
int ret = zend_declare_property_ex(ce, key, property, access_type, NULL, NULL);
zend_string_release(key);
return ret;
}
Expand Down Expand Up @@ -3737,7 +3738,7 @@ ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *nam
}
/* }}} */

ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment) /* {{{ */
ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment, HashTable *attributes) /* {{{ */
{
zend_class_constant *c;

Expand All @@ -3760,6 +3761,7 @@ ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *n
ZVAL_COPY_VALUE(&c->value, value);
Z_ACCESS_FLAGS(c->value) = access_type;
c->doc_comment = doc_comment;
c->attributes = attributes;
c->ce = ce;
if (Z_CONSTANT_P(value)) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
Expand All @@ -3779,7 +3781,7 @@ ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name,
int ret;

zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS);
ret = zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL);
ret = zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL, NULL);
zend_string_release(key);
return ret;
}
Expand Down
6 changes: 4 additions & 2 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, zend_strin
ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_name);
ZEND_API const char *zend_get_module_version(const char *module_name);
ZEND_API int zend_get_module_started(const char *module_name);
ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment);
ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, HashTable *attributes);
ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type);
ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type);
ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type);
Expand All @@ -322,7 +322,7 @@ ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name
ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type);
ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type);

ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment);
ZEND_API int zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment, HashTable *attributes);
ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value);
ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length);
ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value);
Expand Down Expand Up @@ -623,6 +623,7 @@ END_EXTERN_C()
#define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value)
#define RETVAL_RES(r) ZVAL_RES(return_value, r)
#define RETVAL_ARR(r) ZVAL_ARR(return_value, r)
#define RETVAL_IMMUTABLE_ARR(r) ZVAL_IMMUTABLE_ARR(return_value, r)
#define RETVAL_OBJ(r) ZVAL_OBJ(return_value, r)
#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor)
#define RETVAL_FALSE ZVAL_FALSE(return_value)
Expand All @@ -641,6 +642,7 @@ END_EXTERN_C()
#define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; }
#define RETURN_RES(r) { RETVAL_RES(r); return; }
#define RETURN_ARR(r) { RETVAL_ARR(r); return; }
#define RETURN_IMMUTABLE_ARR(r) { RETVAL_IMMUTABLE_ARR(r); return; }
#define RETURN_OBJ(r) { RETVAL_OBJ(r); return; }
#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; }
#define RETURN_FALSE { RETVAL_FALSE; return; }
Expand Down
Loading