Skip to content

Rfc: inner classes #18069

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5a8a98e
add new token
withinboredom Mar 8, 2025
716a401
create the new grammar
withinboredom Mar 8, 2025
1388dca
add new ast pieces
withinboredom Mar 8, 2025
c3cc41e
handle modifiers
withinboredom Mar 8, 2025
b9b93e6
handle compiling class declarations
withinboredom Mar 8, 2025
0ac2ef0
add initial implementation;
withinboredom Mar 8, 2025
17bd2cc
get return types working
withinboredom Mar 9, 2025
eef0b95
make ::class work
withinboredom Mar 9, 2025
f6006ad
fix failing test
withinboredom Mar 9, 2025
1b85087
add another class
withinboredom Mar 9, 2025
3d46bc2
add more tests to validate scope resolution keywords
withinboredom Mar 9, 2025
99abdcd
update reflection
withinboredom Mar 9, 2025
72e14ca
enable visibility
withinboredom Mar 9, 2025
0254635
add tests for autoloading
withinboredom Mar 9, 2025
458fca8
properly persist classes in opcache
withinboredom Mar 9, 2025
7a06f63
handle return type visibility enforcement
withinboredom Mar 9, 2025
eea3ad3
fix static member access
withinboredom Mar 11, 2025
d2b3256
move tests
withinboredom Mar 13, 2025
861da61
add more tests and fix access modifiers
withinboredom Mar 13, 2025
bf196a8
add support for lexical scope
withinboredom Mar 13, 2025
05aecfd
handle type visibility
withinboredom Mar 14, 2025
51f2fc5
fix opcache
withinboredom Mar 14, 2025
4fda62b
fix test
withinboredom Mar 14, 2025
2053a50
refine some error messages
withinboredom Mar 14, 2025
5f9db7b
add type check to return type
withinboredom Mar 14, 2025
7376eff
fix tests
withinboredom Mar 14, 2025
2092910
temporarily fix this test -- might want to undo this
withinboredom Mar 14, 2025
5f5d53f
clean up a bit and check readonly
withinboredom Mar 14, 2025
0ff7a33
handle visibility of methods
withinboredom Mar 14, 2025
b62121a
just do not cache -- more trouble than it is worth right now
withinboredom Mar 14, 2025
1f48e2b
properly handle lexical scope
withinboredom Mar 14, 2025
866bab3
handle long names
withinboredom Mar 14, 2025
b7737a2
handle more visibility
withinboredom Mar 14, 2025
ad8a4b4
handle constructor visibility
withinboredom Mar 15, 2025
405dab1
prevent static access
withinboredom Mar 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refine some error messages
  • Loading branch information
