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