- final
- var
- const常量
- 類自動加載
- 構造函數(shù)與析構函數(shù)
- 范圍解析操作符
- 關于抽象類和接口
- Trait
- 匿名類
- 魔術方法
- clone
- static::后期靜態(tài)綁定
- 對象與引用及傳址賦值與引用賦值
原文:PHP基礎參考10-類與對象語法 - 9ong
PHP基礎參考11-引用語法 - 9ong
很多人都停留在php是過程語言,不能面向對象,php已經(jīng)8了,在5就已經(jīng)逐步與面向對象接軌了姥宝。
PHP 具有完整的對象模型减宣。特性包括: 訪問控制妓雾,抽象類和 final 類與方法摇幻,附加的魔術方法,接口彻犁,對象復制。
對于面向對象的基本知識凰慈,不需要我們介紹了汞幢,大家都懂。
final
被繼承的方法和屬性可以通過用同樣的名字重新聲明被覆蓋微谓。但是如果父類定義方法時使用了 final森篷,則該方法不可被覆蓋〔蛐停可以通過 parent:: 來訪問被覆蓋的方法或屬性仲智。
注意: 屬性不能被定義為 final,只有類和方法才能被定義為 final姻氨。
基本的知識钓辆,但很少人能用上,也許是場景不需要用到,但也許哪天就真香前联,時刻牢記功戚。
var
雖然有些版本允許使用var定義屬性,會被視為public似嗤,但我們不建議使用啸臀。
const常量
常量的值必須是一個定值,不能是變量烁落,類屬性乘粒,數(shù)學運算的結果或函數(shù)調(diào)用。
要區(qū)別于外部const/define定義的常量顽馋。
PHP 7.1.0 開始谓厘,類的常量可以定義為公有、私有或受保護寸谜。如果沒有設置這些關鍵字竟稳,則該常量默認為公有,也就是之前的版本只能使用const關鍵字定義常量熊痴,默認這些常量是公開可訪問的他爸,7.1之后允許public、protect果善、private的訪問控制關鍵字诊笤。
類自動加載
現(xiàn)代php框架都引入自動加載機制了,特別是composer第三方庫使用巾陕。
spl_autoload_register() 函數(shù)可以注冊任意數(shù)量的自動加載器讨跟,當使用尚未被定義的類(class)和接口(interface)時自動去加載。
不建議使用__autoload函數(shù)鄙煤,后續(xù)版本會被棄用晾匠。
spl_autoload_register函數(shù)用于注冊觸發(fā)加載類,提供回調(diào)加載梯刚,達到按需加載凉馆。
spl_autoload_register(function ($class_name) {
require_once $class_name . '.php';
});
$obj = new MyClass1();
$obj2 = new MyClass2();
構造函數(shù)與析構函數(shù)
子類的構造函數(shù)不會默認或隱性的調(diào)用父類構造函數(shù),有需要時亡资,要手動調(diào)用父類構造函數(shù)澜共。
析構函數(shù)即使在使用 exit() 終止腳本運行時也會被調(diào)用。但在析構函數(shù)中調(diào)用 exit() 將會中止其余關閉操作的運行锥腻。
在析構函數(shù)(在腳本終止時被調(diào)用)中拋出一個異常會導致致命錯誤嗦董。
范圍解析操作符
范圍解析操作符 ::
只是認識下這個符號叫:范圍解析操作符
在訪問類常量、靜態(tài)屬性瘦黑、靜態(tài)方法展懈,我們常會用到雙冒號销睁,也就是范圍解析操作符。
關于抽象類和接口
如果對抽象類和接口有不清楚的可以看官方文檔介紹
Trait
Trait 是為類似 PHP 的單繼承語言而準備的一種代碼復用機制存崖。Trait 為了減少單繼承語言的限制冻记,使開發(fā)人員能夠自由地在不同層次結構內(nèi)獨立的類中復用 method。
Trait 和 Class 相似来惧,但僅僅旨在用細粒度和一致的方式來組合功能冗栗。 無法通過 trait 自身來實例化。它為傳統(tǒng)繼承增加了水平特性的組合供搀;也就是說隅居,應用的幾個 Class 之間不需要繼承。
-
優(yōu)先順序是當前類中的方法會覆蓋 trait 方法葛虐,而 trait 方法又覆蓋了基類中的方法胎源。
class Base { public function sayHello() { echo 'Hello '; } } trait HelloWorld { public function sayHello() { echo 'Hello World!'; } } class MyHelloWorld extends Base { use HelloWorld; } $o = new MyHelloWorld(); $o->sayHello(); //輸出:Hello World! //因為trait覆蓋了基類的方法 class TheWorldIsNotEnough { use HelloWorld; public function sayHello() { echo 'Hello Universe!'; } } $o = new TheWorldIsNotEnough(); $o->sayHello(); //輸出:Hello Universe! //因為當前類覆蓋trait的方法
一個類中支持use多個trait,用逗號隔開
-
方法沖突解決
如果兩個 trait 都插入了一個同名的方法屿脐,如果沒有明確解決沖突將會產(chǎn)生一個致命錯誤涕蚤。
為了解決多個 trait 在同一個類中的命名沖突,需要使用 insteadof 操作符來明確指定使用沖突方法中的哪一個的诵。
以上方式僅允許排除掉其它方法万栅,as 操作符可以 為某個方法引入別名。 注意西疤,as 操作符不會對方法進行重命名烦粒,也不會影響其方法。
use A, B { B::smallTalk insteadof A;//相當于排除A中的smallTalk A::bigTalk insteadof B; B::bigTalk as talk;//定義了talk別名 }
-
修改use trait中的方法訪問控制
直接看范例:
// 修改 sayHello 的訪問控制 class MyClass1 { use HelloWorld { sayHello as protected; } } // 給方法一個改變了訪問控制的別名 // 原版 sayHello 的訪問控制則沒有發(fā)生變化 class MyClass2 { use HelloWorld { sayHello as private myPrivateHello; } }
-
trait組合
trait和class一樣也可以組合其他多個trait代赁。
trait支持抽象方法扰她,用于強制實體類實現(xiàn)trait的抽象方法
trait支持靜態(tài)方法
trait支持屬性,但注意沖突芭碍,一般是不能定義同樣名稱的屬性徒役。我們建議避免trait和class出現(xiàn)相同名稱的屬性,即使訪問可見性豁跑、初始值都一樣(允許的),我也不建議泻云,會導致混亂艇拍。
匿名類
php7開始支持匿名類,用于創(chuàng)建一次性簡單對象宠纯。
$util->setLogger(new class {
public function log($msg)
{
echo $msg;
}
});
//也就是不需要先定義一個logger的對象卸夕,再new給setLogger方法。
魔術方法
PHP所提供的重載(overloading)是指動態(tài)地創(chuàng)建類屬性和方法婆瓜。我們是通過魔術方法(magic methods)來實現(xiàn)的快集。
PHP中的重載與其它絕大多數(shù)面向對象語言不同贡羔。傳統(tǒng)的重載是用于提供多個同名的類方法,但各方法的參數(shù)類型和個數(shù)不同个初。
clone
對象復制可以通過 clone 關鍵字來完成(如果可能乖寒,這將調(diào)用對象的 __clone() 方法)。
當對象被復制后院溺,PHP 5 會對對象的所有屬性執(zhí)行一個淺復制(shallow copy)珍逸。所有的引用屬性 仍然會是一個指向原來的變量的引用叭爱。如果有少量及簡單的引用屬性买雾,可以在魔術方法__clone中手動實現(xiàn)引用屬性的復制缨称。
class AA{
public $object1;
function __clone()
{
// 強制復制一份this->object, 否則仍然指向同一個對象
$this->object1 = clone $this->object1;
}
}
$a = new AA();
$a2 = clone $a;//通過__clone方法器净,達到對$a對象的深拷貝当凡。
static::后期靜態(tài)綁定
self沿量、parent朴则、static
我們都知道parent的用法汹想,就是從當前類(子類)往上追溯基類的存在的這個方法古掏;static則是從當前類(父類、基類)往下追溯至當前執(zhí)行實例(子類)中存在的方法侦啸;
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 后期靜態(tài)綁定從這里開始拧烦,這里會執(zhí)行調(diào)用test方法的實例的who方法,也就是B類實例的who方法。
self::who();//這里只會調(diào)用當前類中的who方法秦士,如果有的話,也就是當前代碼行所在類A
parent::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();//輸出:BA
對象與引用及傳址賦值與引用賦值
在php5 的對象編程經(jīng)常提到的一個關鍵點是“默認情況下對象是通過引用傳遞的”隧土。但其實這不是完全正確的。
PHP 的引用是別名艇抠,就是兩個不同的變量名字指向相同的內(nèi)容。
在 PHP 5以后异剥,一個對象變量已經(jīng)不再保存整個對象的值青伤。而是保存一個標識符來訪問真正的對象內(nèi)容擎厢。
當對象作為參數(shù)傳遞,作為結果返回厘惦,或者賦值給另外一個變量偷仿,另外一個變量跟原來的不是引用的關系,只是他們都保存著同一個標識符的拷貝宵蕉,這個標識符指向同一個對象的真正內(nèi)容酝静。
這標識符我們可以理解為存儲地址,所以php的對象正常情況下的復制羡玛、傳遞都是通過傳址的方式别智,而不是引用,雖然效果是一樣的稼稿。
class A {
public $foo = 1;
}
$a = new A;
$b = $a; // $a ,$b都是同一個標識符的拷貝薄榛,意味著a、b指向同一個地址
// ($a) = ($b) = <id>
$b->foo = 2;
echo $a->foo."\n";//輸出:2
$c = new A;
$d = &$c; // $c ,$d是引用让歼,d是c的一個別名敞恋,其實他們還是一樣的
// ($c,$d) = <id>
$d->foo = 2;
echo $c->foo."\n";//輸出:2
$e = new A;
function foo($obj) {//e和obj都是同一個標識符的拷貝
// ($obj) = ($e) = <id>
$obj->foo = 2;
}
foo($e);
echo $e->foo."\n";//輸出:2