Skip to content
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() {}
25 changes: 25 additions & 0 deletions phpunit/code/trait_const_enum_case_same.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
// The SAME enum case in both traits is one definition: composing is legal.
enum E1
{
case Value;
case Other;
}

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

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

class C
{
use T1;
use T2;
}

function main() {}
25 changes: 25 additions & 0 deletions phpunit/code/trait_const_enum_diff_case_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
// Different cases of the SAME enum are different case objects: conflict.
enum E1
{
case Value;
case Other;
}

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

trait T2
{
const X = E1::Other;
}

class C
{
use T1;
use T2;
}

function main() {}
26 changes: 26 additions & 0 deletions phpunit/code/trait_const_enum_marker_string_collision.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
// A user string can spell ANY byte sequence (PHP strings are binary-safe), so
// no marker string can stand in for an enum case: Zend rejects this
// composition because an enum-case object and a string are different values.
enum E
{
case A;
}

trait T1
{
const X = E::A;
}

trait T2
{
const X = "\0enum-case\0e::A";
}

class C
{
use T1;
use T2;
}

function main() {}
18 changes: 18 additions & 0 deletions phpunit/code/trait_const_identity_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
trait A
{
const X = 1;
}

trait B
{
const X = 1.0;
}

class C
{
use A;
use B;
}

function main() {}
31 changes: 31 additions & 0 deletions phpunit/code/trait_const_self_reference_namespaced.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App;

// One definition spelled two ways: Zend evaluates both initializers and the
// composed values match. The evaluation resolves `self::PARTS` against a
// fully qualified trait/class name; the current namespace must not be
// prepended a second time (`App\App\...`), and the comparison must not fall
// back to spelling equality (the spellings differ on purpose).
trait T1
{
const PARTS = [1, 2];
const ALL = [...self::PARTS, 9];
}

trait T2
{
const PARTS = [1, 2];
const ALL = [...self::PARTS, 8 + 1];
}

class C
{
use T1;
use T2;
}

function main(): void
{
var_dump(C::ALL);
}
18 changes: 18 additions & 0 deletions phpunit/code/trait_const_value_conflict.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
trait A
{
const int X = 1;
}

trait B
{
const int X = 3;
}

class C
{
use A;
use B;
}

function main() {}
22 changes: 22 additions & 0 deletions phpunit/code/trait_insteadof_excluded_twice.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
// Both rules pass the winner-existence check, but the same trait method
// (B::f) may only be excluded once.
trait A
{
public function f(): void {}
}

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

class X
{
use A, B {
A::f insteadof B;
A::f insteadof B;
}
}

function main() {}
Loading
Loading