程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP基礎知識 >> php oop 小總結

php oop 小總結

編輯:PHP基礎知識
 

1.OOP思想與理論
其實我不知道在這裡提OOP思想會不會是一種再炒蛋炒飯的行為,但是還是說說自己的理解。
OOP即Object-Oriented Programming,是面向對象程序設計的意思。
如果像我一樣是學C出身的朋友,剛開始接觸的時候可能覺得有點新奇;而沒有泡在C這樣面向過程的語言經驗的朋友可能就覺得自然而然就這樣子了——這應該就是傳說中的可塑性強的意思了^_^。
OO(面向對象)的思想更接近於人類對自然界的認知——這話講得似乎很高深,其實說白了就是人們如何理解和看待事物的。比如汽車是一個類(是抽象的,現實中不存在汽車這樣的實物,存在的是汽車的各種實例),這個類的屬性有:生產日期、輪子大小等;這個類的方法有:加速、減速、鳴喇叭等;而保時捷屬於汽車這個類,是汽車這個類的一個實例——即對象,因此保時捷也具有這個類的屬性和方法;當然,勞斯萊斯也有這些屬性和方法,不過具體的細節顯然和保時捷是不一樣的。

(1)類和對象
人類是一個類,而你和我以及在看這篇文章的朋友是人類這個類的實例——即對象。我們就首先以人類為模型來學習,來看一段代碼:
<?php
// @filename oop_1.php
// @author casual0402
// @contact [email protected]

class People {
private $name;

function sayHello() {
echo "hello\n";
}
}

$man = new People ;
$man->sayHello() ;

?>
代碼首先創建一個People類,該類有姓名這個屬性,而且擁有會講hello這樣的方法;接著實例化一個對象$man,$man也一樣有姓名這個屬性和講hello這個方法;最後調用sayHello()這個方法,使用的方式是:$man->sayHello()。
到這裡,應該能很好地理解類和對象了吧^_^。

(2)繼承、重載與多態
既然是人類的正常思維,那麼繼承就更好理解,無非就是基因的遺傳嘛。
我們把中國人、美國人看做是繼承人類的兩個類。再來一段代碼:
<?php
// @filename oop_2.php
// @author casual0402
// @contact [email protected]

class People {
private $name;

function sayHello() {
echo "hello<br />";
}
}

class Chinese extends People {
function sayHello() {
echo "你好<br />";
}
}

class American extends People {
}

$cnMan = new Chinese;
$usaMan = new American;

$cnMan->sayHello();
$usaMan->sayHello();

?>
運行會發現輸出為:
你好
hello
從這個實例中我們可以看出子類American繼承了父類People的方法;當然,大家都是明白人,也知道子類Chinese也繼承了父類People的屬性和方法,但是中國人嘛,畢竟講得最多的還是中國話;在Chinese類的定義中,重寫父類中的屬性或者方法叫做重載,我們完全可以理解成遺傳變異或者叫做進化——恩,進化顯得更好點。
而中國人和美國人講"你好"的方式是不一樣的,前者用漢語表現而後者用英語表現出來——這可以比較模糊地理解為多態,說白了,就是由於環境不同而產生了不同的進化方向。

(3)更明確地認識重載和多態
其實重載是多態的一種;如何表現多態呢——當然是重寫方法嘛,這就是重載。引用上面的話:重載就是重寫父類中的屬性或者方法。而多態仍是繼承的范圍,只不過在遺傳過程中表現出不同的進化方向。比如你和你弟弟都是遺傳爸媽的,但是兩個人一般是不一樣的吧。因此多態就是同一個方法或者屬性在不同的子類下表現出不同的形態。

(4)關鍵字this、作用域符號::、構造函數__construct()以及析構函數__destruct()
首先來看this。this關鍵字是指本體,即引用當前屬性或方法的對象,比如$this->sayHello()表示引用自身的sayHello()方法,看下代碼:
<?php
// @filename oop_3.php
// @author casual0402
// @contact [email protected]

class People {
private $nationality = "noNationality";
private $name = "noName";

function sayHello() {
echo "hello<br />";
}

function setName($n) {
$this->name = $n;
}

function setNationality($n) {
$this->nationality = $n;
}

function writeName() {
echo $this->name . "<br />";
}

function writeNationality() {
echo $this->nationality . "<br/>";
}
}

class Chinese extends People {
function sayHello() {
echo "你好<br />";
}
}

class American extends People {
}

$cnMan = new Chinese;
$usaMan = new American;

$cnMan->setName("菜籃子");
$cnMan->setNationality("中國");

$cnMan->sayHello();
$cnMan->writeName();
$cnMan->writeNationality();

?>
輸出為:
你好
菜籃子
中國
接著我們在American類中寫上構造函數和析構函數,並用上作用域符號:
<?php
// @filename oop_4.php
// @author casual0402
// @contact [email protected]

