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

php面向對象(基礎)

編輯:關於PHP編程

最近重新學習了php面向對象這一部分的知識,做了下筆記,分享給大家,其中一部分為自己的簡介,加色部分一般為自己認為比較重點或需要注意的地方,分享給大家,還希望大家多提意見共同學習。 1. 析構函數:__destruct ( ) //這是一個析構函數,在對象銷毀前調用
function __destruct()
{
echo “再見”.$this->name.”
”;
}

2. 構造函數:__construct( )

PHP子類能否繼承父類的構造方法?
如果沒有定義子類構造方法的,默認調用父類構造方法 如果定義了子類的構造方法,那麼就直接調用自身
function __construct($name, $sex, $age)
{
//通過構造方法傳進來的$name給成員屬性$this->name賦初使值
$this->name=$name;
//通過構造方法傳進來的$sex給成員屬性$this->sex賦初使值
$this->sex=$sex;
//通過構造方法傳進來的$age給成員屬性$this->age賦初使值
$this->age=$age;
}

3. __set()設置屬性 。 __get()取得屬性 class Person
{
//下面是人的成員屬性, 都是封裝的私有成員
private $name; //人的名字
private $sex; //人的性別
private $age; //人的年齡
//__get()方法用來獲取私有屬性
private function __get($property_name)
{
echo "在直接獲取私有屬性值的時候,自動調用了這個__get()方法
";
if(isset($this->$property_name))
{
return($this->$property_name); //去掉後將不能正確的給成員變量賦值
}
else
{
return(NULL);
}
}
//__set()方法用來設置私有屬性
private function __set($property_name, $value)
{
echo "在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值
";
$this->$property_name = $value;
}
}
$p1=new Person(); //直接為私有屬性賦值的操作, 會自動調用__set()方法進行賦值 $p1->name="張三"; $p1->sex="男"; $p1->age=20; //直接獲取私有屬性的值, 會自動調用__get()方法,返回成員屬性的值 echo "姓名:".$p1->name."
"; echo "性別:".$p1->sex."
"; echo "年齡:".$p1->age."
"; ?>
程序執行結果: 在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值 在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值 在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值 在直接獲取私有屬性值的時候,自動調用了這個__get()方法 姓名:張三 在直接獲取私有屬性值的時候,自動調用了這個__get()方法 性別:男 在直接獲取私有屬性值的時候,自動調用了這個__get()方法 年齡:20
以上代碼如果不加上__get()和__set()方法,程序就會出錯,因為不能在類的外部操作私有成員, 而上面的代碼是通過自動調用__get()和__set()方法來幫助我們直接存取封裝的私有成員的。


4. __isset() 方法,__unset() 方法
class Person
{
//下面是人的成員屬性
private $name; //人的名字
private $sex; //人的性別
private $age; //人的年齡
//__get()方法用來獲取私有屬性
private function __get($property_name)
{
if(isset($this->$property_name))
{
return($this->$property_name);
}else {
return(NULL);
}
}
//__set()方法用來設置私有屬性
private function __set($property_name, $value)
{
$this->$property_name = $value;
}
//__isset()方法
private function __isset($nm)
{
echo "isset()函數測定私有成員時,自動調用
";
return isset($this->$nm);
}
//__unset()方法
private function __unset($nm)
{
echo "當在類外部使用unset()函數來刪除私有成員時自動調用的
";
unset($this->$nm);
}
}
$p1=new Person();
$p1->name="this is a person name";
//在使用isset()函數測定私有成員時,自動調用__isset()方法幫我們完成,返回結果為true
echo var_dump(isset($p1->name))."
";
echo $p1->name."
";
//在使用unset()函數刪除私有成員時,自動調用__unset()方法幫我們完成,刪除name私有屬性
unset($p1->name);
//已經被刪除了, 所這行不會有輸出
echo $p1->name;
?>
輸出結果為: isset()函數測定私有成員時,自動調用 bool(true) this is a person name 當在類外部使用 unset()函數來刪除私有成員時自動調用的 __set()、__get()、__isset()、__unset() 這四個方法都是我們添加到對象裡面的,在需要時自動調 用的,來完成在對象外部對對象內部私有屬性的操作。


