php面向對象編程的三大特性是封裝性、繼承性和多態性。本文將介紹php的這三大特性
封裝就是把對象中的成員屬性和成員方法加上訪問修飾符( public(公有),protected(受保護)或 private(私有)),使其盡可能隱藏對象的內部細節,以達到對成員的訪問控制
被定義為公有的類成員可以在任何地方被訪問。被定義為受保護的類成員則可以被其自身以及其子類和父類訪問。被定義為私有的類成員則只能被其定義所在的類訪問
類屬性必須定義為公有,受保護,私有之一。如果用 var 定義,則被視為公有
<?php class MyClass { public $public = 'Public'; protected $protected = 'Protected'; private $private = 'Private'; function printHello() { echo $this->public; echo $this->protected; echo $this->private; } } $obj = new MyClass(); echo $obj->public; // 這行能被正常執行 echo $obj->protected; // 這行會產生一個致命錯誤 echo $obj->private; // 這行也會產生一個致命錯誤 $obj->printHello(); // 輸出 Public、Protected 和 Private class MyClass2 extends MyClass { // 可以對 public 和 protected 進行重定義,但 private 而不能 protected $protected = 'Protected2'; function printHello() { echo $this->public; echo $this->protected; echo $this->private; } } $obj2 = new MyClass2(); echo $obj2->public; // 這行能被正常執行 echo $obj2->private; // 未定義 private echo $obj2->protected; // 這行會產生一個致命錯誤 $obj2->printHello(); // 輸出 Public、Protected2 和 Undefined ?>
類中的方法可以被定義為公有,私有或受保護。如果沒有設置這些關鍵字,則該方法默認為公有
<?php class MyClass { public function __construct() { } public function MyPublic() { } protected function MyProtected() { } private function MyPrivate() { } function Foo() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); } } $myclass = new MyClass; $myclass->MyPublic(); // 這行能被正常執行 $myclass->MyProtected(); // 這行會產生一個致命錯誤 $myclass->MyPrivate(); // 這行會產生一個致命錯誤 $myclass->Foo(); // 公有,受保護,私有都可以執行 class MyClass2 extends MyClass { function Foo2() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); // 這行會產生一個致命錯誤 } } $myclass2 = new MyClass2; $myclass2->MyPublic(); // 這行能被正常執行 $myclass2->Foo2(); // 公有的和受保護的都可執行,但私有的不行 ?>
繼承已為大家所熟知的一個程序設計特性,PHP 的對象模型也使用了繼承。繼承將會影響到類與類,對象與對象之間的關系
當擴展一個類,子類就會繼承父類所有公有的和受保護的方法。除非子類覆蓋了父類的方法,被繼承的方法都會保留其原有功能
繼承對於功能的設計和抽象是非常有用的,而且對於類似的對象增加新功能就無須重新再寫這些公用的功能
類繼承
一個類可以在聲明中用 extends 關鍵字繼承另一個類的方法和屬性。PHP不支持多重繼承,一個類只能繼承一個基類
被繼承的方法和屬性可以通過用同樣的名字重新聲明被覆蓋。但是如果父類定義方法時使用了 final,則該方法不可被覆蓋
當覆蓋方法時,參數必須保持一致否則 PHP 將發出 E_STRICT 級別的錯誤信息。但構造函數例外,構造函數可在被覆蓋時使用不同的參數
<?php class foo { public function printItem($string) { echo 'Foo: ' . $string . PHP_EOL; } public function printPHP() { echo 'PHP is great.' . PHP_EOL; } } class bar extends foo { public function printItem($string) { echo 'Bar: ' . $string . PHP_EOL; } } $foo = new foo(); $bar = new bar(); $foo->printItem('baz'); // Output: 'Foo: baz' $foo->printPHP(); // Output: 'PHP is great' $bar->printItem('baz'); // Output: 'Bar: baz' $bar->printPHP(); // Output: 'PHP is great' ?>
在子類中,使用parent訪問父類中的被覆蓋的屬性和方法
<?php class Person { protected $name; protected $sex; public function __construct($name=“”, $sex=“男”) { } public function say(){} } class Student extends Person { private $school; public function __construct($name="", $sex="男", $school="") { parent::__construct($name,$sex); $this->school = $school; } public function say( ) { parent::say(); echo "在".$this->school."學校上學<br>"; } } $student = new Student("張三","男",20, "edu"); $student->say();
抽象
在面向對象語言中,一個類可以有一個或多個子類,而每個類都有至少一個公有方法作為外部代碼訪問其的接口。而抽象方法就是為了方便繼承而引入的
當類中有一個方法,他沒有方法體,也就是沒有花括號,直接分號結束,像這種方法我們叫抽象方法,必須使用關鍵字abstract定義
public abstract function fun();
包含這種方法的類必須是抽象類也要使用關鍵字abstract加以聲明
定義為抽象的類不能被實例化。任何一個類,如果它裡面至少有一個方法是被聲明為抽象的,那麼這個類就必須被聲明為抽象的。被定義為抽象的方法只是聲明了其調用方式(參數),不能定義其具體的功能實現
抽象方法的作用就是規定了子類必須有這個方法的實現,功能交給子類,只寫出結構, 而沒有具體實現,實現交給具體的子類按自己的功能去實現;抽象類的作用是要求子類的結構,所以抽象類就是一個規范
繼承一個抽象類的時候,子類必須定義父類中的所有抽象方法;另外,這些方法的訪問控制必須和父類中一樣(或者更為寬松)。例如某個抽象方法被聲明為受保護的,那麼子類中實現的方法就應該聲明為受保護的或者公有的,而不能定義為私有的。此外方法的調用方式必須匹配,即類型和所需參數數量必須一致。例如,子類定義了一個可選參數,而父類抽象方法的聲明裡沒有,則兩者的聲明並無沖突
<?php abstract class Person { public $name; public $age; abstract function say(); abstract function eat(); function run() { echo "11111111111111<br>"; } function sleep() { echo "2222222222222222<br>"; } } class StudentCn extends Person { function say() { echo "中文<br>"; } function eat() { echo "筷子"; } } class StudentEn extends Person { function say() { echo "english<br>"; } function eat() { echo "刀叉"; } } $s1 = new StudentEn(); $s1 -> say();//english $s1 -> eat();//刀叉 ?>
接口
PHP與大多數面向對象編程語言一樣,不支持多重繼承,也就是說每個類只能繼承一個父類。為了解決這個這個問題,PHP引入了接口,接口的思想是指定了一個實現了該接口的類必須實現的一系列函數
使用接口(interface),可以指定某個類必須實現哪些方法,但不需要定義這些方法的具體內容。接口是通過interface關鍵字來定義的,就像定義一個標准的類一樣,但其中定義所有的方法都是空的
接口中定義的所有方法都必須是公有,這是接口的特性。要實現一個接口,使用 implements 操作符。類中必須實現接口中定義的所有方法,否則會報一個致命錯誤。類可以實現多個接口,用逗號來分隔多個接口的名稱。接口中也可以定義常量。接口常量和類常量的使用完全相同,但是不能被子類或子接口所覆蓋
//實現一個接口 <?php interface iTemplate { public function setVariable($name, $var); public function getHtml($template); } class Template implements iTemplate { private $vars = array(); public function setVariable($name, $var) { $this->vars[$name] = $var; } public function getHtml($template) { foreach($this->vars as $name => $value) { $template = str_replace('{' . $name . '}', $value, $template); } return $template; } } ?>
//常量不能被覆蓋 <?php interface a { const b = 'Interface constant'; } echo a::b; // 錯誤寫法,因為常量不能被覆蓋。接口常量的概念和類常量是一樣的。 class b implements a { const b = 'Class constant'; } ?>
//繼承多個接口 <?php interface a { public function foo(); } interface b { public function bar(); } interface c extends a, b { public function baz(); } ?>
對象的多態性是指在父類中定義的屬性或行為被子類繼承之後,可以具有不同的數據類型或表現出不同的行為。這使得同一個屬性或行為在父類及其各個子類中具有不同的語義。例如:"幾何圖形"的"繪圖"方法,"橢圓"和"多邊形"都是"幾何圖"的子類,其"繪圖"方法功能不同
單態
說到多態,首先要提到單態設計模式,單態模式的主要作用是保證在面向對象編程設計中,一個類只能有一個實例對象存在
<?php class DB { private static $obj = null; private function __construct() { echo "連接數據庫成功<br>"; } public static function getInstance() { if(is_null(self::$obj)) self::$obj = new self(); return self::$obj; } public function query($sql) { echo $sql; } } $db = DB::getInstance(); $db -> query("select * from user"); ?>
多態展現了動態綁定的功能,也稱為“同名異式”,多態可以讓軟件在開發和維護時,達到充分的延伸性
在php中,多態性就是指方法的重寫,一個子類可中可以重新修改父類中的某些方法,使其具有自己的特征。重寫要求子類的方法和父類的方法名稱相同,這可以通過聲明抽象類或是接口來規范
<?php interface USB { const WIDTH = 12; const HEIGHT = 3; function load(); function run(); function stop(); } class Cumputer { function useUSB(USB $usb) { $usb -> load(); $usb -> run(); $usb -> stop(); } } class Mouse implements USB{ function load() { echo "加載鼠標成功!<br>"; } function run() { echo "運行鼠標功能!<br>"; } function stop() { echo "鼠標工作結束!<br>"; } } class KeyPress implements USB { function load() { echo "加載鍵盤成功!<br>"; } function run() { echo "運行鍵盤成功!<br>"; } function stop() { echo "停止鍵盤使用!<br>"; } } class Worker { function work() { $c = new Cumputer(); $m = new Mouse; $k = new KeyPress; $c->useUSB($k); $c->useUSB($m); } } $w = new Worker; $w -> work(); ?>