diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index d966edf5..c607faf6 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -2921,6 +2921,12 @@ class CompilerBase extends \PhpAot\Core\Translator $cePtr = 'php_get_called_ce(this_)'; } else { $className = $this->getNamespacedClassName($className); + if ($this->hasNativeClass($className)) { + $classDef = $this->getClassDef($className); + if ($classDef->flags & Modifiers::ABSTRACT) { + $this->fatalError($expr, "abstract class `$className` cannot be instantiated"); + } + } $cePtr = $this->getClassEntryPtr($className); } } else { diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index 6beffb06..f3d8ada9 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -225,7 +225,7 @@ class Preprocessor extends CompilerBase case 'Stmt_EnumCase': break; case 'Stmt_ClassMethod': - $this->prepareMethod($v); + $this->prepareMethod($v, $class); break; case 'Stmt_Expression': $this->foundStrayCode($v); @@ -240,11 +240,15 @@ class Preprocessor extends CompilerBase return $code; } - protected function prepareMethod(Node\Stmt\ClassMethod $v): void + protected function prepareMethod(Node\Stmt\ClassMethod $v, Node\Stmt\Class_|Node\Stmt\Trait_|Node\Stmt\Enum_ $class): void { $abstract = $v->flags & Modifiers::ABSTRACT; if (!$abstract) { $this->prepareFunction($v) . PHP_EOL; + } else { + if (!($class->flags & Modifiers::ABSTRACT)) { + $this->fatalError($v, "Class {$this->class} cannot override non-abstract method {$v->name}"); + } } $fullClassName = $this->getFullClassName(); diff --git a/tests/core/classes/abstract.phpt b/tests/core/classes/abstract.phpt index 14af18f9..fec3f4b3 100644 --- a/tests/core/classes/abstract.phpt +++ b/tests/core/classes/abstract.phpt @@ -27,9 +27,8 @@ function main() { --EXPECTF-- Call to function show() -Fatal error: Uncaught Error: Cannot call abstract method fail::show() in %s:%d +Fatal error: Uncaught Error: Cannot call abstract method fail::show() in %s Stack trace: -#0 [internal function]: pass->error() -#1 Unknown(0) : %s -#2 {main} - thrown in %s on line %d +#0 Unknown(0) : %s +#1 {main} + thrown in Unknown(0) : %s