class People {
private $nationality = "noNationality";
private $name = "noName";

function sayHello() {
echo "hello<br />";
}

function setName($n) {
$this->name = $n;
}

function setNationality($n) {
$this->nationality = $n;
}

function writeName() {
echo $this->name . "<br />";
}

function writeNationality() {
echo $this->nationality . "<br/>";
}
}

class Chinese extends People {
function sayHello() {
echo "你好<br />";
}
}

class American extends People {
function sayHelloInChinese() {
echo "I can say hello in Chinese , you see , ";
Chinese::sayHello();
}

function __construct() {
echo "一個American類的實例被創建了<br />";
}

function __destruct() {
echo "一個American類的實例被撤銷了<br />";
}
}

$cnMan = new Chinese;
$usaMan = new American;

$cnMan->setName("菜籃子");
$cnMan->setNationality("中國");

$cnMan->sayHello();
$cnMan->writeName();
$cnMan->writeNationality();

$usaMan->sayHelloInChinese();

?>
輸出為:
一個American類的實例被創建了
你好
菜籃子
中國
I can say hello in Chinese , you see , 你好
一個American類的實例被撤銷了
因此我們可以了解到__construct()函數在一個對象實例化的時候調用,而__destruct()函數在一個對象被撤銷時調用——我們應該知道PHP5會自動回收資源,不必像C一樣用上free();而作用域符號::指定調用哪個類中的屬性或者方法。

(5)訪問控制:public protected private
引用php.net的一段話:“對屬性或方法的訪問控制,是通過在前面添加關鍵字 public、protected 或 private 來實現的。由 public 所定義的類成員可以在任何地方被訪問;由 protected 所定義的類成員則可以被其所在類的子類和父類訪問(當然,該成員所在的類也可以訪問);而由 private 定義的類成員則只能被其所在類訪問。 ”
而且,方法如果沒有指定關鍵字,默認為public。下見一段代碼了解:
<?php
// @filename oop_5.php
// @author casual0402
// @contact [email protected]

class People {
private $name;
protected $nationality;
public $sex;

function sayHello() {
echo "hello<br />";
}
}

$man = new People ;
$man->sayHello() ;
$man->sex = "男";
echo $man->sex;
$man->nationality = "中國";
echo $man->nationlity;

?>
輸出為:
hello

Fatal error: Cannot access protected property People::$nationality ……
這說明了由 protected 所定義的類成員則可以被其所在類的子類和父類訪問,但是不能被對象訪問。當然,private限制得更多了,只能類本身訪問。我們改進oop_5.php進一步了解訪問控制:
<?php
// @filename oop_5.php
// @author casual0402
// @contact [email protected]

class People {
private $name;
protected $nationality;
public $sex;

function sayHello() {
echo "hello<br />";
}

function setName($n) {
$this->name = $n;
}

function setNationality($n) {
$this->nationality = $n;
}

function writeName() {
echo $this->name . "<br />";
}

function writeNationality() {
echo $this->nationality . "<br />";
}
}

$man = new People ;
$man->sayHello() ;
$man->sex = "男";
echo $man->sex . "<br />";

class Chinese extends People {
protected $nationality = "中國";

function emigrate($n) {
$this->nationality = $n;
}
}

$cnMan = new Chinese;

$cnMan->setName("菜籃子");
$cnMan->setNationality("中國");

$cnMan->sayHello();
$cnMan->writeName();
$cnMan->writeNationality();
$cnMan->emigrate("美國");
$cnMan->writeNationality();

?>
輸出為:
hello

hello
菜籃子
中國
美國
如果在最後加上一句:$cnMan->nationality = "菲律賓";則會出現錯誤:Fatal error: Cannot access protected property Chinese::$nationality in……
訪問控制是為了實現信息的隱藏——即所謂的封裝性。就好比你只要知道踩油門就可以加速而不必知道具體的工作原理,這就是封裝了^_^。

(6)final static clone
final顧名思義就是最後的,指定某個方法不能重載或者某個類不能被繼承。
static是指定靜態方法或者變量的關鍵字。靜態方法可以無需實例化類就可以使用,即用類名和作用域符號結合使用,而靜態變量不止如此,它還在類的作用范圍有“存儲”功能,並且對象不能直接訪問:
<?php
// @filename oop_6.php
// @author casual0402
// @contact [email protected]

class test1 {
static $num1 = 1;
function addNum1() {
echo self::$num1 . "<br />";
self::$num1++;
}
}

class test2 extends test1 {
function writeParentNum() {
echo parent::$num1 . "<br />";
parent::$num1++;
}
}

echo test1::addNum1(); //輸出1

$a = new test1;
$a->addNum1(); //輸出2

$b = new test1;
echo $b->num1 . "<br />"; //不輸出

echo test1::addNum1(); //輸出3

test2::addNum1(); //輸出4

$c = new test2;
$c->writeParentNum(); //輸出5

echo 'the end';

?>
輸出為:
1
2

