Skip to content

Commit 975c15c

Browse files
cscottKrinkle
authored andcommitted
Add TestingAccessWrapper::construct() to use non-public constructors
Change-Id: Idaaae6ce699c15c57df7bc23cdbcf4b6e6e77ea6
1 parent e3c0ef8 commit 975c15c

File tree

4 files changed

+45
-2
lines changed

4 files changed

+45
-2
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ class NonPublic {
2121
protected static function staticFunc() {}
2222
}
2323

24+
class NonPublicCtor {
25+
protected function __construct() {}
26+
}
27+
2428
$object = new NonPublic();
29+
// or:
30+
// $object = TestingAccessWrapper::construct( NonPublicCtor::class );
31+
2532
$wrapper = TestingAccessWrapper::newFromObject( $object );
2633
$classWrapper = TestingAccessWrapper::newFromClass( NonPublic::class );
2734

src/TestingAccessWrapper.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ public static function constant( $className, $constantName ) {
8282
return $classReflection->getConstant( $constantName );
8383
}
8484

85+
/**
86+
* Allow constructing a class with a non-public constructor.
87+
* @param class-string<T> $className
88+
* @param mixed ...$args
89+
* @return T
90+
* @phan-template T
91+
*/
92+
public static function construct( string $className, ...$args ) {
93+
$classReflection = new ReflectionClass( $className );
94+
$constructor = $classReflection->getConstructor();
95+
$constructor->setAccessible( true );
96+
$object = $classReflection->newInstanceWithoutConstructor();
97+
$constructor->invokeArgs( $object, $args );
98+
return $object;
99+
}
100+
85101
/**
86102
* @param string $method
87103
* @param array $args

tests/TestingAccessWrapperTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,26 @@ public function testConstantException() {
6161
TestingAccessWrapper::constant( WellProtectedClass::class, 'NONEXISTENT_CONTENT' );
6262
}
6363

64+
public function testConstructException() {
65+
$this->expectException( \Error::class );
66+
// @phan-suppress-next-line PhanAccessMethodProtected
67+
return new WellProtectedParentClass();
68+
}
69+
70+
public function testConstruct() {
71+
$parent = TestingAccessWrapper::construct( WellProtectedParentClass::class );
72+
$this->assertInstanceOf( WellProtectedParentClass::class, $parent );
73+
$wrapped = TestingAccessWrapper::newFromObject( $parent );
74+
$this->assertSame( 9000, $wrapped->privateParentProperty );
75+
}
76+
77+
public function testConstructArg() {
78+
$parent = TestingAccessWrapper::construct( WellProtectedParentClass::class, 1234 );
79+
$this->assertInstanceOf( WellProtectedParentClass::class, $parent );
80+
$wrapped = TestingAccessWrapper::newFromObject( $parent );
81+
$this->assertSame( 1234, $wrapped->privateParentProperty );
82+
}
83+
6484
public function testGetException_nonStatic() {
6585
$this->expectException( \DomainException::class );
6686
$this->wrappedStatic->property;

tests/WellProtectedParentClass.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ class WellProtectedParentClass {
1111

1212
private const PARENT_CONSTANT = 'parent constant';
1313

14-
public function __construct() {
15-
$this->privateParentProperty = 9000;
14+
protected function __construct( $parentProperty = 9000 ) {
15+
$this->privateParentProperty = $parentProperty;
1616
}
1717

1818
private function incrementPrivateParentPropertyValue() {

0 commit comments

Comments
 (0)