Skip to content

Commit ce3299e

Browse files
committed
handle constructor visibility
1 parent 52495eb commit ce3299e

File tree

5 files changed

+108
-0
lines changed

5 files changed

+108
-0
lines changed

Zend/zend_object_handlers.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,9 +2080,15 @@ ZEND_API zend_function *zend_std_get_constructor(zend_object *zobj) /* {{{ */
20802080
if (constructor) {
20812081
if (UNEXPECTED(!(constructor->op_array.fn_flags & ZEND_ACC_PUBLIC))) {
20822082
zend_class_entry *scope = get_fake_or_executed_scope();
2083+
check_lexical_scope:
20832084
if (UNEXPECTED(constructor->common.scope != scope)) {
20842085
if (UNEXPECTED(constructor->op_array.fn_flags & ZEND_ACC_PRIVATE)
20852086
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(constructor), scope))) {
2087+
if (scope && scope->lexical_scope) {
2088+
scope = scope->lexical_scope;
2089+
goto check_lexical_scope;
2090+
}
2091+
20862092
zend_bad_constructor_call(constructor, scope);
20872093
zend_object_store_ctor_failed(zobj);
20882094
constructor = NULL;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
usage in an enum
3+
--FILE--
4+
<?php
5+
6+
enum Outer {
7+
class Inner {}
8+
}
9+
10+
var_dump(new Outer:>Inner());
11+
var_dump(class_exists(Outer:>Inner::class));
12+
?>
13+
--EXPECT--
14+
object(Outer:>Inner)#1 (0) {
15+
}
16+
bool(true)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
usage in an interface
3+
--FILE--
4+
<?php
5+
6+
interface Outer {
7+
class Inner {}
8+
}
9+
10+
var_dump(new Outer:>Inner());
11+
12+
class Foo implements Outer {}
13+
14+
var_dump(class_exists(Outer:>Inner::class));
15+
var_dump(class_exists(Foo:>Inner::class));
16+
?>
17+
--EXPECT--
18+
object(Outer:>Inner)#1 (0) {
19+
}
20+
bool(true)
21+
bool(false)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
usage inside a trait
3+
--FILE--
4+
<?php
5+
6+
trait Outer {
7+
class Inner {}
8+
}
9+
10+
var_dump(new Outer:>Inner());
11+
12+
class Foo {
13+
use Outer;
14+
}
15+
16+
var_dump(class_exists(Outer:>Inner::class));
17+
var_dump(class_exists(Foo:>Inner::class));
18+
19+
?>
20+
--EXPECT--
21+
object(Outer:>Inner)#1 (0) {
22+
}
23+
bool(true)
24+
bool(false)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
constructors
3+
--FILE--
4+
<?php
5+
6+
class User {
7+
public private(set) string $name;
8+
public private(set) string $email;
9+
10+
private function __construct(self:>Builder $builder) {
11+
$this->name = $builder->name;
12+
$this->email = $builder->email;
13+
}
14+
15+
public readonly final class Builder {
16+
public function __construct(public private(set) string|null $name = null, public private(set) string|null $email = null) {}
17+
18+
public function withEmail(string $email): self {
19+
return new self($this->name, $email);
20+
}
21+
22+
public function withName(string $name): self {
23+
return new self($name, $this->email);
24+
}
25+
26+
public function build(): User {
27+
return new User($this);
28+
}
29+
}
30+
}
31+
32+
$user = new User:>Builder()->withName('Rob')->withEmail('[email protected]')->build();
33+
var_dump($user);
34+
?>
35+
--EXPECT--
36+
object(User)#2 (2) {
37+
["name"]=>
38+
string(3) "Rob"
39+
["email"]=>
40+
string(15) "[email protected]"
41+
}

0 commit comments

Comments
 (0)