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();
?>