处理继承或实现内置类和接口

pull/1/head
韩天峰 7 months ago
parent 6ff687e1da
commit 689b59bbda
  1. 2
      src/Php/CompilerBase.php
  2. 65
      src/Php/Translator.php
  3. 8
      src/template/extension.cc.php
  4. 23
      tests/core/classes/interfaces_001.phpt
  5. 29
      tests/core/classes/interfaces_002.phpt
  6. 30
      tests/core/classes/interfaces_003.phpt

@ -214,7 +214,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->indentLevel = 0;
$this->strictTypes = false;
$this->classesDefineInFile = [];
$this->interfaceDefineInFile = [];
$this->interfacesDefineInFile = [];
}
protected function resetNamespace(): void

@ -166,6 +166,14 @@ class Translator extends Preprocessor
return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName();
}
protected function getInternalCeInfo(string $ce): array
{
return [
'func' => 'php::getClassEntry',
'args' => '"' . substr($ce, strlen(self::PREFIX . 'class_entry_')) . '"',
];
}
protected function getParentClassCe(ClassLikeDef $classDef): string
{
if (!$classDef->extends) {
@ -176,7 +184,11 @@ class Translator extends Preprocessor
private function getImplementCe(ClassDef $classDef): array
{
return array_map(fn($v) => self::PREFIX . 'class_entry_' . $v, $classDef->implements);
$list = [];
foreach ($classDef->implements as $interface) {
$list[] = self::PREFIX . 'class_entry_' . $interface;
}
return $list;
}
protected function doConvert(string $phpCode): string
@ -283,12 +295,19 @@ class Translator extends Preprocessor
$sorter = new StringSort();
foreach ($this->interfacesDefineInFile as $interfaceDef) {
$parent = $interfaceDef->extends;
$ce = $this->getClassCe($interfaceDef);
$parentCe = $this->getParentClassCe($interfaceDef);
$deps = [];
if ($parentCe !== '') {
$deps[] = $parentCe;
if ($parent) {
// 不存在的接口,说明可能是内置接口
$tmpCe = $this->getParentClassCe($interfaceDef);
if (!isset($this->interfaces[$parent])) {
$sorter->add($tmpCe);
}
$deps[] = $tmpCe;
}
$this->classCeInfo[$ce] = [
'deps' => $deps,
'func' => $this->getRegisterClassFunction($interfaceDef->getNamespacedName()),
@ -300,14 +319,35 @@ class Translator extends Preprocessor
foreach ($this->classesDefineInFile as $classDef) {
$ce = $this->getClassCe($classDef);
$depsCeList = $this->getRegisterClassFunctionCeList($classDef);
$deps = [];
$parent = $classDef->extends;
if ($parent) {
// 不存在的父类,说明可能是内置类
$tmpCe = $this->getParentClassCe($classDef);
if (!isset($this->classes[$parent])) {
$sorter->add($tmpCe);
}
$deps[] = $tmpCe;
}
$implements = $classDef->implements;
if ($implements) {
foreach ($implements as $interface) {
$tmpCe = self::PREFIX . 'class_entry_' . $interface;
if (!isset($this->interfaces[$interface])) {
$sorter->add($tmpCe);
}
$deps[] = $tmpCe;
}
}
$this->classCeInfo[$ce] = [
'deps' => $depsCeList,
'deps' => $deps,
'func' => $this->getRegisterClassFunction($classDef->getNamespacedName()),
'args' => $this->getRegisterClassFunctionArgs($classDef),
'argDef' => $this->getRegisterClassFunctionArgDef($classDef),
];
$sorter->add($ce, $depsCeList);
$sorter->add($ce, $deps);
}
$this->classCeList = $sorter->sort();
@ -473,8 +513,9 @@ class Translator extends Preprocessor
}
$this->classDef->implements = $this->parseIdentifierList($class->implements);
$this->classes[$this->class] = $this->classDef;
$this->classesDefineInFile[$this->class] = $this->classDef;
$className = $this->classDef->getNamespacedName();
$this->classes[$className] = $this->classDef;
$this->classesDefineInFile[$className] = $this->classDef;
$methodCodes = [];
@ -557,6 +598,7 @@ class Translator extends Preprocessor
$cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL;
$cppCode .= '}' . PHP_EOL . PHP_EOL;
// 接口没有方法实体
if ($classDef instanceof ClassDef) {
$methods = $classDef->methods;
foreach ($methods as $methodDef) {
@ -762,7 +804,8 @@ class Translator extends Preprocessor
$name = $this->parseIdentifier($v->name);
$this->interface = $name;
$this->interfaceDef = new InterfaceDef($name, $this->namespace);
$this->interfaces[$name] = $this->interfaceDef;
$this->interfacesDefineInFile[$this->interface] = $this->interfaceDef;
$interfaceName = $this->interfaceDef->getNamespacedName();
$this->interfaces[$interfaceName] = $this->interfaceDef;
$this->interfacesDefineInFile[$interfaceName] = $this->interfaceDef;
}
}

@ -17,10 +17,14 @@ foreach ($this->globalVars as $name => $type):
// class register functions
<?php
foreach ($this->classCeList as $ce):
$info = $this->classCeInfo[$ce];
?>
zend_class_entry * <?= $ce ?>;
<?php
if (isset($this->classCeInfo[$ce])):
$info = $this->classCeInfo[$ce];
?>
extern zend_class_entry *<?= $info['func'] ?>(<?= $info['argDef'] ?>);
<?php endif; ?>
<?php endforeach; ?>
// literal strings
@ -55,7 +59,7 @@ static PHP_MINIT_FUNCTION(app) {
// class/interface class entries
<?php
foreach ($this->classCeList as $ce):
$info = $this->classCeInfo[$ce];
$info = $this->classCeInfo[$ce] ?? $this->getInternalCeInfo($ce);
?>
<?=$ce?> = <?= $info['func'] ?>(<?= $info['args'] ?>);
<?php endforeach; ?>

@ -0,0 +1,23 @@
--TEST--
ZE2 interfaces
--FILE--
<?php
interface ThrowableInterface {
public function getMessage();
}
class Exception_foo implements ThrowableInterface {
public $foo = "foo";
public function getMessage() {
return $this->foo;
}
}
function main() {
$foo = new Exception_foo;
echo $foo->getMessage() . "\n";
}
?>
--EXPECT--
foo

@ -0,0 +1,29 @@
--TEST--
ZE2 interface with an unimplemented method
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
interface ThrowableInterface {
public function getMessage();
public function getErrno();
}
class Exception_foo implements ThrowableInterface {
public $foo = "foo";
public function getMessage() {
return $this->foo;
}
}
function main() {
// this should die -- Exception class must be abstract...
$foo = new Exception_foo;
echo "Message: " . $foo->getMessage() . "\n";
}
?>
--EXPECTF--
Fatal error: Class Exception_foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (ThrowableInterface::getErrno) in %s on line %d

@ -0,0 +1,30 @@
--TEST--
ZE2 interface and __construct
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
class MyObject {}
interface MyInterface
{
public function __construct(MyObject $o);
}
class MyTestClass implements MyInterface
{
public function __construct(MyObject $o)
{
}
}
function main() {
$obj = new MyTestClass;
}
?>
--EXPECTF--
Fatal error: Uncaught ArgumentCountError: Too few arguments to function MyTestClass::__construct(), 0 passed in %sinterfaces_003.php on line 17 and exactly 1 expected in %sinterfaces_003.php:12
Stack trace:
#0 %s(%d): MyTestClass->__construct()
#1 {main}
thrown in %sinterfaces_003.php on line %d
Loading…
Cancel
Save