我(wǒ)們可以想象我(wǒ)們的宇宙是由不同的對象組成,像太陽,地球,月亮等等。同樣我(wǒ)們可以想象我(wǒ)們的車(chē)由不同的組件組成如車(chē)輪,轉向盤,齒輪等。同樣有面向對象編程概念,假設一(yī)切作爲對象使用不同的對象實例化一(yī)個事物(wù)。
面向對象的概念
在我(wǒ)們進入講述細節之前,讓我(wǒ)們首先定義面向對象編程相關的重要術語。
類:這是一(yī)個編程定義的數據類型,包括本地的方法以及本地數據。你能想到的一(yī)個類模闆制作許多相同類型的實例(或類)的對象。
對象:一(yī)個單獨的數據結構用來定義的一(yī)個類的實例。你定義一(yī)個類,然後讓許多對象屬于它。對象也被稱爲實例。
成員(yuán)變量:這是在類的内部定義的變量。這些數據對于外(wài)部類是不可見的,但是可以通過成員(yuán)函數來訪問。對象一(yī)旦創建這些變量被稱該對象的屬性。
成員(yuán)函數:這些函數定義在一(yī)個類,用于訪問對象的數據。
繼承:當一(yī)個類被定義爲繼承一(yī)個已經存在的父類,我(wǒ)們稱這個類爲繼承類,這裏繼承類可以使用父類的一(yī)些成員(yuán)函數和變量。
父類:一(yī)個類被另一(yī)個類繼承。這個類也被稱爲基類或超類。
子類:一(yī)個類繼承另一(yī)個類。這個類也被稱爲一(yī)個子類或派生(shēng)類
多态性:這是一(yī)個面向對象的概念,相同的函數可以用于不同的目的。例如函數名仍将是相同的,但它采取不同的數量的參數,可以做不同的任務,完成不同的工(gōng)作。
重載:一(yī)種多态性的部分(fēn)指在所有的運算符有不同的實現取決于他們的類型參數。同樣的函數也可以重載伴随着不同的實現。
數據抽象:任何表示的數據的實現細節是隐藏(抽象)。
封裝:是指一(yī)個概念,我(wǒ)們的所有數據和成員(yuán)函數封裝在一(yī)起,形成一(yī)個對象
構造函數:指一(yī)個特殊的函數類型可以被自動調用,構造函數的類會在每次創建新對象時先調用此方法。
析構函數:指一(yī)個特殊的函數類型可以被自動調用,會在到某個對象的所有引用都被删除或者當對象被顯式銷毀時執行。
定義的 PHP 類
在 PHP 中(zhōng)定義一(yī)個新類的一(yī)般形式如下(xià):
<?php class phpClass{ var $var1; var $var2 = "constant string"; function myfunc ($arg1, $arg2) { [..] } [..] } ?>
這是每一(yī)行的描述:
定義類形式 Class,後面是您想要定義的類的名稱。
一(yī)組花括号包含任意數量的變量聲明和函數定義。
變量聲明開(kāi)始使用 var 的特殊形式,緊随其後的是一(yī)個傳統的 $ 變量名;他們可能也有一(yī)個初始化分(fēn)配一(yī)個常量值。
函數定義看起來很像獨立的 PHP 函數,但該類和将被用于設置和訪問對象數據。
例子
這裏是一(yī)個例子定義了一(yī)個書(shū)籍類型類:
<?php class Books{ /* Member variables */ var $price; var $title; /* Member functions */ function setPrice($par){ $this->price = $par; } function getPrice(){ echo $this->price ."<br/>"; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title ." <br/>"; } } ?>
變量 $this 是一(yī)個特殊的變量,它指的是同一(yī)個對象,本身。
用 PHP 創建對象
你一(yī)旦定義好你的類,那麽您可以創建許多對象。下(xià)面是一(yī)個例子,如何使用 new 操作符創建對象。
$physics = new Books; $maths = new Books; $chemistry = new Books;
在這裏,我(wǒ)們已經創建了三個對象,這些對象是相互獨立的,他們有自己的單獨存在的空間。接下(xià)來,我(wǒ)們将看到如何訪問成員(yuán)函數和成員(yuán)變量的過程。
調用成員(yuán)函數
創建對象後,您将能夠使用相關的對象調用成員(yuán)函數。一(yī)個成員(yuán)函數将能夠處理相關對象的成員(yuán)變量。
下(xià)面的例子顯示了如何通過調用成員(yuán)函數設置标題和價格三本書(shū)。
$physics->setTitle( "Physics for High School" ); $chemistry->setTitle( "Advanced Chemistry" ); $maths->setTitle( "Algebra" ); $physics->setPrice( 10 ); $chemistry->setPrice( 15 ); $maths->setPrice( 7 );
現在你調用另一(yī)個成員(yuán)函數獲取設置在上面的例子的值:
$physics->getTitle(); $chemistry->getTitle(); $maths->getTitle(); $physics->getPrice(); $chemistry->getPrice(); $maths->getPrice();
這将會産生(shēng)以下(xià)結果:
Physics for High School Advanced Chemistry Algebra 10 15 7
構造函數
構造函數是特殊類型的函數自動創建一(yī)個對象時函數的功能會自動執行。所以我(wǒ)們充分(fēn)利用這個行爲,通過構造函數初始化很多功能。PHP 提供了一(yī)個特殊的函數叫做 __construct()
來定義一(yī)個構造函數。你可以把參數傳遞到構造函數中(zhōng)。以下(xià)示例将爲書(shū)籍類,在創建對象的時候它将創建一(yī)個構造函數用來初始化價格和标題這本書(shū)。
function __construct( $par1, $par2 ){ $this->price = $par1; $this->title = $par2; }
現在我(wǒ)們不需要調用設置好的函數分(fēn)别設置價格和标題。我(wǒ)們可以初始化這兩個成員(yuán)變量隻在創建對象的時候。檢查以下(xià)例子:
$physics = new Books( "Physics for High School", 10 ); $maths = new Books ( "Advanced Chemistry", 15 ); $chemistry = new Books ("Algebra", 7 ); /* Get those set values */ $physics->getTitle(); $chemistry->getTitle(); $maths->getTitle(); $physics->getPrice(); $chemistry->getPrice(); $maths->getPrice();
這将産生(shēng)以下(xià)結果:
Physics for High School Advanced Chemistry Algebra 10 15 7
析構函數
您可以定義析構函數:就像定義一(yī)個構造函數,析構函數使用函數__destruct()
。你可以調用一(yī)個析構函數釋放(fàng)所有資(zī)源。
繼承
PHP 類定義可以使用 extends 關鍵字繼承一(yī)個父類。語法如下(xià):
class Child extends Parent { <definition body> }
繼承的影響是子類 (或派生(shēng)類或子類)具有以下(xià)特點:
自動繼承所有父類的成員(yuán)變量聲明。
自動繼承父類的成員(yuán)函數。(默認情況下(xià))像父類一(yī)樣使用函數。以下(xià)例子書(shū)類繼承和基于需求增加了更多的功能。
class Novel extends Books{ var publisher; function setPublisher($par){ $this->publisher = $par; } function getPublisher(){ echo $this->publisher. "<br />"; } }
現在除了繼承功能,類帶了兩個額外(wài)的成員(yuán)函數。
函數重載
函數定義子類覆蓋與父類中(zhōng)相同的屬性及方法名稱。在子類中(zhōng),我(wǒ)們可以修改繼承自父類中(zhōng)的方法。
在以下(xià)示例中(zhōng) getPrice 和 getTitle 方法重載。
function getPrice(){ echo $this->price . "<br/>"; return $this->price; } function getTitle(){ echo $this->title . "<br/>"; return $this->title; }
公共成員(yuán)
除非你指定,否則類的屬性和方法默認都是公共的。也就是說,他們可能在三種可能的情況下(xià)被訪問:
從類外(wài)聲明。
在類中(zhōng)聲明。
從另一(yī)個類中(zhōng)實現的類聲明它。
直到現在我(wǒ)們看到所有成員(yuán)都作爲公共成員(yuán)。如果你想限制類的成員(yuán)的可訪問性,然後你必須定義類成員(yuán)爲 private 或者 protected。
私有成員(yuán)
通過指定一(yī)個私有成員(yuán),你可以限制其訪問對象在類外(wài)訪問它。類的私有成員(yuán)不能在繼承類中(zhōng)調用它,也不能從類外(wài)部訪問。
私有屬性或方法隻能在本類内使用:
class MyClass { private $car = "skoda"; $driver = "SRK"; function __construct($par) { // Statements here run every time // an instance of the class // is created. } function myPublicFunction() { return("I'm visible!"); } private function myPrivateFunction() { return("I'm not visible outside!"); } }
當 MyClass 類被一(yī)個類使用關鍵字 extends 繼承時,myPublicFunction() 方法在子類中(zhōng)是可用的,屬性$drive也一(yī)樣。方法 myPrivateFunction() 和屬性 $car 在子類中(zhōng)是不可以被繼承的當然也不可以用,因爲他們被聲明爲了私有的。
受保護成員(yuán)
訪問一(yī)個受保護的屬性或方法并在類中(zhōng)聲明它,以及使用關鍵字 extends 繼承該類時。保護成員(yuán)在兩種類型的類之外(wài)無法使用。一(yī)個類成員(yuán)可以使用關鍵字 protected 在其前面。
這是不同版本的 MyClass 類:
class MyClass { protected $car = "skoda"; $driver = "SRK"; function __construct($par) { // Statements here run every time // an instance of the class // is created. } function myPublicFunction() { return("I'm visible!"); } protected function myPrivateFunction() { return("I'm visible in child class!"); } }
接口
接口被開(kāi)發人員(yuán)定義爲提供一(yī)個普通的方法名。不同的開(kāi)發人員(yuán)可以根據他們不同的需求來分(fēn)别實現這些接口。你可以說,接口是根據不同的需求被開(kāi)發人員(yuán)所實現。
PHP5,可以定義一(yī)個接口,如下(xià):
interface Mail { public function sendMail(); }
然後,另一(yī)個類像這樣實現該接口:
class Report implements Mail { // sendMail() Definition goes here }
常量
一(yī)個常量有點像一(yī)個變量,它擁有一(yī)個值,但實際上更像一(yī)個函數,因爲常量是永遠不變的。一(yī)旦你聲明一(yī)個常量,它不能被改變。
聲明一(yī)個常量是很容易的,就像下(xià)面這個版本的 MyClass,它完成了常量的定義:
class MyClass { const requiredMargin = 1.7; function __construct($incomingValue) { // Statements here run every time // an instance of the class // is created. } }
在這個類中(zhōng),requiredMargin 是一(yī)個常量。它是用關鍵字 const 聲明常量,在任何情況不可以改變他的值 1.7。注意,常量的定義沒有 $ 符号,不能像變量那樣。
抽象類
抽象類不能被實例化,隻能被繼承。你用關鍵字 abstract 聲明一(yī)個抽象類,就像這樣:
當繼承一(yī)個抽象類的時候,子類必須實現抽象類中(zhōng)的所有的抽象方法,另外(wài),這些方法的可見性必須和抽象類中(zhōng)一(yī)樣(或更輕松)。
abstract class MyAbstractClass { abstract function myAbstractFunction() { } }
注意,方法定義在一(yī)個抽象類中(zhōng)在方法名稱前面之前必須使用關鍵字 abstract。抽象方法定義在一(yī)個非抽象類中(zhōng)是不合法的。
Static關鍵字
聲明類屬性或方法爲靜态,就可以不實例化類而直接訪問。靜态屬性不能通過一(yī)個類已實例化的對象來訪問(但靜态方法可以)。
試運行下(xià)面的例子:
<?php class Foo { public static $my_static = 'foo'; public function staticValue() { return self::$my_static; } } print Foo::$my_static . "\n"; $foo = new Foo(); print $foo->staticValue() . "\n";
final 關鍵字
PHP 5 介紹了這個 final 關鍵字。如果父類中(zhōng)的方法被聲明爲 final,則子類無法覆蓋該方法。如果一(yī)個類被聲明爲 final,則不能被繼承。
以下(xià)的例子會産生(shēng)一(yī)個緻命錯誤:Cannot override final method BaseClass::moreTesting()。
<?php class BaseClass { public function test() { echo "BaseClass::test() called<br>"; } final public function moreTesting() { echo "BaseClass::moreTesting() called<br>"; } } class ChildClass extends BaseClass { public function moreTesting() { echo "ChildClass::moreTesting() called<br>"; } } ?>
調用父類的構造函數
當子類需要一(yī)個構造函數時,需要調用父類的構造函數而不是在子類中(zhōng)寫一(yī)個全新的構造函數,我(wǒ)們需要調用父類的構造函數加一(yī)下(xià)我(wǒ)們要寫的内容,另外(wài)在子類的構造函數中(zhōng)做一(yī)些初始化是必要的。這是一(yī)個簡單的例子:
class Name { var $_firstName; var $_lastName; function Name($first_name, $last_name) { $this->_firstName = $first_name; $this->_lastName = $last_name; } function toString() { return($this->_lastName .", " .$this->_firstName); } } class NameSub1 extends Name { var $_middleInitial; function NameSub1($first_name, $middle_initial, $last_name) { Name::Name($first_name, $last_name); $this->_middleInitial = $middle_initial; } function toString() { return(Name::toString() . " " . $this->_middleInitial); } }
在上面這個例子中(zhōng),我(wǒ)們有一(yī)個父類(Name),它裏面有一(yī)個二個參數的構造函數,在子類中(zhōng)(NameSub1)有一(yī)個帶有 3 個參數的構造函數。子類 NameSub1 中(zhōng)的構造函數通過調用其父類中(zhōng)的構造函數 Name::Name
(傳遞兩個參數)加以使用,然後增加一(yī)個額外(wài)的屬性。同樣,NameSub1 定義了 toString() 方法然後重寫父類中(zhōng)的 toString() 方法。
注:上例中(zhōng)定義的,可以在子類中(zhōng)定義和父類中(zhōng)相同的構造函數,并且名字名稱相同。