5. 調用父類接口
header("Content-Type: text/html; charset=utf-8");
class Person
{
//下面是人的成員屬性, 都是封裝的私有成員
private $name; //人的名字
private $sex; //人的性別
public $age; //人的年齡


function __construct($name, $sex, $age)
{
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}

function say(){
echo "我的名字叫:".$this->name."性別:".$this->sex."年齡:".$this->age;
}


}


class Student extends Person
{
var $school; //學生所在學校的屬性
function __construct($name, $sex, $age,$school)
{
parent::__construct($name,$sex,$age);
$this->school=$school;
}


//這個學生學習的方法
function study()
{
echo "我的名字叫:".$this->name." 我正在”.$this->school.”學習
";
}
//這個學性可以說話的方法, 說自己所有的屬性,覆蓋了父類的同名方法
function say()
{
//使用父類的“類名::“來調用父類中被覆蓋的方法;
// Person::say();
//或者使用“parent::”的方試來調用父類中被覆蓋的方法;


parent::say();
//加上一點自己的功能
echo "我的年齡是:".$this->age."我在".$this->school."上學.
";
}
}
$p1 = new Student("wangyaofeng","男","22","河南科技學院");
$p1->say();

?> 結果: 我的名字叫:wangyaofeng性別:男年齡:22我的年齡是:22我在河南科技學院上學


6. final 關鍵字的應用
這個關鍵字只能用來定義類和定義方法,不能使用 final 這個關鍵字來定義成員屬性,因為 final 是常量的意思,我們在 PHP 裡定義常量使用的是 define()函數,所以不能使用 final 來定義 成員屬性。 使用 final 關鍵標記的類不能被繼承; 代碼片斷 final class Person { ...... } class Student extends Person { } 會出現下面錯誤: Fatal error: Class Student may not inherit from final class (Person) 使用 final 關鍵標記的方法不能被子類覆蓋,是最終版本; 代碼片斷 class Person {
final function say()
{
}
} class Student extends Person {
function say()
{
}
} 會出現下面錯誤: Fatal error: Cannot override final method Person::say()

7.static 和 const 關鍵字的使用
Static 關鍵字是在類中描述成員屬性和成員方法是靜態的;靜態的成員好處在那裡呢?前面我們聲明了“Person”的人類,在“Person”這個類裡如果我們加上一個“人所屬國家”的屬性,這樣用“Person”這個類實例化出幾百個或者更多個實例對象,每個對象裡面就都有“所屬國家”的屬性了,如果開發的項目就是為中國人而開發的,那麼每個對象裡面就都有一個國家的屬性是“中國”其它的屬性是不同的,如果我們把“國家”的屬性做成靜態的成員,這樣國家的屬性在內存中就只有一個,而讓這幾百個或更多的對象共用這一個屬性,static 成員能夠限制外部的訪問,因為static 的成員是屬於類的,是不屬於任何對象實例,是在類第一次被加載的時候分配的空間,其他類是無法訪問的,只對類的實例共享,能一定程度對類該成員形成保護。 從內存的角度我們來分析一下,內存從邏輯上被分為四段,其中對象是放在“堆內存”裡面,對象的引用被放到了“棧內存”裡,而靜態成員則放到了“初始化靜態段”,在類第一次被加載的時候放入的,可以讓堆內存裡面的每個對象所共享,如下圖;類的靜態變量,非常類似全局變量,能夠被所有類的實例共享,類的靜態方法也是一樣的,類似於全局函數。
class Person
{
//下面是人的靜態成員屬性
public static $myCountry="中國";
// var $name; //人的名字
//這是人的靜態成員方法
public static function say()
{
echo "我是中國人
";
}
}
//輸出靜態屬性
echo Person::$myCountry;
//訪問靜態方法
Person::say();
//重新給靜態屬性賦值
Person::$myCountry="美國";
echo Person::$myCountry;
?> 因為靜態成員是在類第一次加載的時候就創建的,所以在類的外部不需要對象而使用類名就可
以訪問的到靜態的成員;上面說過,靜態成員被這個類的每個實例對象所共享,那麼我們使用對象
可不可以訪問類中的靜態成員呢?從上圖中我們可以看到,靜態的成員不是在每個對象內部存在
的,但是每個對象都可以共享,所以我們如果使用對象訪問成員的話就會出現沒有這個屬性定義,
使用對象訪問不到靜態成員的,在其它的面向對象的語言中,比如 Java 是可以使用對象的方式訪
問靜態成員的,如果 PHP 中可以使用對象訪問靜態成員的話,我們也盡量不要去使用,因為靜態的
成員我們在做項目的時候目的就是使用類名去訪問(Person::$myCountry="美國";)。
類裡面的靜態方法只能訪問類的靜態的屬性,在類裡面的靜態方法是不能訪問類的非靜態成員
的,原因很簡單,我們要想在本類的方法中訪問本類的其它成員,我們需要使用$this 這個引用,
而$this 這個引用指針是代表調用此方法的對象,我們說了靜態的方法是不用對象調用的,而是使
用類名來訪問,所以根本就沒有對象存在,也就沒有$this 這個引用了,沒有了$this 這個引用就
不能訪問類裡面的非靜態成員,又因為類裡面的靜態成員是可以不用對象來訪問的,所以類裡面的
靜態方法只能訪問類的靜態的屬性,既然$this 不存在,在靜態方法中訪其它靜態成員我們使用的
是一個特殊的類“self”;self 和$this 相似,只不過 self 是代表這個靜態方法所在的類。所以
在靜態方法裡,可以使用這個方法所在的類的“類名”
,也可以使用“self”來訪問其它靜態成員,
如果沒有特殊情況的話,我們通常使用後者,即“self::成員屬性”的方式。
代碼片斷
class Person
{
//下面是人的靜態成員屬性
public static $myCountry="中國";
//這是人的靜態成員方法, 通過self訪問其它靜態成員
public static function say()
{
echo "我是".self::$myCountry."
";
}
}
//訪問靜態方法
Person::say();
?>
在非靜態方法裡可不可以訪問靜態成員呢,當然也是可以的了,但是也不能使用“$this”引用
也要使用類名或是“self::成員屬性的形式”。

