--TEST-- PHP Spec test generated from ./traits/traits.php --FILE-- " . __TRAIT__ . "<\n"; echo "Inside >" . __CLASS__ . "<\n"; echo "Inside >" . __METHOD__ . "<\n"; echo "Inside >" . __FUNCTION__ . "<\n"; echo "===================== Test an Empty Trait =========================\n"; trait T1 {} // allowed to be empty class C1 { use T1; } echo "========== Test Overriding and Collisions Between Traits =====\n"; trait T2a { function f() { echo "Inside " . __TRAIT__ . "\n"; echo "Inside " . __CLASS__ . "\n"; echo "Inside " . __METHOD__ . "\n"; } } trait T2b { // function f($p1, $p2) // signatures not factored in when looking for name clashes function f() { echo "Inside " . __TRAIT__ . "\n"; echo "Inside " . __CLASS__ . "\n"; echo "Inside " . __METHOD__ . "\n"; } } class C2Base { public function f() { echo "Inside " . __METHOD__ . "\n"; } } class C2Derived extends C2Base { // use T2a; use T2b; // equivalent to use T2a, T2b; // use T2a, T2b; // clash between two names f REGARDLESS of argument lists use T2a, T2b { // with both below excepted, went to base, bypassing both traits!! T2a::f insteadof T2b; // T2b::f insteadof T2a; T2b::f as g; // allow otherwise hidden T2B::f to be seen through alias g T2a::f as h; // allow T2a::f to also be seen through alias h // don't need qualifier prefix if f is unambiguous } // public function f() { echo "Inside " . __METHOD__ . "\n"; } } $c2 = new C2Derived; echo "-------\n"; $c2->f(); // call T2a::f echo "-------\n"; $c2->g(); // call T2b::f via its alias g echo "-------\n"; $c2->h(); // call T2a::f via its alias h // confirmed that lookup starts with current class, then trait(s), then base classes echo "===================== Changing Visibility =========================\n"; trait T3 { public function m1() { echo "Inside " . __METHOD__ . "\n"; } protected function m2() { echo "Inside " . __METHOD__ . "\n"; } private function m3() { echo "Inside " . __METHOD__ . "\n"; } function m4() { echo "Inside " . __METHOD__ . "\n"; } // implicitly public } class C3 { use T3 { m1 as protected; // reduce visibility to future, derived classes m2 as private; m3 as public; m3 as protected z3; } } $c3 = new C3; //$c3->m1(); // accessible, by default, but not once protected //$c3->m2(); // inaccessible, by default $c3->m3(); // inaccessible, by default $c3->m4(); // accessible, by default echo "===================== Traits using other Traits =========================\n"; trait Tx1 { function k() { echo "Inside " . __TRAIT__ . "\n"; echo "Inside " . __CLASS__ . "\n"; echo "Inside " . __METHOD__ . "\n"; } } trait Tx2 { function m() { echo "Inside " . __TRAIT__ . "\n"; echo "Inside " . __CLASS__ . "\n"; echo "Inside " . __METHOD__ . "\n"; } } trait T4 { use Tx1, Tx2; use T2a, T2b, T3 { Tx1::k as kk; T2a::f insteadof T2b; } } class C4 { use T4; } $c4 = new C4; echo "-------\n"; $c4->f(); echo "-------\n"; $c4->m1(); echo "-------\n"; $c4->k(); echo "-------\n"; $c4->m(); echo "===================== static properties =========================\n"; trait T5 { public static $prop; } class C5a { use T5; } class C5b { use T5; } C5a::$prop = 123; C5b::$prop = "red"; echo C5a::$prop . "\n"; // ==> 123 echo C5b::$prop . "\n"; // ==> red echo "===================== function statics =========================\n"; trait T6 { public function f() { echo "Inside " . __METHOD__ . "\n"; static $v = 0; // static is class-specific echo "\$v = " . $v++ . "\n"; } } class C6a { use T6; } class C6b { use T6; } $v1 = new C6a; $v1->f(); // method run twice with same $v $v1->f(); echo "-------\n"; $v2 = new C6b; $v2->f(); // method run three times with a different $v $v2->f(); $v2->f(); echo "===================== Using a Trait without a Class =========================\n"; trait T7 { public static $pubs = 123; function f() // implicitly public { echo "Inside " . __TRAIT__ . "\n"; echo "Inside " . __CLASS__ . "\n"; echo "Inside " . __METHOD__ . "\n"; var_dump($this); } public static function g() { echo "Inside " . __TRAIT__ . "\n"; echo "Inside " . __CLASS__ . "\n"; echo "Inside " . __METHOD__ . "\n"; } } T7::f(); // calls f like a static function with class name being the trait name echo "-------\n"; T7::g(); /* echo "-------\n"; var_dump(T7::pubs); // doesn't work for static properties */ echo "===================== examples for spec =========================\n"; trait T9a { public function compute(/* ... */) { /* ... */ } } trait T9b { public function compute(/* ... */) { /* ... */ } } trait T9c { public function sort(/* ... */) { /* ... */ } } trait T9d { use T9c; use T9a, T9b { T9a::compute insteadof T9b; T9c::sort as private sorter; } } trait T10 { private $prop1 = 1000; protected static $prop2; var $prop3; public function compute() {} public static function getData() {} } --EXPECTF-- Inside >< Inside >< Inside >< Inside >< ===================== Test an Empty Trait ========================= ========== Test Overriding and Collisions Between Traits ===== ------- Inside T2a Inside C2Derived Inside T2a::f ------- Inside T2b Inside C2Derived Inside T2b::f ------- Inside T2a Inside C2Derived Inside T2a::f ===================== Changing Visibility ========================= Inside T3::m3 Inside T3::m4 ===================== Traits using other Traits ========================= ------- Inside T2a Inside C4 Inside T2a::f ------- Inside T3::m1 ------- Inside Tx1 Inside C4 Inside Tx1::k ------- Inside Tx2 Inside C4 Inside Tx2::m ===================== static properties ========================= 123 red ===================== function statics ========================= Inside T6::f $v = 0 Inside T6::f $v = 1 ------- Inside T6::f $v = 0 Inside T6::f $v = 1 Inside T6::f $v = 2 ===================== Using a Trait without a Class ========================= %AInside T7 Inside T7 Inside T7::f Notice: Undefined variable: this in %s/traits/traits.php on line 227 NULL ------- Inside T7 Inside T7 Inside T7::g ===================== examples for spec =========================