Skip to content
Closed
46 changes: 46 additions & 0 deletions phpunit/code/trait_adaptations_valid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
trait Inner
{
public function f(): void {}
}

trait Outer
{
use Inner;
}

// Aliases resolve methods arriving from NESTED traits, both unqualified and
// qualified with the directly-used trait.
class UsesNested
{
use Outer {
f as g;
}
}

class UsesNestedQualified
{
use Outer {
Outer::f as h;
}
}

trait Winner
{
public function m(): void {}
}

trait Loser
{
public function other(): void {}
}

// The overridden trait need not declare the method a precedence rule names.
class PrecedenceLoserMissing
{
use Winner, Loser {
Winner::m insteadof Loser;
}
}

function main() {}
14 changes: 14 additions & 0 deletions phpunit/code/trait_alias_missing_method.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
trait A
{
public function f(): void {}
}

class C
{
use A {
missing as g;
}
}

function main() {}
14 changes: 14 additions & 0 deletions phpunit/code/trait_alias_missing_qualified.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
trait A
{
public function f(): void {}
}

class C
{
use A {
A::missing as g;
}
}

function main() {}
19 changes: 19 additions & 0 deletions phpunit/code/trait_alias_trait_not_used.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
trait A
{
public function f(): void {}
}

trait B
{
public function h(): void {}
}

class C
{
use A {
B::h as g;
}
}

function main() {}
30 changes: 30 additions & 0 deletions phpunit/code/trait_const_enum_backed_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
// A shared backing scalar does not make cases of two different backed enums
// the same value: Zend compares the case objects, not their backing values.
enum E1: string
{
case Value = 'x';
}

enum E2: string
{
case Value = 'x';
}

trait T1
{
const X = E1::Value;
}

trait T2
{
const X = E2::Value;
}

class C
{
use T1;
use T2;
}

function main() {}
30 changes: 30 additions & 0 deletions phpunit/code/trait_const_enum_case_array_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
// Enum-case identity nests recursively: arrays holding same-named cases of
// two DIFFERENT enums hold distinct case objects, so the definitions conflict.
enum E1
{
case Value;
}

enum E2
{
case Value;
}

trait T1
{
const X = [E1::Value];
}

trait T2
{
const X = [E2::Value];
}

class C
{
use T1;
use T2;
}

function main() {}
26 changes: 26 additions & 0 deletions phpunit/code/trait_const_enum_case_array_same.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
// Enum-case identity nests recursively: two arrays holding the SAME enum case
// (and equal scalars) are one definition, so composing is legal.
enum E
{
case A;
case B;
}

trait T1
{
const X = [E::A, 1];
}

trait T2
{
const X = [E::A, 1];
}

class C
{
use T1;
use T2;
}

function main() {}
30 changes: 30 additions & 0 deletions phpunit/code/trait_const_enum_case_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
// Same-named cases of two DIFFERENT enums are distinct case objects in Zend,
// so the two definitions of X conflict even though both cases share the name.
enum E1
{
case Value;
}

enum E2
{
case Value;
}

trait T1
{
const X = E1::Value;
}

trait T2
{
const X = E2::Value;
}

class C
{
use T1;
use T2;
}

function main() {}
42 changes: 42 additions & 0 deletions phpunit/code/trait_const_enum_case_indirect_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
// Enum-case identity must survive INDIRECT constant references: each trait
// reads a class constant that holds a case of a different enum, so the two
// definitions of VALUE are different case objects and Zend rejects the
// composition even though both cases share the name `Value`.
enum E1
{
case Value;
}

enum E2
{
case Value;
}

class H1
{
public const ITEM = E1::Value;
}

class H2
{
public const ITEM = E2::Value;
}

trait T1
{
public const VALUE = H1::ITEM;
}

trait T2
{
public const VALUE = H2::ITEM;
}

class C
{
use T1;
use T2;
}

function main() {}
33 changes: 33 additions & 0 deletions phpunit/code/trait_const_enum_case_indirect_same.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
// The SAME enum case reached through an intermediate class constant is one
// definition: both traits' VALUE evaluate to E1::Value, so composing is
// legal — the indirection through H1::ITEM must not lose the case identity
// (a fresh non-interned value per evaluation would falsely conflict here).
enum E1
{
case Value;
case Other;
}

class H1
{
public const ITEM = E1::Value;
}

trait T1
{
public const VALUE = H1::ITEM;
}

trait T2
{
public const VALUE = H1::ITEM;
}

class C
{
use T1;
use T2;
}

function main() {}
50 changes: 50 additions & 0 deletions phpunit/code/trait_const_enum_case_inherited_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
// Different enum cases reached through INHERITED class constants: neither
// H1 nor H2 declares ITEM, so both lookups walk up to a parent whose ITEM
// holds a case of a different enum. The two definitions of VALUE are
// different case objects and the composition is rejected.
enum E1
{
case Value;
}

enum E2
{
case Value;
}

class B1
{
public const ITEM = E1::Value;
}

class B2
{
public const ITEM = E2::Value;
}

class H1 extends B1
{
}

class H2 extends B2
{
}

trait T1
{
public const VALUE = H1::ITEM;
}

trait T2
{
public const VALUE = H2::ITEM;
}

class C
{
use T1;
use T2;
}

function main() {}
44 changes: 44 additions & 0 deletions phpunit/code/trait_const_enum_case_inherited_same.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
// The SAME enum case reached through an INHERITED class constant: H1 does
// not declare ITEM itself, so the lookup walks up to BaseH. One trait reads
// the constant through the child, the other through the parent, and one
// reads the case directly — all three spellings are the same case object,
// so composing is legal.
enum E1
{
case Value;
case Other;
}

class BaseH
{
public const ITEM = E1::Value;
}

class H1 extends BaseH
{
}

trait T1
{
public const VALUE = H1::ITEM;
}

trait T2
{
public const VALUE = BaseH::ITEM;
}

trait T3
{
public const VALUE = E1::Value;
}

class C
{
use T1;
use T2;
use T3;
}

function main() {}
Loading
Loading