350 строки
6.3 KiB
PHP
350 строки
6.3 KiB
PHP
--TEST--
|
|
PHP Spec test generated from ./traits/traits.php
|
|
--FILE--
|
|
<?php
|
|
|
|
/*
|
|
+-------------------------------------------------------------+
|
|
| Copyright (c) 2014 Facebook, Inc. (http://www.facebook.com) |
|
|
+-------------------------------------------------------------+
|
|
*/
|
|
|
|
error_reporting(-1);
|
|
|
|
echo "Inside >" . __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 =========================
|