mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
GH-16067: prevent invalid abstract
during compilation of methods (GH-16069)
For classes that are not declared `abstract`, produce a compiler error for any `abstract` methods. For anonymous classes, since they cannot be made abstract, the error message is slightly different. Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
This commit is contained in:
parent
e64e531e3d
commit
0b94cf65e4
10 changed files with 64 additions and 10 deletions
19
Zend/tests/abstract_implicit.phpt
Normal file
19
Zend/tests/abstract_implicit.phpt
Normal file
|
@ -0,0 +1,19 @@
|
|||
--TEST--
|
||||
Abstract methods not allowed in classes that are not abstract (GH-16067)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Still allowed via trait
|
||||
trait TraitWithAbstract {
|
||||
abstract public function foo();
|
||||
}
|
||||
class TraitWorks {
|
||||
use TraitWithAbstract;
|
||||
}
|
||||
|
||||
class NotAbstract {
|
||||
abstract public function bar();
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class NotAbstract declares abstract method bar() and must therefore be declared abstract in %s on line %d
|
11
Zend/tests/anon/gh16067.phpt
Normal file
11
Zend/tests/anon/gh16067.phpt
Normal file
|
@ -0,0 +1,11 @@
|
|||
--TEST--
|
||||
Compiler prevents explicit `abstract` methods on anonymous classes
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$c = new class {
|
||||
abstract public function f();
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Anonymous class method f() must not be abstract in %s on line 4
|
12
Zend/tests/enum/no-abstract.phpt
Normal file
12
Zend/tests/enum/no-abstract.phpt
Normal file
|
@ -0,0 +1,12 @@
|
|||
--TEST--
|
||||
Compiler prevents `abstract` methods on enums classes (GH-16067)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
enum Example {
|
||||
abstract public function foo();
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Enum method Example::foo() must not be abstract in %s on line 4
|
|
@ -10,4 +10,4 @@ class test {
|
|||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class test contains 1 abstract method and must therefore be declared abstract or implement the remaining method (test::foo) in %s on line %d
|
||||
Fatal error: Class test declares abstract method foo() and must therefore be declared abstract in %s on line %d
|
||||
|
|
|
@ -8067,6 +8067,22 @@ static zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string
|
|||
zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
|
||||
}
|
||||
|
||||
if ((fn_flags & ZEND_ACC_ABSTRACT)
|
||||
&& !(ce->ce_flags & (ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_TRAIT))) {
|
||||
// Don't say that the class should be declared abstract if it is
|
||||
// anonymous or an enum and can't be abstract
|
||||
if (ce->ce_flags & ZEND_ACC_ANON_CLASS) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Anonymous class method %s() must not be abstract",
|
||||
ZSTR_VAL(name));
|
||||
} else if (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_INTERFACE)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "%s method %s::%s() must not be abstract",
|
||||
zend_get_object_type_case(ce, true), ZSTR_VAL(ce->name), ZSTR_VAL(name));
|
||||
} else {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Class %s declares abstract method %s() and must therefore be declared abstract",
|
||||
ZSTR_VAL(ce->name), ZSTR_VAL(name));
|
||||
}
|
||||
}
|
||||
|
||||
if (in_interface) {
|
||||
if (!(fn_flags & ZEND_ACC_PUBLIC)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface method "
|
||||
|
@ -8076,10 +8092,6 @@ static zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string
|
|||
zend_error_noreturn(E_COMPILE_ERROR, "Interface method "
|
||||
"%s::%s() must not be final", ZSTR_VAL(ce->name), ZSTR_VAL(name));
|
||||
}
|
||||
if (fn_flags & ZEND_ACC_ABSTRACT) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Interface method "
|
||||
"%s::%s() must not be abstract", ZSTR_VAL(ce->name), ZSTR_VAL(name));
|
||||
}
|
||||
op_array->fn_flags |= ZEND_ACC_ABSTRACT;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,4 +13,4 @@ class derived extends base {
|
|||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
Fatal error: Class derived contains 1 abstract method and must therefore be declared abstract or implement the remaining method (derived::show) in %sabstract_derived.php on line %d
|
||||
Fatal error: Class derived declares abstract method show() and must therefore be declared abstract in %sabstract_derived.php on line %d
|
||||
|
|
|
@ -10,4 +10,4 @@ class fail {
|
|||
echo "Done\n"; // shouldn't be displayed
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining method (fail::show) in %s on line %d
|
||||
Fatal error: Class fail declares abstract method show() and must therefore be declared abstract in %s on line %d
|
||||
|
|
|
@ -16,4 +16,4 @@ class fail extends pass {
|
|||
echo "Done\n"; // Shouldn't be displayed
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining method (fail::show) in %sabstract_redeclare.php on line %d
|
||||
Fatal error: Class fail declares abstract method show() and must therefore be declared abstract in %sabstract_redeclare.php on line %d
|
||||
|
|
|
@ -31,4 +31,4 @@ echo "Done\n"; // shouldn't be displayed
|
|||
--EXPECTF--
|
||||
Call to function show()
|
||||
|
||||
Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining method (fail::func) in %sabstract_static.php(%d) : eval()'d code on line %d
|
||||
Fatal error: Class fail declares abstract method func() and must therefore be declared abstract in %sabstract_static.php(%d) : eval()'d code on line %d
|
||||
|
|
|
@ -4,7 +4,7 @@ ZE2 An interface method cannot be private
|
|||
<?php
|
||||
|
||||
interface if_a {
|
||||
abstract private function err();
|
||||
private function err();
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue