parent
2287695b44
commit
9cdc8b1b09
13 changed files with 363 additions and 0 deletions
@ -0,0 +1,11 @@ |
||||
<?php |
||||
|
||||
class TestClass |
||||
{ |
||||
private function __construct(){} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass; |
||||
} |
||||
@ -0,0 +1,11 @@ |
||||
<?php |
||||
|
||||
class TestClass |
||||
{ |
||||
protected function __construct(){} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass; |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
<?php |
||||
|
||||
class Base |
||||
{ |
||||
protected function __construct(){} |
||||
} |
||||
|
||||
class Other |
||||
{ |
||||
public static function make(): Base |
||||
{ |
||||
return new Base(); |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
Other::make(); |
||||
} |
||||
@ -0,0 +1,29 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
trait TraitA |
||||
{ |
||||
public function __construct() |
||||
{ |
||||
echo "A\n"; |
||||
} |
||||
} |
||||
|
||||
trait TraitB |
||||
{ |
||||
public function __construct() |
||||
{ |
||||
echo "B\n"; |
||||
} |
||||
} |
||||
|
||||
class TestClass |
||||
{ |
||||
use TraitA, TraitB; |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass(); |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
trait TestTrait |
||||
{ |
||||
private function __construct() |
||||
{ |
||||
echo "trait ctor\n"; |
||||
} |
||||
} |
||||
|
||||
class TestClass |
||||
{ |
||||
use TestTrait; |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass(); |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
trait TestTrait |
||||
{ |
||||
protected function __construct() |
||||
{ |
||||
echo "trait ctor\n"; |
||||
} |
||||
} |
||||
|
||||
class TestClass |
||||
{ |
||||
use TestTrait; |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass(); |
||||
} |
||||
@ -0,0 +1,57 @@ |
||||
<?php |
||||
|
||||
use TypePhp\Exception\TestError; |
||||
|
||||
class ConstructorVisibilityTest extends BaseTest |
||||
{ |
||||
/** |
||||
* 编译期错误在转换阶段直接以 TestError 抛出,而在桩文件生成阶段 |
||||
* (gen_stub.php) 会被包成 RuntimeException,这里两者都要捕获。 |
||||
*/ |
||||
protected function exec(string $expected, string $file): void |
||||
{ |
||||
try { |
||||
$this->compile($file); |
||||
} catch (TestError | \RuntimeException $exception) { |
||||
$this->assertStringContainsString($expected, $exception->getMessage()); |
||||
return; |
||||
} |
||||
$this->fail('Expected compile-time error was not thrown'); |
||||
} |
||||
|
||||
public function testPrivateConstructorCannotBeCalledFromOutside(): void |
||||
{ |
||||
// 私有构造器不能从类外部通过 `new` 调用 |
||||
$this->exec('Cannot call private TestClass::__construct()', 'constructor_visibility_private.php'); |
||||
} |
||||
|
||||
public function testProtectedConstructorCannotBeCalledFromGlobalScope(): void |
||||
{ |
||||
// 保护构造器不能从全局作用域调用 |
||||
$this->exec('Cannot call protected TestClass::__construct()', 'constructor_visibility_protected.php'); |
||||
} |
||||
|
||||
public function testProtectedConstructorCannotBeCalledFromNonSubclass(): void |
||||
{ |
||||
// 保护构造器不能从非子类的其它类内部调用 |
||||
$this->exec('Cannot call protected Base::__construct()', 'constructor_visibility_protected_foreign_class.php'); |
||||
} |
||||
|
||||
public function testTraitPrivateConstructorCannotBeCalledFromGlobalScope(): void |
||||
{ |
||||
// trait 提供的私有构造器扁平化后等价于类的私有构造器 |
||||
$this->exec('Cannot call private TestClass::__construct()', 'trait_constructor_private.php'); |
||||
} |
||||
|
||||
public function testTraitProtectedConstructorCannotBeCalledFromGlobalScope(): void |
||||
{ |
||||
// trait 提供的保护构造器扁平化后等价于类的保护构造器 |
||||
$this->exec('Cannot call protected TestClass::__construct()', 'trait_constructor_protected.php'); |
||||
} |
||||
|
||||
public function testConflictingTraitConstructorMustBeResolved(): void |
||||
{ |
||||
// 两个 trait 各自声明 __construct 时必须显式解决冲突 |
||||
$this->exec('Trait `TraitB` method `__construct` already exists', 'trait_constructor_conflict.php'); |
||||
} |
||||
} |
||||
@ -0,0 +1,26 @@ |
||||
--TEST-- |
||||
Constructor visibility - protected constructor accessible from subclass |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class Base |
||||
{ |
||||
protected function __construct(){} |
||||
} |
||||
|
||||
class Sub extends Base |
||||
{ |
||||
public static function make(): Base |
||||
{ |
||||
return new Base(); |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
$obj = Sub::make(); |
||||
var_dump($obj instanceof Base); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
bool(true) |
||||
@ -0,0 +1,27 @@ |
||||
--TEST-- |
||||
Trait __construct is used by the composing class |
||||
--FILE-- |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
trait TestTrait |
||||
{ |
||||
public function __construct() |
||||
{ |
||||
echo "trait ctor\n"; |
||||
} |
||||
} |
||||
|
||||
class TestClass |
||||
{ |
||||
use TestTrait; |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
trait ctor |
||||
@ -0,0 +1,32 @@ |
||||
--TEST-- |
||||
Class __construct overrides the one provided by a trait |
||||
--FILE-- |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
trait TestTrait |
||||
{ |
||||
public function __construct() |
||||
{ |
||||
echo "trait ctor\n"; |
||||
} |
||||
} |
||||
|
||||
class TestClass |
||||
{ |
||||
use TestTrait; |
||||
|
||||
public function __construct() |
||||
{ |
||||
echo "class ctor\n"; |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
class ctor |
||||
@ -0,0 +1,37 @@ |
||||
--TEST-- |
||||
Trait protected __construct is accessible from a subclass |
||||
--FILE-- |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
trait TestTrait |
||||
{ |
||||
protected function __construct() |
||||
{ |
||||
echo "base ctor\n"; |
||||
} |
||||
} |
||||
|
||||
class BaseClass |
||||
{ |
||||
use TestTrait; |
||||
} |
||||
|
||||
class SubClass extends BaseClass |
||||
{ |
||||
public function __construct() |
||||
{ |
||||
new BaseClass(); |
||||
echo "sub ctor\n"; |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new SubClass(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
base ctor |
||||
sub ctor |
||||
@ -0,0 +1,30 @@ |
||||
--TEST-- |
||||
Trait __construct with arguments and $this property access |
||||
--FILE-- |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
trait TestTrait |
||||
{ |
||||
private int $value = 0; |
||||
|
||||
public function __construct(int $value) |
||||
{ |
||||
$this->value = $value; |
||||
echo "value=" . $this->value . "\n"; |
||||
} |
||||
} |
||||
|
||||
class TestClass |
||||
{ |
||||
use TestTrait; |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
new TestClass(42); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
value=42 |
||||
Loading…
Reference in new issue