fix(translator): 修复trait parent::调用的函数声明参数不一致 #38
Merged
韩天峰
merged 3 commits from translator-fix-trait-parent-funcdecl-params into master 1 month ago
5 changed files with 166 additions and 23 deletions
@ -0,0 +1,42 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
class Base |
||||
{ |
||||
public function __construct(array $option = []) |
||||
{ |
||||
echo 'Base:'; |
||||
foreach ($option as $k => $v) { |
||||
echo ' ' . $k . '=' . $v; |
||||
} |
||||
echo "\n"; |
||||
} |
||||
} |
||||
|
||||
trait TPdoDriver |
||||
{ |
||||
public function __construct(array $option = []) |
||||
{ |
||||
$option['fromTrait'] = 1; |
||||
parent::__construct($option); |
||||
} |
||||
} |
||||
|
||||
class Driver extends Base |
||||
{ |
||||
use TPdoDriver { |
||||
__construct as private tPdoDriverConstruct; |
||||
} |
||||
|
||||
public function __construct(array $option = []) |
||||
{ |
||||
$option['username'] = 'postgres'; |
||||
$this->tPdoDriverConstruct($option); |
||||
} |
||||
} |
||||
|
||||
class DirectDriver extends Base |
||||
{ |
||||
use TPdoDriver; |
||||
} |
||||
@ -0,0 +1,45 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* Regression test for the trait `parent::` / `trait_parent_ce` declaration bug. |
||||
* |
||||
* A trait method whose body contains `parent::` calls is compiled with an implicit |
||||
* `zend_class_entry *trait_parent_ce` parameter (so `parent::` can be bound to the |
||||
* class that composes the trait). The shared `func_decl.h` declaration must emit the |
||||
* same parameter; otherwise the generated C++ fails to compile with C2660 |
||||
* ("function does not accept 3 arguments") at the call site that forwards to the trait |
||||
* function. This is a code-generation-level check that fails before the fix and passes |
||||
* after it. |
||||
*/ |
||||
class TraitFuncDeclTest extends \BaseTest |
||||
{ |
||||
public function testAliasedTraitConstructorParentCallDeclaresTraitParentCe(): void |
||||
{ |
||||
// BaseTest::compile() populates the global $translator and translates the file. |
||||
$this->compile('trait-aliased-constructor-parent-call.php'); |
||||
|
||||
global $translator; |
||||
$compiler = $translator; |
||||
|
||||
$headerPath = $compiler->getIncludeDir() . '/php_trait_parent_ce_func_decl.h'; |
||||
if (file_exists($headerPath)) { |
||||
@unlink($headerPath); |
||||
} |
||||
// Emit the shared function-declaration header (genFunctionDeclarations), which |
||||
// is what the fix targets. |
||||
$compiler->genFunctionDeclarations($headerPath); |
||||
|
||||
$decl = file_get_contents($headerPath); |
||||
$this->assertMatchesRegularExpression( |
||||
'/extern void php_tpdodriver____construct\([^;\n]*trait_parent_ce[^;\n]*\);/', |
||||
$decl, |
||||
'The trait function declaration must include its implicit parent scope' |
||||
); |
||||
$this->assertDoesNotMatchRegularExpression( |
||||
'/extern void php_(?:driver__tpdodriverconstruct|directdriver____construct)' |
||||
. '\([^;\n]*trait_parent_ce[^;\n]*\);/', |
||||
$decl, |
||||
'Composing-class wrapper declarations must not expose the implicit parent scope' |
||||
); |
||||
} |
||||
} |
||||
@ -0,0 +1,61 @@ |
||||
--TEST-- |
||||
Trait parent constructor calls keep declarations aligned for aliased and direct wrappers |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class Base |
||||
{ |
||||
public function __construct(array $options = []) |
||||
{ |
||||
var_dump($options); |
||||
} |
||||
} |
||||
|
||||
trait DriverConstructor |
||||
{ |
||||
public function __construct(array $options = []) |
||||
{ |
||||
$options['trait'] = 1; |
||||
parent::__construct($options); |
||||
} |
||||
} |
||||
|
||||
class AliasedDriver extends Base |
||||
{ |
||||
use DriverConstructor { |
||||
__construct as private traitConstruct; |
||||
} |
||||
|
||||
public function __construct(array $options = []) |
||||
{ |
||||
$options['alias'] = 1; |
||||
$this->traitConstruct($options); |
||||
} |
||||
} |
||||
|
||||
class DirectDriver extends Base |
||||
{ |
||||
use DriverConstructor; |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new AliasedDriver(['input' => 1]); |
||||
new DirectDriver(['direct' => 1]); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
array(3) { |
||||
["input"]=> |
||||
int(1) |
||||
["alias"]=> |
||||
int(1) |
||||
["trait"]=> |
||||
int(1) |
||||
} |
||||
array(2) { |
||||
["direct"]=> |
||||
int(1) |
||||
["trait"]=> |
||||
int(1) |
||||
} |
||||
Loading…
Reference in new issue