php.netphp
在類定義內部,能夠用 new self 和 new parent 建立新對象。
當把一個對象已經建立的實例賦給一個新變量時,新變量會訪問同一個實例,就和用該對象賦值同樣。能夠用克隆給一個已建立的對象創建一個新實例。數組
<?php $instance = new SimpleClass(); $assigned = $instance; $reference =& $instance; $instance->var = '$assigned will have this value'; $instance = null; // $instance and $reference become null var_dump($instance); var_dump($reference); var_dump($assigned); ?>
輸出:函數
NULL NULL object(SimpleClass)#1 (1) { ["var"]=> string(30) "$assigned will have this value" }
PHP 5.3.0 引進了兩個新方法來建立一個對象的實例:this
<?php class Test { static public function getNew() { return new static; } } $obj1 = new Test(); $obj2 = new $obj1; //第一種 $obj3 = Test::getNew();
自 PHP 5.5 起,使用 ClassName::class 你能夠獲取一個字符串,包含了類 ClassName 的徹底限定名稱。這對使用了 命名空間 的類尤爲有用。.net
能夠把在類中始終保持不變的值定義爲常量。在定義和使用常量的時候不須要使用 $ 符號debug
<?php class MyClass { const constant = 'constant value'; function showConstant() { echo self::constant . "\n"; } }
靜態屬性不能經過一個類已實例化的對象來訪問(但靜態方法能夠)code
任何一個類,若是它裏面至少有一個方法是被聲明爲抽象的,那麼這個類就必須被聲明爲抽象的。對象
<?php abstract class AbstractClass { // 強制要求子類定義這些方法 abstract protected function getValue(); abstract protected function prefixValue($prefix); // 普通方法(非抽象方法) public function printOut() { print $this->getValue() . "\n"; } }
傳統繼承增長了水平特性的組合,避免傳統多繼承和 Mixin 類相關典型問題。優先級:當前類的成員覆蓋了 trait 的方法,而 trait 則覆蓋了被繼承的方法。繼承
<?php trait ezcReflectionReturnInfo { function getReturnType() { /*1*/ } function getReturnDescription() { /*2*/ } } class ezcReflectionMethod extends ReflectionMethod { use ezcReflectionReturnInfo; /* ... */ } class ezcReflectionFunction extends ReflectionFunction { use ezcReflectionReturnInfo; /* ... */ }
經過逗號分隔,在 use 聲明列出多個 trait,能夠都插入到一個類中。ip
<?php trait Hello { public function sayHello() { echo 'Hello '; } } trait World { public function sayWorld() { echo 'World'; } } class MyHelloWorld { use Hello, World; public function sayExclamationMark() { echo '!'; } } $o = new MyHelloWorld(); $o->sayHello(); $o->sayWorld();
若是兩個 trait 都插入了一個同名的方法,若是沒有明確解決衝突將會產生一個致命錯誤。
須要使用 insteadof 操做符來明確指定使用衝突方法中的哪個。as 操做符能夠將其中一個衝突的方法以另外一個名稱來引入。
示例:定義了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk,用了 as 操做符來定義了 talk 來做爲 B 的 bigTalk 的別名。
<?php trait A { public function smallTalk() { echo 'a'; } public function bigTalk() { echo 'A'; } } trait B { public function smallTalk() { echo 'b'; } public function bigTalk() { echo 'B'; } } class Aliased_Talker { use A, B { B::smallTalk insteadof A; A::bigTalk insteadof B; B::bigTalk as talk; } }
使用as
<?php trait HelloWorld { public function sayHello() { echo 'Hello World!'; } } // 修改 sayHello 的訪問控制 class MyClass1 { use HelloWorld { sayHello as protected; } } // 給方法一個改變了訪問控制的別名 // 原版 sayHello 的訪問控制則沒有發生變化 class MyClass2 { use HelloWorld { sayHello as private myPrivateHello; } } ?>
其它 trait 也可以使用 trait。
trait 支持抽象方法的使用。
Trait 一樣能夠定義屬性。
匿名類被嵌套進普通 Class 後,不能訪問這個外部類(Outer class)的 private(私有)、protected(受保護)方法或者屬性。 爲了訪問外部類(Outer class)protected 屬性或方法,匿名類能夠 extend(擴展)此外部類。 爲了使用外部類(Outer class)的 private 屬性,必須經過構造器傳進來:
<?php class Outer { private $prop = 1; protected $prop2 = 2; protected function func1() { return 3; } public function func2() { return new class($this->prop) extends Outer { private $prop3; public function __construct($prop) { $this->prop3 = $prop; } public function func3() { return $this->prop2 + $this->prop3 + $this->func1(); } }; } } echo (new Outer)->func2()->func3();
不可訪問屬性、不可訪問方法:未定義或不可見的類屬性或方法
在給不可訪問屬性賦值時,__set() 會被調用。
讀取不可訪問屬性的值時,__get() 會被調用。
當對不可訪問屬性調用 isset() 或 empty() 時,__isset() 會被調用。
當對不可訪問屬性調用 unset() 時,__unset() 會被調用。
在對象中調用一個不可訪問方法時,__call() 會被調用。
在靜態上下文中調用一個不可訪問方法時,__callStatic() 會被調用。
serialize() 函數會檢查類中是否存在一個魔術方法 __sleep()。若是存在,該方法會先被調用,而後才執行序列化操做。此功能能夠用於清理對象,並返回一個包含對象中全部應被序列化的變量名稱的數組。
unserialize() 會檢查是否存在一個 __wakeup() 方法。若是存在,則會先調用 __wakeup 方法,預先準備對象須要的資源。
public void __set ( string $name , mixed $value ) public mixed __get ( string $name ) public bool __isset ( string $name ) public void __unset ( string $name ) public mixed __call ( string $name , array $arguments ) public static mixed __callStatic ( string $name , array $arguments ) __construct(), __destruct(), __sleep(), __wakeup(), __toString(), __invoke(),__set_state(), __clone() , __debugInfo()
示例:
<?php class PropertyTest { /** 被重載的數據保存在此 */ private $data = array(); /** 重載不能被用在已經定義的屬性 */ public $declared = 1; /** 只有從類外部訪問這個屬性時,重載纔會發生 */ private $hidden = 2; public function __set($name, $value) { echo "Setting '$name' to '$value'\n"; $this->data[$name] = $value; } public function __get($name) { echo "Getting '$name'\n"; if (array_key_exists($name, $this->data)) { return $this->data[$name]; } $trace = debug_backtrace(); trigger_error( 'Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE); return null; } /** PHP 5.1.0以後版本 */ public function __isset($name) { echo "Is '$name' set?\n"; return isset($this->data[$name]); } /** PHP 5.1.0以後版本 */ public function __unset($name) { echo "Unsetting '$name'\n"; unset($this->data[$name]); } /** 非魔術方法 */ public function getHidden() { return $this->hidden; } }
call示例:arguments是一個數組
<?php class MethodTest { public function __call($name, $arguments) { // 注意: $name 的值區分大小寫 var_dump($arguments); } /** PHP 5.3.0以後版本 */ public static function __callStatic($name, $arguments) { // 注意: $name 的值區分大小寫 var_dump($arguments); } } $obj = new MethodTest; $obj->runTest('in object context','fyfy'); MethodTest::runTest('in static context'); // PHP 5.3.0以後版本 ?> //輸出相似 /* array(2) { [0] => string(17) "in object context" [1] => string(4) "fyfy" } array(1) { [0] => string(17) "in static context" } */
默認狀況下,全部可見屬性都將被用於遍歷。
<?php class MyClass { public $var1 = 'value 1'; public $var2 = 'value 2'; public $var3 = 'value 3'; protected $protected = 'protected var'; private $private = 'private var'; function iterateVisible() { echo "MyClass::iterateVisible:\n"; foreach($this as $key => $value) { print "$key => $value\n"; } } } $class = new MyClass(); foreach($class as $key => $value) { print "$key => $value\n"; } echo "\n"; $class->iterateVisible(); ?>
clone 關鍵字,淺複製(shallow copy)。全部的引用屬性 仍然會是一個指向原來的變量的引用。當複製完成時,若是定義了 __clone() 方法,則新建立的對象(複製生成的對象)中的 __clone() 方法會被調用,可用於修改屬性的值(若是有必要的話)。
示例:關於淺複製
<?php class subclass{ public $var1='subclass default'; } class MyClass { public $var1 = 'myclass default'; public $object; function __construct(){ $this->object=new subclass(); } } $object1 = new MyClass(); $object2 = clone $object1; $object1->object->var1='object1 change'; $object1->var1='object1 change'; print_r($object1); print_r($object2); ?>
輸出結果:
MyClass Object ( [var1] => object1 change [object] => subclass Object ( [var1] => object1 change ) ) MyClass Object ( [var1] => myclass default [object] => subclass Object ( [var1] => object1 change )
==:兩個對象的屬性和屬性值 都相等,並且兩個對象是同一個類的實例,那麼這兩個對象變量相等。 ===:必須是同一個對象。