const 是一個定義常量的關鍵字,在 PHP 中定義常量使用的是“define()”這個函數, 但是在類裡面定義常量使用的是“const”這個關鍵字, 類似於 C 中的#define 如果在程序中改變了它的值,
那麼會出現錯誤,用“const”修飾的成員屬性的訪問方式和“static”修飾的成員訪問的方式差
不多,也是使用“類名”,在方法裡面使用“self”關鍵字。但是不用使用“$”符號,也不能使
用對象來訪問。
代碼片斷
class MyClass
{
//定義一個常量 constant
const constant = 'constant value';
function showConstant() {
echo self::constant . "\n"; //使用 self 訪問,不要加”$”
}
}
echo MyClass::constant . "\n"; //使用類名來訪問,也不加”$”
$class = new MyClass();
$class->showConstant();
// echo $class::constant; 是不允許的
?>

8.__toString()方法

我們前面說過在類裡面聲明“--”開始的方法名的方法(PHP 給我們提供的),都是在某一時刻
不同情況下自動調用執行的方法,“__toString()”方法也是一樣自動被調用的,是在直接輸出對
象引用時自動調用的, 前面我們講過對象引用是一個指針,比如說:“$p=new Person()”中,$p
就是一個引用,我們不能使用 echo 直接輸出$p,這樣會輸出“Catchable fatal error: Object of
class Person could not be converted to string ” 這 樣 的 錯 誤 , 如 果 你 在 類 裡 面 定 義 了
“ __toString()” 方 法 , 在 直 接 輸 出 對 象 引 用 的 時 候 , 就 不 會 產 生 錯 誤 , 而 是 自 動 調 用 了
“__toString()”方法,輸出“__toString()”方法中返回的字符,所以“__toString()”方法一
定要有個返回值(return 語句). 代碼片斷
// Declare a simple class
class TestClass
{
public $foo;
public function __construct($foo) {
$this->foo = $foo;
}
//定義一個__toString方法,返加一個成員屬性$foo
public function __toString() {
return $this->foo;
}
}
$class = new TestClass('Hello');
//直接輸出對象
echo $class;
?>
上例輸出:Hello
9.克隆對象
有的時候我們需要在一個項目裡面,使用兩個或多個一樣的對象,如果你使用“new”關鍵字
重新創建對象的話,再賦值上相同的屬性,這樣做比較煩瑣而且也容易出錯,所以要根據一個對象
完全克隆出一個一模一樣的對象,是非常有必要的,而且克隆以後,兩個對象互不干擾。
在 PHP5 中我們使用“clone”這個關鍵字克隆對象;
代碼片斷
class Person
{
//下面是人的成員屬性
var $name; //人的名字
var $sex; //人的性別
var $age; //人的年齡
//定義一個構造方法參數為屬性姓名$name、性別$sex 和年齡$age 進行賦值
function __construct($name="", $sex="", $age="")
{
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
//這個人可以說話的方法, 說出自己的屬性
function say()
{
echo "我的名字叫:".$this->name." 性別:".$this->sex." 我的年齡是:".$this->age."
";
}
}
$p1=new Person("張三", "男", 20);
//使用“clone”克隆新對象 p2,和 p1 對象具有相同的屬性和方法。
$p2=clone $p1;
$p2->say();
?>
PHP5 定義了一個特殊的方法名“__clone()”方法,是在對象克隆時自動調用的方法,用
“__clone()”方法將建立一個與原對象擁有相同屬性和方法的對象,如果想在克隆後改變原對象
的內容,需要在__clone()中重寫原本的屬性和方法,
“__clone()”方法可以沒有參數,它自動包
$this $that 兩個指針,$this 指向復本,而$that 指向原本;
代碼片斷
class Person
{
//下面是人的成員屬性
var $name; //人的名字
var $sex; //人的性別
var $age; //人的年齡
//定義一個構造方法參數為屬性姓名$name、性別$sex 和年齡$age 進行賦值
function __construct($name="", $sex="", $age="")
{
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
//這個人可以說話的方法, 說出自己的屬性
function say()
{
echo "我的名字叫:".$this->name." 性別:".$this->sex." 我的年齡是:".$this->age."
";
}
//對象克隆時自動調用的方法, 如果想在克隆後改變原對象的內容,需要在__clone()中重寫原本的屬性和方法
function __clone()
{
//$this 指的復本 p2, 而$that 是指向原本 p1,這樣就在本方法裡,改變了復本的屬性。
$this->name="我是假的$that->name";
$this->age=30;
}

}
$p1=new Person("張三", "男", 20);
$p2=clone $p1;
$p1->say();
$p2->say();
?>
上例輸出:
執行結果
我的名字叫:張三 性別:男 我的年齡是:20
我的名字叫:我是假的張三 性別:男 我的年齡是:30


10.__call 處理調用錯誤
在程序開發中,如果在使用對象調用對象內部方法時候,調用的這個方法不存在那麼程序就會
出錯,然後程序退出不能繼續執行。那麼可不可以在程序調用對象內部不存在的方法時,提示我們
調用的方法及使用的參數不存在,但程序還可以繼續執行,這個時候我們就要使用在調用不存在的
方法時自動調用的方法“__call()”。 代碼片斷
//這是一個測試的類,裡面沒有屬性和方法
class Test
{
}
//產生一個 Test 類的對象
$test=new Test();
//調用對象裡不存在的方法
$test->demo("one", "two", "three");//此方法是沒有的
//程序不會執行到這裡
echo "this is a test
";
?>
上例出現如下錯誤,程序通出不能繼續執行;
Fatal error: Call to undefined method Test::demo()
下面我們加上”__call()”方法,這個方法有 2 個參數,第一個參數為調用不存在的方法過程中,
自動調用__call()方法時,把這個不存在的方法名傳給第一個參數,第二個參數則是把這個方法的多
個參數以數組的形式傳進來。
//這是一個測試的類,裡面沒有屬性和方法
class Test
{
//調用不存的方法時自動調用的方法,第一個參數為方法名,第二個參數是數組參數
function __call($function_name, $args)
{
print "你所調用的函數:$function_name(參數:";
print_r($args);
print ")不存在!
\n";
}
}
//產生一個Test類的對象
$test=new Test();
//調用對象裡不存在的方法
$test->demo("one", "two", "three");
//程序不會退出可以執行到這裡
echo "this is a test
";
?>
上例輸出結果為:
執行結果
你所調用的函數:demo(參數:Array ( [0] => one [1] => two [2] => three ) )不存在!
this is a test.
11.抽象方法和抽象類 在 OOP 語言中,一個類可以有一個或多個子類,而每個類都有至少一個公有方法做為外部代碼
訪問其的接口。而抽象方法就是為了方便繼承而引入的,我們先來看一下抽象類和抽象方法的定義
再說明它的用途。
什麼是抽象方法?我們在類裡面定義的沒有方法體的方法就是抽象方法,
所謂的沒有方法體指的是,
在方法聲明的時候沒有大括號以及其中的內容,
而是直接在聲明時在方法名後加上分號結束,
另外在聲明抽象方法時還要加一個關鍵字“abstract”來修飾;
例如:
abstract function fun1();
abstract function fun2();
上例是就是“abstract”修飾的沒有方法體的抽象方法“fun1()”和“fun2()”
,不要忘記抽象方法後面還要有一個分號;那麼什麼是抽象類呢?只要一個類裡面有一個方法是抽象方法,那麼這
個類就要定義為抽象類,抽象類也要使用“abstract”關鍵字來修飾;在抽象類裡面可以有不是抽
象的方法和成員屬性,但只要有一個方法是抽象的方法,這個類就必須聲明為抽象類,使用
“abstract”來修飾。
例如:
代碼片斷
abstract class Demo
{
var $test;
abstract function fun1();
abstract function fun2();
function fun3()
{
....
}
}

上例中定義了一個抽象類“Demo”使用了“abstract”來修飾, 在這個類裡面定義了一個成員
屬性“$test”,和兩個抽象方法“fun1”和“fun2”還有一個非抽象的方法 fun3();那麼抽象類我
們怎麼使用呢?最重要的一點就是抽象類不能產生實例對象,所以也不能直接使用,前面我們多次
提到過類不能直接使用,我們使用的是通過類實例化出來的對象,那麼抽象類不能產生實例對象我
們聲明抽象類有什麼用呢?我們是將抽象方法是作為子類重載的模板使用的,定義抽象類就相當於
定義了一種規范,這種規范要求子類去遵守,子類繼承抽象類之後,把抽象類裡面的抽象方法按照
子類的需要實現。子類必須把父類中的抽象方法全部都實現,否則子類中還存在抽象方法,那麼子
類還是抽象類,還是不能實例化對;為什麼我們非要從抽象類中繼承呢?因為有的時候我們要實現
一些功能就必須從抽象類中繼承,否則這些功能你就實現不了,如果繼承了抽象類,就要實現類其
中的抽象方法;
代碼片斷
abstract class Demo
{
var $test;
abstract function fun1();
abstract function fun2();
function fun3()
{
....
}
}
$demo=new Demo(); //抽象類為能產生實例對象,所以這樣做是錯的,實例化對象交給子類
class Test extends Demo
{
function fun1()
{
...
}
function fun2()
{
...
}
}
$test=new Test(); //子類可以實例化對象,因為實現了父類中所有抽象方法
?> fun3可以不用再重新實現即可應用
12.php5 接口技術 PHP 與大多數面向對象編程語言一樣,不支持多重繼承.也就是說每個類只能繼承一個父類.為
了解決這個問題,PHP 引入了接口,接口的思想是指定了一個實現了該接口的類必須實現的一系列
方法。接口是一種特殊的抽象類,抽象類又是一種特殊的類,所以接口也是一種特殊的類,為什麼
說接口是一種特殊的抽象類呢?如果一個抽象類裡面的所有的方法都是抽象方法,那麼我們就換一
種聲明方法使用“接口”;也就是說接口裡面所有的方法必須都是聲明為抽象方法,另外接口裡面
不能聲明變量,而且接口裡面所有的成員都是 public 權限的。所以子類在實現的時候也一定要使
用 public 權限實限。 聲明一個類的時候我們使用的關鍵字是“class”,而接口一種特殊的類,使用的關鍵字是
“interface”;
類的定義:class 類名{ ... },接口的聲明:interface 接口名{ ... } 代碼片斷
//定義一個接口使用 interface 關鍵字,“One”為接口名稱
interface One
{
//定義一個常量
const constant = 'constant value';
//定義了一個抽象方法”fun1”
public function fun1();
//定義了抽象方法”fun2”
public function fun2();
}
?> 上例中定義了一個接口“one”,裡面聲明了兩個抽象方法“fun1”和“fun2”,因為接口裡
面所有的方法都是抽象方法,所以在聲明抽象方法的時候就不用像抽象類那樣使用“abstract”
個關鍵字了,默認的已經加上這個關鍵字,另外在接口裡邊的“public”這個訪問權限也可以去掉,
因為默認就是 public 的,因為接口裡所有成員都要是公有的,所在對於接口裡面的成員我們就不
能使用“private”的和“protected”的權限了,都要用 public 或是默認的。另外在接口裡面我
們也聲明了一個常量“constant”
,因為在接口裡面不能用變量成員,所以我們要使用 const 這個
關鍵字聲明。
因為接口是一種特殊的抽象類,裡面所有的方法都是抽象方法,所以接口也不能產生實例對象;
它也作為一種規范,所有抽象方法需要子類去實現。
我們可以使用“extends”關鍵字讓一個接口去繼承另一個接口;
代碼片斷
//使用”extends”繼承另外一個接口
interface Two extends One
{
function fun3();
function fun4();
}
?> 而我們定義一個接口的子類去實現接口中全部抽象方法使用的關鍵字是“implements”,而不
是我們前面所說的“extends”;
代碼片斷
//使用“implements”這個關鍵字去實現接口中的抽象方法
class Three implements One
{
function fun1()
{
....
}
function fun2()
{
....
}
}
//實現了全部方法,我們去可以使用子類去實例化對象了
$three=new Three();
?>
我們也可以使用抽象類,去實現接口中的部分抽象方法,但要想實例化對象,這個抽象類還要
有子類把它所有的抽象方法都實現才行;
在前面我們說過,PHP 是單繼承的,一個類只能有一父類,但是一個類可以實現多個接口,就
相當於一個類要遵守多個規范,就像我們不僅要遵守國家的法律,如果是在學校的話,還要遵守學
校的校規一樣;
代碼片斷
//使用implements實現多個接口
class Four implemtns 接口一, 接口二, ... .
{
//必須把所有接口中的方法都要實現才可以實例化對象。
}
?>
PHP 中不僅一個類可以實現多個接口,也可以在繼承一個類的同時實現多個接口, 一定要先
繼承類再去實現接口;
//使用 extends 繼承一個類,使用 implements 實現多個接口
class Four extends 類名一 implemtns 接口一, 接口二, ... .
{
//所有接口中的方法都要實現才可以實例化對象
... ... ... ..
}
?> 抽象類中允許抽象方法的存在,同時也允許非抽象方法的存在。而接口只允許抽象方法和常量存在。所以抽象方法是可以繼承與接口實現的,抽象方法中的非抽象方法通過self::方法名進行調用。 例: //抽象類繼承接口類並實現接口類的方法
abstract class Demo implements one{
var $test;
abstract function fun1();
abstract function fun2();
function fun3(){
echo "這是demo類中的fun3
";
//抽象類中方法之間的相互調用要使用self
self::fun4();
}
//將接口中的方法在抽象類中實現,也可要在具體的繼承抽象類的子類中實現
function fun4(){
echo "這是demo類中的fun4
";
}
}
//接口
interface one{
public function fun4();
}
//繼承抽象類
class Test extends Demo{
//重寫抽象類中的方法
function fun1(){
echo "這是Test類中的fun1
";
}
function fun2(){
echo "這是Test類中的fun2
";
}
//fun3若不重寫則在調用時自動調用父類中的fun3
function fun3(){
echo "hello word
";
//調用父類中的方法
parent::fun3();
}
function fun4(){
echo "hi,helllo !";


}
}
$p1 = new Test();
$p1->fun1();
$p1->fun2();
$p1->fun3();


?> 運行結果: 這是Test類中的fun1
這是Test類中的fun2
hello word
這是demo類中的fun3
這是demo類中的fun4
hi,helllo !
13.多態的應用 多態是除封裝和繼承之外的另一個面向對象的三大特性之一,我個人看來 PHP 中雖然可以實現
多態,但和 C++還有 Java 這些面向對象的語言相比,多態性並不是那麼突出,因為 PHP 本身就是一
種弱類型的語言,不存在父類對象轉化為子類對象或者是子類對象轉化為父類對象的問題,所以多
態的應用並不是那麼的明顯;所謂多態性是指一段程序能夠處理多種類型對象的能力,比如說在公
司上班,每個月財務發放工資,同一個發工資的方法,在公司內不同的員工或是不同職位的員工,
都是通過這個方法發放的,但是所發的工資都是不相同的。所以同一個發工資的方法就出現了多種
形態。對於面向對象的程序來說,多態就是把子類對象賦值給父類引用,然後調用父類的方法,去
執行子類覆蓋父類的那個方法(基類:class A{} 寄)
,但在 PHP 裡是弱類型的,對象引用都是一樣的不分父類引用,還是
子類引用。
我們現在來看一個例子,首先還是要使用多態就要有父類對象和子類對象的關系。做一個形狀
的接口或是抽象類作為父類,裡面有兩個抽象方法,一個求周長的方法,另一個是求面積的方法;
這接口的子類是多種不同的形狀,每個形狀又都有周長和面積,又因為父類是一個接口,所以子類
裡面就必須要實現父類的這兩個周長和面積的抽象方法,這樣做的目的是每種不同形狀的子類都遵
守父類接口的規范,都要有求周長和求面積的方法。 代碼片斷
//定義了一個形狀的接口,裡面有兩個抽象方法讓子類去實現
interface Shape
{
function area();
function perimeter();
}
//定義了一個矩形子類實現了形狀接口中的周長和面積
class Rect implements Shape
{
private $width;
private $height;
function __construct($width, $height)
{
$this->width=$width;
$this->height=$height;
}
function area()
{
return "矩形的面積是:".($this->width*$this->height);
}
function perimeter()
{
return "矩形的周長是:".(2*($this->width+$this->height));
}
}
//定義了一個圓形子類實現了形狀接口中的周長和面積
class Circular implements Shape
{
private $radius;
function __construct($radius)
{
$this->radius=$radius;
}
function area()
{
return "圓形的面積是:".(3.14*$this->radius*$this->radius);
}
function perimeter()
{
return "圓形的周長是:".(2*3.14*$this->radius);
}
}
//把子類矩形對象賦給形狀的一個引用
$shape=new Rect(5, 10);
echo $shape->area()."
";
echo $shape->perimeter()."
";
//把子類圓形對象賦給形狀的一個引用
$shape=new Circular(10);
echo $shape->area()."
";
echo $shape->perimeter()."
";
?>
上例執行結果:
執行結果
矩形的面積是:50
矩形的周長是:30
圓形的面積是:314
圓形的周長是:62.8
通過上例我們看到,把矩形對象和圓形對象分別賦給了變量$shape,調用$shape 引用中的面積
和周長的方法,出現了不同的結果,這就是一種多態的應用,其實在我們 PHP 這種弱類形的面向對
象的語言裡面,多態的特性並不是特別的明顯,其實就是對象類型變量的變項應用。

14.把對象串行化
有時候需要把一個對象在網絡上傳輸,為了方便傳輸,可以把整個對象轉化為二進制串,等到
達另一端時,再還原為原來的對象,這個過程稱之為串行化, 就像我們現在想把一輛汽車通過輪
船運到美國去,因為汽車的體積比較大,我們可以把汽車拆開成小的部件,然後我們把這些部件通
過輪船運到美國去,到了美國再把這些部件組裝回汽車。
有兩種情況我們必須把對象串行化,第一種情況就是把一個對象在網絡中傳輸的時候要將對象
串行化,第二種情況就是把對象寫入文件或是數據庫的時候用到串行化。
串行化有兩個過程,一個是串行化,就是把對象轉化為二進制的字符串,我們使用 serialize()
函數來串行化一個對象,另一個是反串行化,就是把對象轉化的二進制字符串再轉化為對象, 我
們使用 unserialize()函數來反串行化一個對象.
PHP 中 serialize()函數的參數為對象名,返回值為一個字符串,Serialize()返回的字符串含
義模糊,一般我們不會解析這個串來得到對象的信息,我們只要把返回來的這個字符串傳到網絡另
一端或是保存到方件中即可。
PHP 中 unserialize()函數來反串行化對象,這個函數的參數即為 serialize()函數的返回值,
輸出當然是重新組織好的對象.
class Person
{
//下面是人的成員屬性
var $name; //人的名字
var $sex; //人的性別
var $age; //人的年齡
//定義一個構造方法參數為屬性姓名$name、性別$sex 和年齡$age 進行賦值
function __construct($name="", $sex="", $age="")
{
代碼片斷
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
//這個人可以說話的方法, 說出自己的屬性
function say()
{
echo "我的名字叫:".$this->name." 性別:".$this->sex." 我的年齡是:".$this->age."
";
}
}
$p1=new Person("張三", "男", 20);
$p1_string=serialize($p1); //把一個對象串行化,返一個字符串
echo $p1_string."
"; //串行化的字符串我們通常不去解析
$p2=unserialize($p1_string); //把一個串行化的字符串反串行化形成對象$p2
$p2->say();
?> 執行結果
O:6:"Person":3:{s:4:"name";s:4:"張三";s:3:"sex";s:2:"男";s:3:"age";i:20;}
我的名字叫:張三 性別:男 我的年齡是:20
在 php5 中有兩個魔術方法__sleep()方法和__wakeup()方法,在對象串行化的時候,會調用一
個__sleep()方法來完成一些睡前的事情;而在重新醒來,即由二進制串重新組成一個對象的時候,
則會自動調用 PHP 的另一個函數__wakeup(),做一些對象醒來就要做的動作。
__sleep()函數不接受任何參數, 但返回一個數組,其中包含需要串行化的屬性。末被包含的
屬性將在串行化時被忽略,如果沒有__sleep()方法,PHP 將保存所有屬性。 代碼片斷
class Person
{
//下面是人的成員屬性
var $name; //人的名字
var $sex; //人的性別
var $age; //人的年齡
//定義一個構造方法參數為屬性姓名$name、性別$sex 和年齡$age 進行賦值
function __construct($name="", $sex="", $age="")
{
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
//這個人可以說話的方法, 說出自己的屬性
function say()
{
echo "我的名字叫:".$this->name." 性別:".$this->sex." 我的年齡是:".$this->age."
";
}
//指定串行化時把返回的數組中$name 和$age 值串行化,忽略沒在數組中的屬性$sex
function __sleep()
{
$arr=array("name", "age");
return($arr);
}

//重新生成對象時,並重新賦值$age為40
function __wakeup() {
$this->age = 40;
}
}
$p1=new Person("張三", "男", 20);
//把一個對象串行化,返一個字符串,調用了__sleep()方法,忽略沒在數組中的屬性$sex
$p1_string=serialize($p1);
echo $p1_string."
"; //串行化的字符串我們通常不去解析
$p2=unserialize($p1_string); //反串行化形成對象$p2重新賦值$age為40
$p2->say();
?>
上例輸出值為:
執行結果
O:6:"Person":2:{s:4:"name";s:4:"張三";s:3:"age";i:20;} 我的名字叫:張三 性別: 我的年齡是:40


15.自動加載類
很多開發者寫面向對象的應用程序時,對每個類的定義建立一個 PHP 源文件。一個很大的煩
惱是不得不在每個腳本(每個類一個文件)開頭寫一個長長的包含文件的列表。
在軟件開發的系統中,不可能把所有的類都寫在一個 PHP 文件中,當在一個 PHP 文件中需要調
用另一個文件中聲明的類時,就需要通過 include 把這個文件引入。不過有的時候,在文件眾多的
項目中,要一一將所需類的文件都 include 進來,是一個很讓人頭疼的事,所以我們能不能在用到
什麼類的時候,再把這個類所在的 PHP 文件導入呢?這就是我們這裡我們要講的自動加載類。
在 PHP 5 中,可以定義一個__autoload()函數,它會在試圖使用尚未被定義的類時自動調用,
通過調用此函數,腳本引擎在 PHP 出錯失敗前有了最後一個機會加載所需的類,__autoload()函
數接收的一個參數,就是你想加載的類的類名,所以你做項目時,在組織定義類的文件名時,需要
按照一定的規則,最好以類名為中心,也可以加上統一的前綴或後綴形成文件名,比如
xxx_classname.php、classname_xxx.php 以及就是 classname.php 等等。
本例嘗試分別從 MyClass1.php 和 MyClass2.php 文件中加載 MyClass1 和 MyClass2 類
代碼片斷
function __autoload($classname)
{
require_once $classname . '.php';
}
//MyClass1 類不存在自動調用__autoload()函數,傳入參數”MyClass1”
$obj = new MyClass1();
//MyClass2 類不存在自動調用__autoload()函數,傳入參數”MyClass2”
$obj2 = new MyClass2();
?>





















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