Skip to content

Commit 33c01ca

Browse files
committed
enable visibility
1 parent af3e49a commit 33c01ca

File tree

7 files changed

+199
-24
lines changed

7 files changed

+199
-24
lines changed

Zend/zend_execute.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,23 @@ static zend_always_inline bool zend_check_type_slow(
11961196
}
11971197
} else {
11981198
ce = zend_fetch_ce_from_cache_slot(cache_slot, type);
1199+
1200+
// verify that the class is being used in the correct scope
1201+
if (ce && ce->required_scope) {
1202+
zend_class_entry *scope = zend_get_executed_scope();
1203+
if (ce->required_scope_absolute && scope != ce->required_scope) {
1204+
if (scope == NULL) {
1205+
zend_error(E_ERROR, "Private inner class %s cannot be used as a type declaration in the global scope", ce->name->val);
1206+
}
1207+
1208+
zend_error(E_ERROR, "Private inner class %s cannot be used as a type declaration in the scope of %s", ce->name->val, scope->name->val);
1209+
} else if (scope == NULL) {
1210+
zend_error(E_ERROR, "Protected inner class %s cannot be used as a type declaration in the global scope", ce->name->val);
1211+
} else if (!instanceof_function(scope, ce->required_scope)) {
1212+
zend_error(E_ERROR, "Protected inner class %s cannot be used as a type declaration in the scope of %s", ce->name->val, scope->name->val);
1213+
}
1214+
}
1215+
11991216
/* If we have a CE we check if it satisfies the type constraint,
12001217
* otherwise it will check if a standard type satisfies it. */
12011218
if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {

Zend/zend_vm_def.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,7 +1804,9 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
18041804
SAVE_OPLINE();
18051805

18061806
zend_string *inner_class_name, *full_class_name;
1807-
zend_class_entry *outer_ce = NULL, *inner_ce = NULL;
1807+
zend_class_entry *outer_ce = NULL, *inner_ce = NULL, *scope = NULL;
1808+
1809+
scope = EX(func)->op_array.scope;
18081810

18091811
if (OP1_TYPE == IS_CONST) {
18101812
zval *outer_class_zv = RT_CONSTANT(opline, opline->op1);
@@ -1815,10 +1817,9 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
18151817
}
18161818
} else if (OP1_TYPE == IS_UNUSED) {
18171819
uint32_t fetch_type;
1818-
zend_class_entry *called_scope, *scope;
1820+
zend_class_entry *called_scope;
18191821

1820-
fetch_type = opline->op1.num;
1821-
scope = EX(func)->op_array.scope;
1822+
fetch_type = opline->op1.num & ZEND_FETCH_CLASS_MASK;
18221823
if (UNEXPECTED(scope == NULL)) {
18231824
SAVE_OPLINE();
18241825
zend_throw_error(NULL, "Cannot use \"%s\" in the global scope",
@@ -1827,9 +1828,9 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
18271828
ZVAL_UNDEF(EX_VAR(opline->result.var));
18281829
HANDLE_EXCEPTION();
18291830
}
1830-
if (fetch_type & ZEND_FETCH_CLASS_SELF) {
1831+
if (fetch_type == ZEND_FETCH_CLASS_SELF) {
18311832
outer_ce = scope;
1832-
} else if (fetch_type & ZEND_FETCH_CLASS_PARENT) {
1833+
} else if (fetch_type == ZEND_FETCH_CLASS_PARENT) {
18331834
if (UNEXPECTED(scope->parent == NULL)) {
18341835
SAVE_OPLINE();
18351836
zend_throw_error(NULL,
@@ -1838,7 +1839,7 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
18381839
HANDLE_EXCEPTION();
18391840
}
18401841
outer_ce = scope->parent;
1841-
} else if (fetch_type & ZEND_FETCH_CLASS_STATIC) {
1842+
} else if (fetch_type == ZEND_FETCH_CLASS_STATIC) {
18421843
if (Z_TYPE(EX(This)) == IS_OBJECT) {
18431844
called_scope = Z_OBJCE(EX(This));
18441845
} else {
@@ -1867,6 +1868,17 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
18671868
inner_ce = zend_lookup_class(full_class_name);
18681869
if (!inner_ce) {
18691870
zend_error(E_ERROR, "Class '%s' not found", ZSTR_VAL(full_class_name));
1871+
HANDLE_EXCEPTION();
1872+
}
1873+
1874+
if (inner_ce->required_scope) {
1875+
if (inner_ce->required_scope_absolute && inner_ce->required_scope != scope) {
1876+
zend_error(E_ERROR, "Class '%s' is private", ZSTR_VAL(full_class_name));
1877+
HANDLE_EXCEPTION();
1878+
} else if (scope == NULL || !instanceof_function(scope, inner_ce->required_scope)) {
1879+
zend_error(E_ERROR, "Class '%s' is protected", ZSTR_VAL(full_class_name));
1880+
HANDLE_EXCEPTION();
1881+
}
18701882
}
18711883

18721884
CACHE_PTR(opline->extended_value, inner_ce);

Zend/zend_vm_execute.h

Lines changed: 54 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
private inner class
3+
--FILE--
4+
<?php
5+
6+
class Outer {
7+
private class Inner {}
8+
9+
public function getInner(): self:>Inner {
10+
return new self:>Inner();
11+
}
12+
}
13+
14+
class Foo extends Outer {
15+
public function getInner(): parent:>Inner {
16+
var_dump(parent::getInner());
17+
return new parent:>Inner();
18+
}
19+
}
20+
21+
$outer = new Foo();
22+
var_dump($outer->getInner());
23+
?>
24+
--EXPECTF--
25+
object(Outer:>Inner)#2 (0) {
26+
}
27+
28+
Fatal error: Class 'Outer:>Inner' is private in %s on line %d
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
protected inner class
3+
--FILE--
4+
<?php
5+
6+
class Outer {
7+
protected class Inner {}
8+
9+
public function getInner(): self:>Inner {
10+
return new self:>Inner();
11+
}
12+
}
13+
14+
class Foo extends Outer {
15+
public function getInner(): parent:>Inner {
16+
var_dump(parent::getInner());
17+
return new parent:>Inner();
18+
}
19+
}
20+
21+
$outer = new Foo();
22+
var_dump($outer->getInner());
23+
var_dump(new Outer:>Inner());
24+
?>
25+
--EXPECTF--
26+
object(Outer:>Inner)#2 (0) {
27+
}
28+
object(Outer:>Inner)#2 (0) {
29+
}
30+
31+
Fatal error: Class 'Outer:>Inner' is protected in %s on line %d
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
private return types
3+
--FILE--
4+
<?php
5+
6+
class Outer {
7+
private class Inner {}
8+
9+
public static function getInner(): self:>Inner {
10+
return new self:>Inner();
11+
}
12+
}
13+
14+
$r = Outer::getInner();
15+
function test($r): Outer:>Inner {
16+
return $r;
17+
}
18+
var_dump($r);
19+
test($r);
20+
?>
21+
--EXPECTF--
22+
object(Outer:>Inner)#1 (0) {
23+
}
24+
25+
Fatal error: Private inner class Outer:>Inner cannot be used as a type declaration in the global scope in %s on line %d
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
protected return types
3+
--FILE--
4+
<?php
5+
6+
class Outer {
7+
protected class Inner {}
8+
9+
public static function getInner(): self:>Inner {
10+
return new self:>Inner();
11+
}
12+
}
13+
14+
$r = Outer::getInner();
15+
function test($r): Outer:>Inner {
16+
return $r;
17+
}
18+
var_dump($r);
19+
test($r);
20+
?>
21+
--EXPECTF--
22+
object(Outer:>Inner)#1 (0) {
23+
}
24+
25+
Fatal error: Protected inner class Outer:>Inner cannot be used as a type declaration in the global scope in %s on line %d

0 commit comments

Comments
 (0)