withinboredom committed Mar 14, 2025
commit 2053a50bc1d85c965130acc7663a25a8a8ccdff9
14 changes: 7 additions & 7 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -1812,7 +1812,7 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
zval *outer_class_zv = RT_CONSTANT(opline, opline->op1);
outer_ce = zend_lookup_class(Z_STR_P(outer_class_zv));
if (!outer_ce) {
zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL_P(outer_class_zv));
zend_error(E_ERROR, "Outer class '%s' not found for inner class %s:>%s", Z_STRVAL_P(outer_class_zv), Z_STRVAL_P(outer_class_zv), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
HANDLE_EXCEPTION();
}
} else if (OP1_TYPE == IS_UNUSED) {
Expand Down Expand Up @@ -1864,7 +1864,7 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S

inner_ce = zend_lookup_class(full_class_name);
if (!inner_ce) {
zend_error(E_ERROR, "Class '%s' not found", ZSTR_VAL(full_class_name));
zend_error(E_ERROR, "Inner class '%s' not found in outer class %s", ZSTR_VAL(full_class_name), ZSTR_VAL(outer_ce->name));
HANDLE_EXCEPTION();
}

Expand All @@ -1874,15 +1874,15 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_S
if (scope != NULL && (inner_ce->required_scope == scope || scope->lexical_scope == inner_ce->required_scope)) {
// we are in the correct scope
} else {
zend_error(E_ERROR, "Class '%s' is private", ZSTR_VAL(full_class_name));
zend_error(E_ERROR, "Cannot access private inner class '%s'", ZSTR_VAL(full_class_name));
HANDLE_EXCEPTION();
}
} else {
// for protected classes, we check if the scope is an instance of the required scope
if (scope != NULL && (instanceof_function(scope, inner_ce->required_scope) || instanceof_function(scope->lexical_scope, inner_ce->required_scope))) {
// we are in the correct scope
} else {
zend_error(E_ERROR, "Class '%s' is protected", ZSTR_VAL(full_class_name));
zend_error(E_ERROR, "Cannot access protected inner class '%s'", ZSTR_VAL(full_class_name));
HANDLE_EXCEPTION();
}
}
Expand Down Expand Up @@ -4529,15 +4529,15 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
if (Z_OBJCE_P(retval_ptr)->required_scope) {
if (EX(func)->common.fn_flags & ZEND_ACC_PUBLIC) {
if (Z_OBJCE_P(retval_ptr)->required_scope_absolute) {
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));
zend_type_error("Public method %s cannot return private class %s", ZSTR_VAL(EX(func)->common.function_name), ZSTR_VAL(Z_OBJCE_P(retval_ptr)->name));
HANDLE_EXCEPTION();
} else {
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));
zend_type_error("Public method %s cannot return protected class %s", ZSTR_VAL(EX(func)->common.function_name), ZSTR_VAL(Z_OBJCE_P(retval_ptr)->name));
HANDLE_EXCEPTION();
}
} else if (EX(func)->common.fn_flags & ZEND_ACC_PROTECTED) {
if (Z_OBJCE_P(retval_ptr)->required_scope_absolute && Z_OBJCE_P(retval_ptr)->required_scope != EX(func)->common.scope) {
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));
zend_type_error("Protected method %s cannot return private class %s", ZSTR_VAL(EX(func)->common.function_name), ZSTR_VAL(Z_OBJCE_P(retval_ptr)->name));
HANDLE_EXCEPTION();
}
}
Expand Down
54 changes: 27 additions & 27 deletions Zend/zend_vm_execute.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tests/classes/inner_classes/autoload_002.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ var_dump($line);
--EXPECTF--
autoload(inner_classes)

Fatal error: Class 'inner_classes:>Line' is private in %s on line %d
Fatal error: Cannot access private inner class 'inner_classes:>Line' in %s
9 changes: 9 additions & 0 deletions tests/classes/inner_classes/errors_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--TEST--
no outer class
--FILE--
<?php

new Outer:>Inner();
?>
--EXPECTF--
Fatal error: Outer class 'Outer' not found for inner class Outer:>Inner in %s on line %d
12 changes: 12 additions & 0 deletions tests/classes/inner_classes/errors_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
inner class not found
--FILE--
<?php

class Outer {
}

new Outer:>Inner();
?>
--EXPECTF--
Fatal error: Inner class 'Outer:>Inner' not found in outer class Outer in %s on line %d
2 changes: 1 addition & 1 deletion tests/classes/inner_classes/return_types_002.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ var_dump($outer->getInner());
object(Outer:>Inner)#2 (0) {
}

Fatal error: Class 'Outer:>Inner' is private in %s on line %d
Fatal error: Cannot access private inner class 'Outer:>Inner' in %s on line %d
2 changes: 1 addition & 1 deletion tests/classes/inner_classes/return_types_003.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var_dump(new Outer:>Inner());
object(Outer:>Inner)#2 (0) {
}

Fatal error: Uncaught TypeError: Method getInner is public but returns a protected class: Outer:>Inner in %s:%d
Fatal error: Uncaught TypeError: Public method getInner cannot return protected class Outer:>Inner in %s:%d
Stack trace:
#0 %s(%d): Foo->getInner()
#1 {main}
Expand Down
2 changes: 1 addition & 1 deletion tests/classes/inner_classes/return_types_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var_dump($r);
test($r);
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Method getInner is public but returns a private class: Outer:>Inner in %s:%d
Fatal error: Uncaught TypeError: Public method getInner cannot return private class Outer:>Inner in %s:%d
Stack trace:
#0 %s(%d): Outer::getInner()
#1 {main}
Expand Down
2 changes: 1 addition & 1 deletion tests/classes/inner_classes/return_types_005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var_dump($r);
test($r);
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Method getInner is public but returns a protected class: Outer:>Inner in %s:%d
Fatal error: Uncaught TypeError: Public method getInner cannot return protected class Outer:>Inner in %s:%d
Stack trace:
#0 %s(%d): Outer::getInner()
#1 {main}
Expand Down