Skip to content

Commit e8d5b37

Browse files
committed
handle return type visibility enforcement
1 parent 5dd1464 commit e8d5b37

File tree

6 files changed

+136
-78
lines changed

6 files changed

+136
-78
lines changed

Zend/zend_vm_def.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,10 +1851,7 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
18511851
HANDLE_EXCEPTION();
18521852
}
18531853
} else {
1854-
outer_ce = CACHED_PTR(opline->extended_value);
1855-
if (UNEXPECTED(outer_ce == NULL)) {
1856-
outer_ce = Z_CE_P(EX_VAR(opline->op1.var));
1857-
}
1854+
outer_ce = Z_CE_P(EX_VAR(opline->op1.var));
18581855
}
18591856

18601857
inner_class_name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
@@ -4518,6 +4515,24 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
45184515
}
45194516

45204517
SAVE_OPLINE();
4518+
4519+
if (Z_OBJCE_P(retval_ptr)->required_scope) {
4520+
if (EX(func)->common.fn_flags & ZEND_ACC_PUBLIC) {
4521+
if (Z_OBJCE_P(retval_ptr)->required_scope_absolute) {
4522+
zend_type_error("Method %s is public but returns a private class: %s", ZSTR_VAL(EX(func)->common.function_name), ZSTR_VAL(Z_OBJCE_P(retval_ptr)->name));
4523+
HANDLE_EXCEPTION();
4524+
} else {
4525+
zend_type_error("Method %s is public but returns a protected class: %s", ZSTR_VAL(EX(func)->common.function_name), ZSTR_VAL(Z_OBJCE_P(retval_ptr)->name));
4526+
HANDLE_EXCEPTION();
4527+
}
4528+
} else if (EX(func)->common.fn_flags & ZEND_ACC_PROTECTED) {
4529+
if (Z_OBJCE_P(retval_ptr)->required_scope_absolute && Z_OBJCE_P(retval_ptr)->required_scope != EX(func)->common.scope) {
4530+
zend_type_error("Method %s is protected but returns a private class: %s", ZSTR_VAL(EX(func)->common.function_name), ZSTR_VAL(Z_OBJCE_P(retval_ptr)->name));
4531+
HANDLE_EXCEPTION();
4532+
}
4533+
}
4534+
}
4535+
45214536
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
45224537
zend_verify_return_error(EX(func), retval_ptr);
45234538
HANDLE_EXCEPTION();
@@ -8264,6 +8279,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
82648279

82658280
case ZEND_FETCH_CLASS:
82668281
case ZEND_DECLARE_ANON_CLASS:
8282+
case ZEND_FETCH_INNER_CLASS:
82678283
break; /* return value is zend_class_entry pointer */
82688284

82698285
default:

Zend/zend_vm_execute.h

Lines changed: 94 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/classes/inner_classes_014.phpt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ private inner class
66
class Outer {
77
private class Inner {}
88

9-
public function getInner(): self:>Inner {
9+
private function getInner(): self:>Inner {
1010
return new self:>Inner();
1111
}
12+
13+
public function getInner2(): mixed {
14+
return $this->getInner();
15+
}
1216
}
1317

1418
class Foo extends Outer {
1519
public function getInner(): parent:>Inner {
16-
var_dump(parent::getInner());
20+
var_dump(parent::getInner2());
1721
return new parent:>Inner();
1822
}
1923
}

tests/classes/inner_classes_015.phpt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ protected inner class
66
class Outer {
77
protected class Inner {}
88

9-
public function getInner(): self:>Inner {
9+
protected function getInner(): self:>Inner {
1010
return new self:>Inner();
1111
}
1212
}
@@ -25,7 +25,9 @@ var_dump(new Outer:>Inner());
2525
--EXPECTF--
2626
object(Outer:>Inner)#2 (0) {
2727
}
28-
object(Outer:>Inner)#2 (0) {
29-
}
3028

31-
Fatal error: Class 'Outer:>Inner' is protected in %s on line %d
29+
Fatal error: Uncaught TypeError: Method getInner is public but returns a protected class: Outer:>Inner in %s:%d
30+
Stack trace:
31+
#0 %s(%d): Foo->getInner()
32+
#1 {main}
33+
thrown in %s on line %d

0 commit comments

Comments
 (0)