3
4
5
the end
而第三個是clone,用法為$obj1 = clone $obj2;即復制$obj2所有屬性和方法到$obj1——純粹只是復制屬性和方法而已,而二者的內存指向是不一樣的,與$obj1 = $obj2是不同的,詳細了解見下面代碼:
<?php

class SubObject
{
static $instances = 0; //靜態變量
public $instance;

public function __construct() { //構造函數
$this->instance = ++self::$instances;
}

public function __clone() { //當使用clone關鍵字時,會首先嘗試尋找調用已定義的__clone()函數
//而且__clone()函數不能直接不調用
$this->instance = ++self::$instances;
}
}

class MyCloneable
{
public $object1;
public $object2;

function __clone()
{
// Force a copy of this->object, otherwise
// it will point to same object.
$this->object1 = clone $this->object1;
}
}

$obj = new MyCloneable();

$obj->object1 = new SubObject(); //這裡會調用構造函數,靜態變量增1,為1
//即$obj->object1的屬性:$instance = 1; $instances = 1;
$obj->object2 = new SubObject(); //這裡會調用構造函數,靜態變量再增1,為2
//即$obj->object2的屬性:$instance = 2; $instances = 2;
$obj2 = clone $obj; //這裡會調用MyCloneable類中__clone()函數
//執行$this->object1 = clone $this->object1;(其中僅有$obj2->object1克隆了$obj->object1;)
//因此,$obj2->object1新開辟了一個內存空間,並且克隆了$obj->object1的所有屬性
//可知 $obj2->object1->instance=1;$obj2->object1->instances=2;
//並且由於再度出現clone關鍵字,所以調用SubObject類中__clone()函數
//所以在這裡執行了$this->instance = ++self::$instances;
//因此得到$obj2->object1->instance=3;
//而另外進行的是:$obj2->object2 = $obj->object2
//這樣的環境我總是喜歡C語言中的解釋:$obj2->object2 與 $obj->object2指向的是同一內存地址
//所以$obj2->object2 與 $obj->object2指向的是同一片內存空間,即二者的本質是一樣的
//因此可知,$obj2->object2->instance=2;因為並沒有使用clone關鍵字,所以沒有調用__clone()函數


print("Original Object:<br />");
print_r($obj);
echo '<br />';

print("Cloned Object:<br />");
print_r($obj2);
echo '<br />';

?>
輸出如下:
Original Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)

[object2] => SubObject Object
(
[instance] => 2
)

)
Cloned Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)

[object2] => SubObject Object
(
[instance] => 2
)

)


(7)抽象方法、抽象類以及接口
我根據php.net裡Class Abstraction的內容直接翻譯過來並摘要得:
1.抽象類不能被實例化,只能被繼承再實例化。
2.只要含有抽象函數則該類必須為抽象類。
3.集成抽象類後,對於抽象函數的具體實現時要注意訪問控制只能更松散而不能更嚴格,比如原來是protected關鍵字,實現時只能是protected或者public,而不能是private。
而關於接口,我也是直接根據php.net裡的Object Interfaces的內容直接翻譯:
1.接口允許用戶指定一些某個類要實現的函數;
2.接口用interface關鍵字定義,但是接口內的函數不能有實際內容;
3.接口內所有函數必須指定為public,這是接口的本質;
4.類用implements關鍵字實現接口,如class Template implements iTemplate{}或者class Template implements iTemplate1,iTemplate2{};
5.實現多個接口的時候,各個接口內不能有重名屬性或者含義,否則會有歧義;
6.一個類實現接口時必須具體化每個接口內指定的函數。
這樣我們會發現當抽象類中所有函數都沒有具體操作句柄的時候,就幾乎為接口了^_^。
進一步學習請參考:
http://docs.php.net/manual/zh/language.oop5.abstract.php
http://docs.php.net/manual/zh/language.oop5.interfaces.php

(8)__autoload()
直接參考php.net的經典代碼:
<?php
function __autoload($class_name) {
require_once $class_name . '.php';
}

$obj = new MyClass1();
$obj2 = new MyClass2();
?>
^_^自動加載函數__autoload()的作用是實例化一個對象時,如果當前文件內沒有指定類則調用__autoload()。比如我們經常把某個類單獨存為一個文件*.class.php,那麼就可以用到了。

當然,OOP不僅僅是這些的,想要深入學習還得靠自己。 ^_^
接下來將會分享幾個OOP實例,敬請期待,謝謝。


實例篇:

<?php
// @filename dbConnect.class.php
// @author casual0402
// @contact [email protected]

class dbConnect {
private $dbhost;
private $dbuser;
private $dbpwd;
private $dbname;
public $link;
public $query;

function __construct($h,$u,$p,$n) {
$this->dbhost = $h;
$this->dbuser = $u;
$this->dbpwd = $p;
$this->dbname = $n;
}

function __destruct() {
mysql_close($this->link);
}

public function createCon() {
$this->link = mysql_connect($this->dbhost,$this->dbuser,$this->dbpwd);
mysql_select_db($this->dbname,$this->link);
mysql_query("set names utf8");
}
}
 

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved