1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Leverage object_init_with_constructor() in zend_get_attribute_object() (#14532)

This commit is contained in:
Tim Düsterhus
2024-06-10 15:12:22 +02:00
committed by GitHub
parent 10a6f0bd92
commit 193d3850b2
4 changed files with 35 additions and 95 deletions

View File

@@ -72,19 +72,6 @@ try {
echo "\n";
#[Attribute]
class A4 { }
$ref = new \ReflectionFunction(#[A4(1)] function () { });
try {
$ref->getAttributes()[0]->newInstance();
} catch (\Error $e) {
var_dump('ERROR 5', $e->getMessage());
}
echo "\n";
class A5 { }
$ref = new \ReflectionFunction(#[A5] function () { });
@@ -111,10 +98,7 @@ string(7) "ERROR 3"
string(30) "Attribute class "A2" not found"
string(7) "ERROR 4"
string(48) "Attribute constructor of class A3 must be public"
string(7) "ERROR 5"
string(69) "Attribute class A4 does not have a constructor, cannot pass arguments"
string(51) "Call to private A3::__construct() from global scope"
string(7) "ERROR 6"
string(55) "Attempting to use non-attribute class "A5" as attribute"

View File

@@ -25,20 +25,20 @@ foreach ((new ReflectionClass(C::class))->getAttributes() as $reflectionAttribut
}
?>
--EXPECT--
object(Attr)#1 (1) {
--EXPECTF--
object(Attr)#%d (1) {
["value"]=>
string(1) "B"
}
object(Attr)#1 (1) {
object(Attr)#%d (1) {
["value"]=>
string(1) "C"
}
object(Attr)#1 (1) {
object(Attr)#%d (1) {
["value"]=>
string(1) "B"
}
object(Attr)#1 (1) {
object(Attr)#%d (1) {
["value"]=>
string(1) "C"
}

View File

@@ -214,18 +214,9 @@ ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, u
return SUCCESS;
}
static zend_result call_attribute_constructor(
zend_attribute *attr, zend_class_entry *ce, zend_object *obj,
zval *args, uint32_t argc, HashTable *named_params, zend_string *filename)
ZEND_API zend_result zend_get_attribute_object(zval *obj, zend_class_entry *attribute_ce, zend_attribute *attribute_data, zend_class_entry *scope, zend_string *filename)
{
zend_function *ctor = ce->constructor;
zend_execute_data *call = NULL;
ZEND_ASSERT(ctor != NULL);
if (!(ctor->common.fn_flags & ZEND_ACC_PUBLIC)) {
zend_throw_error(NULL, "Attribute constructor of class %s must be public", ZSTR_VAL(ce->name));
return FAILURE;
}
if (filename) {
/* Set up dummy call frame that makes it look like the attribute was invoked
@@ -244,7 +235,7 @@ static zend_result call_attribute_constructor(
opline = (zend_op*)(call + 1);
memset(opline, 0, sizeof(zend_op));
opline->opcode = ZEND_DO_FCALL;
opline->lineno = attr->lineno;
opline->lineno = attribute_data->lineno;
call->opline = opline;
call->call = NULL;
@@ -255,57 +246,17 @@ static zend_result call_attribute_constructor(
memset(call->func, 0, sizeof(zend_function));
call->func->type = ZEND_USER_FUNCTION;
call->func->op_array.fn_flags =
attr->flags & ZEND_ATTRIBUTE_STRICT_TYPES ? ZEND_ACC_STRICT_TYPES : 0;
attribute_data->flags & ZEND_ATTRIBUTE_STRICT_TYPES ? ZEND_ACC_STRICT_TYPES : 0;
call->func->op_array.fn_flags |= ZEND_ACC_CALL_VIA_TRAMPOLINE;
call->func->op_array.filename = filename;
EG(current_execute_data) = call;
}
zend_call_known_function(ctor, obj, obj->ce, NULL, argc, args, named_params);
if (filename) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_call_frame(call);
}
if (EG(exception)) {
zend_object_store_ctor_failed(obj);
return FAILURE;
}
return SUCCESS;
}
static void attribute_ctor_cleanup(zval *obj, zval *args, uint32_t argc, HashTable *named_params)
{
if (obj) {
zval_ptr_dtor(obj);
}
if (args) {
uint32_t i;
for (i = 0; i < argc; i++) {
zval_ptr_dtor(&args[i]);
}
efree(args);
}
if (named_params) {
zend_array_destroy(named_params);
}
}
ZEND_API zend_result zend_get_attribute_object(zval *obj, zend_class_entry *attribute_ce, zend_attribute *attribute_data, zend_class_entry *scope, zend_string *filename)
{
zval *args = NULL;
HashTable *named_params = NULL;
if (SUCCESS != object_init_ex(obj, attribute_ce)) {
return FAILURE;
}
zend_result result = FAILURE;
uint32_t argc = 0;
if (attribute_data->argc) {
@@ -314,8 +265,8 @@ ZEND_API zend_result zend_get_attribute_object(zval *obj, zend_class_entry *attr
for (uint32_t i = 0; i < attribute_data->argc; i++) {
zval val;
if (FAILURE == zend_get_attribute_value(&val, attribute_data, i, scope)) {
attribute_ctor_cleanup(obj, args, argc, named_params);
return FAILURE;
result = FAILURE;
goto out;
}
if (attribute_data->args[i].name) {
if (!named_params) {
@@ -329,20 +280,25 @@ ZEND_API zend_result zend_get_attribute_object(zval *obj, zend_class_entry *attr
}
}
if (attribute_ce->constructor) {
if (FAILURE == call_attribute_constructor(attribute_data, attribute_ce, Z_OBJ_P(obj), args, argc, named_params, filename)) {
attribute_ctor_cleanup(obj, args, argc, named_params);
return FAILURE;
}
} else if (argc || named_params) {
attribute_ctor_cleanup(obj, args, argc, named_params);
zend_throw_error(NULL, "Attribute class %s does not have a constructor, cannot pass arguments", ZSTR_VAL(attribute_ce->name));
return FAILURE;
result = object_init_with_constructor(obj, attribute_ce, argc, args, named_params);
out:
for (uint32_t i = 0; i < argc; i++) {
zval_ptr_dtor(&args[i]);
}
attribute_ctor_cleanup(NULL, args, argc, named_params);
efree(args);
return SUCCESS;
if (named_params) {
zend_array_destroy(named_params);
}
if (filename) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_call_frame(call);
}
return result;
}
static const char *target_names[] = {

View File

@@ -36,34 +36,34 @@ $obj = $ra->newInstance();
var_dump($args, $obj);
?>
--EXPECT--
--EXPECTF--
array(2) {
[0]=>
NULL
[1]=>
object(stdClass)#3 (0) {
object(stdClass)#%d (0) {
}
}
object(MyAttribute)#4 (2) {
object(MyAttribute)#%d (2) {
["x"]=>
NULL
["y"]=>
object(stdClass)#5 (0) {
object(stdClass)#%d (0) {
}
}
bool(true)
bool(true)
array(2) {
["y"]=>
object(stdClass)#2 (0) {
object(stdClass)#%d (0) {
}
["x"]=>
NULL
}
object(MyAttribute)#10 (2) {
object(MyAttribute)#%d (2) {
["x"]=>
NULL
["y"]=>
object(stdClass)#11 (0) {
object(stdClass)#%d (0) {
}
}