Skip to content

Commit 43691c1

Browse files
committed
Support class variance for internal classes
1 parent 40ee566 commit 43691c1

File tree

2 files changed

+48
-21
lines changed

2 files changed

+48
-21
lines changed

Zend/zend_inheritance.c

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,18 @@ static zend_bool class_visible(zend_class_entry *ce) {
240240
}
241241

242242
static zend_class_entry *lookup_class(zend_string *name) {
243-
zend_class_entry *ce = zend_lookup_class(name);
244-
if (!ce) {
245-
return NULL;
243+
zend_class_entry *ce;
244+
if (EG(active)) {
245+
ce = zend_lookup_class(name);
246+
} else {
247+
/* When a class lookup is necessary during internal class registration in early
248+
* startup, look it up in CG(class_table), as the executor is not active yet. */
249+
zend_string *lcname = zend_string_tolower(name);
250+
ce = zend_hash_find_ptr(CG(class_table), lcname);
251+
zend_string_release(lcname);
246252
}
247253

248-
return class_visible(ce) ? ce : NULL;
254+
return ce && class_visible(ce) ? ce : NULL;
249255
}
250256

251257
static zend_class_entry *resolve_and_lookup_class(const zend_function *fe, zend_string *name) {
@@ -284,8 +290,8 @@ static inheritance_status _check_covariance(
284290
}
285291

286292
if (ZEND_TYPE_IS_CLASS(proto_type)) {
287-
zend_string *proto_class_name;
288-
zend_string *fe_class_name;
293+
zend_string *proto_class_name, *fe_class_name;
294+
zend_class_entry *proto_ce, *fe_ce;
289295
if (!ZEND_TYPE_IS_CLASS(fe_type)) {
290296
return INHERITANCE_ERROR;
291297
}
@@ -300,20 +306,15 @@ static inheritance_status _check_covariance(
300306
return INHERITANCE_SUCCESS;
301307
}
302308

303-
if (fe->common.type == ZEND_USER_FUNCTION) {
304-
zend_class_entry *fe_ce = lookup_class(fe_class_name);
305-
zend_class_entry *proto_ce = lookup_class(proto_class_name);
306-
if (!fe_ce || !proto_ce) {
307-
return INHERITANCE_UNRESOLVED;
308-
}
309-
310-
return instanceof_function(fe_ce, proto_ce)
311-
? INHERITANCE_SUCCESS
312-
: INHERITANCE_ERROR;
313-
} else {
314-
/* TODO: what should this actually do? */
315-
return INHERITANCE_ERROR;
309+
fe_ce = lookup_class(fe_class_name);
310+
proto_ce = lookup_class(proto_class_name);
311+
if (!fe_ce || !proto_ce) {
312+
return INHERITANCE_UNRESOLVED;
316313
}
314+
315+
return instanceof_function(fe_ce, proto_ce)
316+
? INHERITANCE_SUCCESS
317+
: INHERITANCE_ERROR;
317318
}
318319

319320
switch (proto_type_code) {

ext/zend_test/test.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,37 @@ static int zend_test_class_call_method(zend_string *method, zend_object *object,
179179
}
180180
/* }}} */
181181

182+
static ZEND_METHOD(_ZendTestClass, varianceTest) /* {{{ */ {
183+
RETURN_TRUE;
184+
}
185+
/* }}} */
186+
187+
static ZEND_METHOD(_ZendTestChildClass, varianceTest) /* {{{ */ {
188+
RETURN_TRUE;
189+
}
190+
/* }}} */
191+
182192
static ZEND_METHOD(_ZendTestTrait, testMethod) /* {{{ */ {
183193
RETURN_TRUE;
184194
}
185195
/* }}} */
186196

197+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_parent, 0, 0, _ZendTestClass, 0)
198+
ZEND_END_ARG_INFO()
199+
200+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_child, 0, 0, _ZendTestChildClass, 0)
201+
ZEND_END_ARG_INFO()
202+
203+
static const zend_function_entry zend_test_class_methods[] = {
204+
ZEND_ME(_ZendTestClass, varianceTest, arginfo_parent, ZEND_ACC_PUBLIC)
205+
ZEND_FE_END
206+
};
207+
208+
static const zend_function_entry zend_test_child_class_methods[] = {
209+
ZEND_ME(_ZendTestChildClass, varianceTest, arginfo_child, ZEND_ACC_PUBLIC)
210+
ZEND_FE_END
211+
};
212+
187213
static const zend_function_entry zend_test_trait_methods[] = {
188214
ZEND_ME(_ZendTestTrait, testMethod, NULL, ZEND_ACC_PUBLIC)
189215
ZEND_FE_END
@@ -196,7 +222,7 @@ PHP_MINIT_FUNCTION(zend_test)
196222
INIT_CLASS_ENTRY(class_entry, "_ZendTestInterface", NULL);
197223
zend_test_interface = zend_register_internal_interface(&class_entry);
198224
zend_declare_class_constant_long(zend_test_interface, ZEND_STRL("DUMMY"), 0);
199-
INIT_CLASS_ENTRY(class_entry, "_ZendTestClass", NULL);
225+
INIT_CLASS_ENTRY(class_entry, "_ZendTestClass", zend_test_class_methods);
200226
zend_test_class = zend_register_internal_class_ex(&class_entry, NULL);
201227
zend_class_implements(zend_test_class, 1, zend_test_interface);
202228
zend_test_class->create_object = zend_test_class_new;
@@ -234,7 +260,7 @@ PHP_MINIT_FUNCTION(zend_test)
234260
zend_string_release(name);
235261
}
236262

237-
INIT_CLASS_ENTRY(class_entry, "_ZendTestChildClass", NULL);
263+
INIT_CLASS_ENTRY(class_entry, "_ZendTestChildClass", zend_test_child_class_methods);
238264
zend_test_child_class = zend_register_internal_class_ex(&class_entry, zend_test_class);
239265

240266
memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers));

0 commit comments

Comments
 (0)