Skip to content

Commit 82a8d05

Browse files
authored
Merge pull request #2443 from Girgias/ctor-calls-refacto
Refactor object constructor calls to use new PHP 8.4 API
2 parents 90070a6 + 9565529 commit 82a8d05

File tree

1 file changed

+73
-68
lines changed

1 file changed

+73
-68
lines changed

kernel/object.c

Lines changed: 73 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,77 @@ int zephir_create_closure_ex(zval *return_value, zval *this_ptr, zend_class_entr
12261226
return SUCCESS;
12271227
}
12281228

1229+
/**
1230+
* Copied from php-src source tree for PHP 8.4
1231+
*/
1232+
#ifndef object_init_with_constructor
1233+
static zend_result object_init_with_constructor(zval *arg, zend_class_entry *class_type, uint32_t param_count, zval *params, HashTable *named_params)
1234+
{
1235+
zend_result status = object_and_properties_init(arg, class_type, NULL);
1236+
if (UNEXPECTED(status == FAILURE)) {
1237+
ZVAL_UNDEF(arg);
1238+
return FAILURE;
1239+
}
1240+
zend_object *obj = Z_OBJ_P(arg);
1241+
zend_function *constructor = obj->handlers->get_constructor(obj);
1242+
if (constructor == NULL) {
1243+
/* The constructor can be NULL for 2 different reasons:
1244+
* - It is not defined
1245+
* - We are not allowed to call the constructor (e.g. private, or internal opaque class)
1246+
* and an exception has been thrown
1247+
* in the former case, we are (mostly) done and the object is initialized,
1248+
* in the latter we need to destroy the object as initialization failed
1249+
*/
1250+
if (UNEXPECTED(EG(exception))) {
1251+
zval_ptr_dtor(arg);
1252+
ZVAL_UNDEF(arg);
1253+
return FAILURE;
1254+
}
1255+
1256+
/* Surprisingly, this is the only case where internal classes will allow to pass extra arguments
1257+
* However, if there are named arguments (and it is not empty),
1258+
* an Error must be thrown to be consistent with new ClassName() */
1259+
if (UNEXPECTED(named_params != NULL && zend_hash_num_elements(named_params) != 0)) {
1260+
/* Throw standard Error */
1261+
zend_string *arg_name = NULL;
1262+
zend_hash_get_current_key(named_params, &arg_name, /* num_index */ NULL);
1263+
ZEND_ASSERT(arg_name != NULL);
1264+
zend_throw_error(NULL, "Unknown named parameter $%s", ZSTR_VAL(arg_name));
1265+
/* Do not call destructor, free object, and set arg to IS_UNDEF */
1266+
zend_object_store_ctor_failed(obj);
1267+
zval_ptr_dtor(arg);
1268+
ZVAL_UNDEF(arg);
1269+
return FAILURE;
1270+
} else {
1271+
return SUCCESS;
1272+
}
1273+
}
1274+
/* A constructor should not return a value, however if an exception is thrown
1275+
* zend_call_known_function() will set the retval to IS_UNDEF */
1276+
zval retval;
1277+
zend_call_known_function(
1278+
constructor,
1279+
obj,
1280+
class_type,
1281+
&retval,
1282+
param_count,
1283+
params,
1284+
named_params
1285+
);
1286+
if (Z_TYPE(retval) == IS_UNDEF) {
1287+
/* Do not call destructor, free object, and set arg to IS_UNDEF */
1288+
zend_object_store_ctor_failed(obj);
1289+
zval_ptr_dtor(arg);
1290+
ZVAL_UNDEF(arg);
1291+
return FAILURE;
1292+
} else {
1293+
/* Unlikely, but user constructors may return any value they want */
1294+
zval_ptr_dtor(&retval);
1295+
return SUCCESS;
1296+
}
1297+
}
1298+
#endif
1299+
12291300
/**
12301301
* Creates a new instance dynamically. Call constructor without parameters
12311302
*/
@@ -1244,38 +1315,7 @@ int zephir_create_instance(zval *return_value, const zval *class_name)
12441315
return FAILURE;
12451316
}
12461317

1247-
if(UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
1248-
return FAILURE;
1249-
}
1250-
1251-
if (EXPECTED(Z_OBJ_HT_P(return_value)->get_constructor)) {
1252-
zend_object* obj = Z_OBJ_P(return_value);
1253-
zend_function* ctor = Z_OBJ_HT_P(return_value)->get_constructor(obj);
1254-
if (ctor) {
1255-
zend_fcall_info fci;
1256-
zend_fcall_info_cache fcc;
1257-
1258-
zend_class_entry* ce = Z_OBJCE_P(return_value);
1259-
1260-
fci.size = sizeof(fci);
1261-
fci.object = obj;
1262-
fci.retval = 0;
1263-
fci.param_count = 0;
1264-
fci.params = 0;
1265-
fci.named_params = NULL;
1266-
1267-
ZVAL_NULL(&fci.function_name);
1268-
1269-
fcc.object = obj;
1270-
fcc.called_scope = ce;
1271-
fcc.calling_scope = ce;
1272-
fcc.function_handler = ctor;
1273-
1274-
return zend_fcall_info_call(&fci, &fcc, NULL, NULL);
1275-
}
1276-
}
1277-
1278-
return SUCCESS;
1318+
return object_init_with_constructor(return_value, ce, 0, NULL, NULL);
12791319
}
12801320

12811321
/**
@@ -1301,40 +1341,5 @@ int zephir_create_instance_params(zval *return_value, const zval *class_name, zv
13011341
return FAILURE;
13021342
}
13031343

1304-
if(UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
1305-
return FAILURE;
1306-
}
1307-
1308-
if (EXPECTED(Z_OBJ_HT_P(return_value)->get_constructor)) {
1309-
zend_object* obj = Z_OBJ_P(return_value);
1310-
zend_function* ctor = Z_OBJ_HT_P(return_value)->get_constructor(obj);
1311-
if (ctor) {
1312-
int status;
1313-
zend_fcall_info fci;
1314-
zend_fcall_info_cache fcc;
1315-
1316-
zend_class_entry* ce = Z_OBJCE_P(return_value);
1317-
1318-
fci.size = sizeof(fci);
1319-
fci.object = obj;
1320-
fci.retval = 0;
1321-
fci.param_count = 0;
1322-
fci.params = 0;
1323-
fci.named_params = NULL;
1324-
1325-
ZVAL_NULL(&fci.function_name);
1326-
1327-
fcc.object = obj;
1328-
fcc.called_scope = ce;
1329-
fcc.calling_scope = ce;
1330-
fcc.function_handler = ctor;
1331-
1332-
zend_fcall_info_args_ex(&fci, fcc.function_handler, params);
1333-
status = zend_fcall_info_call(&fci, &fcc, NULL, NULL);
1334-
zend_fcall_info_args_clear(&fci, 1);
1335-
return status;
1336-
}
1337-
}
1338-
1339-
return SUCCESS;
1344+
return object_init_with_constructor(return_value, ce, 0, NULL, Z_ARRVAL_P(params));
13401345
}

0 commit comments

Comments
 (0)