一:結構和調用(實例化):php
class className{} ,調用:$obj = new className();當類有構造函數時,還應傳入參數。如$obj = new className($v,$v2…);數組
二:構造函數和析構函數:函數
一、構造函數用於初始化:使用__construct(),可帶參數。ui
二、但析構函數不能帶參數(用於在銷去一個類以前執行一些操做或功能)。析構函數用__destruct()作名稱。在腳本執行結束時,會銷掉內存中的對象,所以可不用析造函數,但有些好比COOKIE等,就應當要用此函數銷掉。this
知識點:在PHP4中也提供了構造函數,但使用的是與類同名的類方法,在PHP5仍能兼容這種作法,當一個類中沒有包含__construct時,會查找與類同名的方法,若是找到,就認爲是構造函數,以下:spa
三、PHP不會自動調用父類的構造函數(不支持構造函數重載),必須使用parent關鍵字顯式地調用。code
固然也能夠調用與該實例沒有任何關係的其它類的構造函數。只需在__construct()前加上類名便可。如:
otherClassName::__construct();對象
類的主家庭成員:屬性、方法、常量、靜態成員繼承
3、類的屬性:
有兩種方法對類的屬性賦值或取值。
一、使用公共做用域public關鍵詞。
二、使用__set()和__get()來分別賦值和取值,前者稱爲設置方法(setter)或修改方法(mutator),後者稱爲訪問方法(accessor)或獲取方法(getter)。建議使用這種方法:優勢:
A、可在__set()統一進行數據驗證。
B、便於統一管理屬性。接口
注意:
第一:__set()和__get()只對私有屬性起做用,對於用public定義的屬性,它們兩個都懶理搭理,以下:
實例只對$a,$b,$c的設置會通過__set和__get過濾與返回,對於$d,就不會起做用。如$a->d=5,再返回仍是5。
第二:__set($n,$v)要帶兩個參數。而__get($n)只能有一個參數。實例:
類的屬性可自由擴展,如上例的k,無論是否用__set,當一個實例創建起來後,能夠用$e->newProperty = xx;直接來創造一個屬性,但不建議這麼作。
4、類的方法:
理解成類當中的函數便可。
調用:
一、內部調用:可以使用$this->Fanname();或$this->addab()或test::addab();
二、實例化調用時,用$e->addab();便可。對於在該方法中沒有使用$this關鍵字的,如上例中的:
function addab() { return $this->a+$this->b; }
改成: function addab() { return 25; }那在在外部實例調用該方法,也可用「$e::addab();」或「test::addab();」
5、類的常量:
若是類的屬性理解成類中的變量,那麼類的常量和變量是不同的,其定義方法爲:
常量只能用雙冒號::來調用。而且不能更改其值。
在類外部實例化後調用類常量一樣也有兩種方法。方法爲:
「$e::PI」 或 「test::PI」,共同點是都要用冒號,不一樣點是外部不能用this關鍵字,只能用實例名,但類名::PI是通用的。
6、類的靜態成員(靜態屬性或靜態方法):
若是須要建立供全部類的實例共享的字段或方法。就得用靜態成員。有兩個特徵:
一、靜態成員是共產主義者,它讓腳本上的全部該類的實例調用,但不能借助類的特定實例名調用,而是在類的外部,統一使用「類名::$成員名」的方式調用。而類的內部則統一使用 「self::$成員名」來調用。
二、當每一次新建立實例時,靜態成員會從上次建立的實例最後值開始從新計算,而不是類中初始的值開始計算。
三、對於用public定義的靜態成員,能夠在外部更改它的值。private等則不行。
7、關鍵字:
(一)this關鍵字:用於類的內部指代類的自己。來訪問屬性或方法或常量,如$this->屬性名或方法名。$this::常量名。this還能夠用在該類的子類中,來指代自己的屬性或方法。
(二)雙冒號「::」關鍵字:用於調用常量、靜態成員。
(三)self關鍵字:在類的內部與雙冒號配合調用靜態成員,如 self::$staticVar.,在類的內部,不能用$this來調用靜態成員。
(四)__toString():在類中使用__toString(),用於將類轉成字串並打印類,用處不大:如:
(五)__clone() :當克隆對象時,這個關鍵字纔會發生做用,用於更改克隆時某些值。
(六)__call():方法重載,參下面示例:
$x='a';
$y=array(‘a','b');
$b=new cB;
$b->showVarType($x); //不是數組也不是數字
$b->showVarType($y); //這是數組
注意,不能在類中定義showVarType()方法,不然代碼不能用。
(七)extends:繼承: 如class a{} class b extends a{} 類b繼承了類a
附:記憶:之後統一在調用方法或屬性時用 「-> 「,調用常量則用雙冒號「::」,不會搞暈。
8、方法和屬性的做用域:
共有6種:public(默認,可省略,也等同於php6的var聲明),private(私有,也不能由子類使用),protected(私有, 但可由子類使用) ,abstract(抽象,參下文),final(阻止在子類中覆蓋—也稱重載,阻止被繼承,用於修飾類名及方法,如final class test{ final function fun(){}} ,但不能用於屬性),static(靜態)
九:抽象類和抽象方法(abstract——注意:沒有所謂抽象屬性):
抽象能夠理解成父類爲子類定義了一個模板或基類。做用域abstract只在父類中聲明,但在子類中實現。注意事項:
一、抽象類不能被實例化,只能被子類(具體類)繼承後實現。
二、抽象類必須在其子類中實現該抽象類的全部抽象方法。不然會出錯。
三、在抽象方法中,只是聲明,但不能具體實現:如abstract function gettow(){ return $this->p; }是錯的,只能聲明這個方法:abstract function gettow();(連方括號{}都不要出現),抽象方法和抽象類主要用於複雜的類層次關係中。該層次關係須要確保每個子類都包含並重載了某些特定的方 法。這也能夠經過接口實現
四、屬性不能被命名爲抽象屬性,如abstract $p = 5是錯的。
五、只有聲明爲抽象的類能夠聲明抽象方法,但若是方法聲明爲抽象,就不能具體實現。如:
之後再對這個父類擴展,組成各類子類(如經理,員工,出納)。
六、抽象類中,若是要實現具體的方法,不能聲明爲抽象。這樣可能實際意義更大。能夠把幾個類庫中共同的部分提取到抽象類中,其它的類繼承抽象類便可。以下:
十:類型提示:
注 意,類型提示功能只能用於參數爲對象的提示,而沒法用於爲整數,字串,浮點等類型提示。有些類的方法須要傳入的參數爲所指望的對象類型,能夠用下面的方法 達到強制實施此替則。要達到類型提示,只要在方法的對象型參數前加一個已存在的類的名稱,如:function funname(OtherClassName $otherclassINSName,$c….),注意,OtherClassName必須是存在的類。以下:
function addab(em $j,$c) //這個方法,便可以在內部調用,也能夠在外部調用。只要做用域許可。
{ return $j->k+$c; }
}
$a = new test();
$b = new em();
echo $a->addab($b,2); //或 $a->addab(new em(),2);
11、類的管理:
一、instanceof關鍵字:用於分析一個對象是不是某一個類的實例或子類或是實現了某個特定的接口:以下例,但要注意: 類名沒有任何引號等定界符,不然會出錯。如test不能用'test'
二、肯定類是否存在:boolean class_exists(string class_name): class_exists(‘test');
三、返回類名:string get_class(object),成功時返回實例的類名,失敗則返回FALSE:
$a = new test2(); echo get_class($a); //返回 test2
四、瞭解類的公用屬性:array get_class_vars(‘className') ,返回關鍵數組:包含全部定義的public屬性名及其相應的值。這個函數不能用實例名作變量
五、返回類方法:get_class_methods(‘test'); //或: get_class_methods($a);可用實例名作參數,返回包括構造函數在內的全部非私有方法。
六、print_r(get_declared_classes())瞭解當前PHP版本中全部的類名。PHP5有149個。
七、get_object_vars($a)返回實例中全部公用的屬性及其值的關聯數組。注意它和get_class_vars()的區別:
/* (1) get_object_vars($a)是用實例名作參數,而get_class_vars(‘test')是用類名作參數。
* (2) get_object_vars($a)得到的屬性值是實例運行後的值,而get_class_vars(‘test')得到的屬性值是類中的初始定義。
* (3) 二者均返回關聯數組,且均對未賦值的屬性返回NULL的值。如類test中有定義了public $q;則返回Array ( [v] => 5 [q]=>) ,
*/
八、返回父類的名稱:get_parent_class($b);//或get_parent_class(‘test2′); 返回test
九、肯定接口是否存在:boolean interface_exists($string interface[,boolean autoload])
十、肯定對象類型: boolean is_a($obj,'className'),當$obj屬於CLASSNAME類時,或屬於其子類時,返回TRUE,若是$obj與class類型無關則返回FALSE。如:is_a($a,'test')
十一、肯定是不是某類的子對象:當$b是繼承自TEST類時,返回TRUE,不然FALSE。boolean is_subclass_of($b,'test');
十二、肯定類或實例中,是否存在某方法。method_exists($a,'getv') //或用method_exists(‘test','getv'),此函數適用於非public定義的做用域的方法。
以上函數實例:
$a=new test();
$b=new test2();
print_r( get_class_methods(‘test')); //或:print_r( get_class_methods($a)); 均返回:Array ( [0] => __construct [1] => getv )
echo ‘<br />';
print_r( get_class_vars(‘test')); //返回:Array ( [v] => 2 ),和上面不同,不能用print_r( get_class_methods($a));
echo ‘<br />';
echo get_parent_class($b);//或get_parent_class(‘test2′); 返回test
echo ‘<br />';
echo is_a($b,'test');// 返回1
echo ‘<br />';
if(is_subclass_of(‘test2′,'test'))echo ‘是子類!'; //或(is_subclass_of($b,'test')),返回1,當參數1爲$a時則返回false,
echo ‘<br />';
echo method_exists($a,'getv') //或用method_exists(‘test','getv')返回1,本函數也適用於用private等定義域的方法。
11、自動加載類庫文件:
當類多了之後,好比要在一個文件中載入3個類庫文件:a.class.php,b.class.php,c.class.php要用三個require_once(‘classes/a.class.php);
require_once(‘classes/b.class.php);
require_once(‘classes/c.class.php);
能夠用PHP5自動加載的功能來處理:在全局應用配置文件中,定義一個特殊的函數__autoload($class)函數(__autoload並非一個類的方法,只是單獨的函數,和類沒有關係):
function __autoload($class){
require_once(「classes/$class)
}
該函數放哪沒有關係,在建立類實例時,也沒必要去調用這個autoload函數。PHP會自動完成。但務必注意一點:「在調用頁面上建立實例所使用的 類名稱」、和「被調用的文件名」、以及「該文件中的類的名稱」3個必須是同樣的。這樣就不須要去調用__autoload();若是不同則必須單獨調用 __autoload(‘c');並給它一個文件名前綴。如:
c.class.php文件的代碼是:
這裏代碼的類名稱是c,而文件名也是c,
如今要在index.php調用:
$m = new c(); //建立實例調用的類也是c
echo $m->m;
?>
此時PHP會自動調用根目錄下的c.class.php中的類C。
但若是c.class.php中的代碼是:
而調用頁index.php代碼是:
會出錯,提示找不到mm.class.php文件。這時能夠加一行__autoload(‘c');但這樣就達不到簡化代碼的目的。
類的家族化擴展:類的高級功能:
1、對象克隆:
當克隆一個對象的實例時,其屬性初始值繼承了被克隆對象的當前值。
2、對象繼承:
沒有被聲明爲final的類能夠被繼承,沒有被final和private界定的方法也能夠繼承,沒有被private界定的屬性也能夠繼承。當子類繼承了父類或超類後,能夠直接使用父類或超類(祖父類以及祖父的祖父)的全部容許的方法,屬性。
關鍵:理解構造函數和重載在繼承中的特性!
(一)構造函數在繼承中的特性:
一、當父類有構造函數而子類沒有:則子類會在實例化時會自動執行父類的構造函數。這時若是要建立子類的實例,須要引入父類構造函數中所需的參數,否 則出錯。即便是「子類的子類」若是沒有構造函數,也要在建立實例時輸入其父類的父類的構造函數所需參數。PHP會從實例所在的子類會向上搜索合造的構造函 數,一旦找到就中止,使用該構造函數。而不會再向上搜索,所以:子類自己若是沒有構造函數,則以其最靠近的一個超類而且有構造函數的爲準。
class cB extends cA{
function funB1() { echo ‘<h3>Class cB execute success!</h3>'; }
}
class cC extends cB {
function funC1() { echo ‘<h3>Class cC FunC1!</h3>'; }
}
$b=new cB(‘Jack');
$b->name='John';
echo 「$b->name : $b->age」;
$b->funB1();
$c=new cC(); //這裏會出錯,因爲cB也沒有構造函數,所以再向上以cA爲準,須要一個參數。改成$c=new cC(‘David');便可。
echo $c->name(); //David
二、當子類也有構造函數時:這時,無論父類是否有構造函數,都會執行子類本身的構造函數。
如上:
現 在類CB有本身的構造函數時,這時建立實例$b=new cB(‘Jack');參數JACK不會起做用,由於父類CA的構造函數沒有獲得執行。所以$b->name和$->age就不會初始化值。 須要另外賦值$b->name='Jack',$b->age=25;
若是這時要執行父類CA的構造函數,能夠這樣:
由 於parent::__construct($n); 只會向上搜索父類的構造函數,一找到就中止且執行當前找到的構造函數,所以在上面例子中,若是parent::__construct($n)是用在最後 一層的類cC中,而且類CB,CA都有構造函數,那麼cC的實例只會執行cB的構造函數。不會執行cA。這時,若是CC的實例想都調用CA和CB的構造函 數,有兩種方法:
A、在CB中也加入parent::__construct($n)
B、在CC中把構造函數改成:
(二)在子類中調用父類的屬性或方法:
一、調用父類方法:在子類中調用父類的方法,有3種方法:
$this->ParentFunction(); 或
父類名::ParentFunction(); 或
parent::parentFun();
二、調用父類屬性:只能用$this->ParentProperty;
(三)重載:
在子類中,能夠定義與父類相同屬性或方法,改變父類該屬性或方法的值或操做,稱作重載。如:
calss ParClass{ function pfun(){ ….}}
class ChildrenClass extends ParClass{function pfun(){ ….}}} //重載了父類的pfun的方法。
在子類中重載後,優先執行本身重載後的新定義的方法或屬性。
也能夠在子類中用parent::parentFun();調用父類的方法,但所獲得的值是子類本身輸入的參數運算值。而不是該方法在父類中運算的值。
3、接口:
接口:interface,能夠理解成一組功能的共同規範,最大意義可能就是在多人協做時,爲各自的開發規定一個共同的方法名稱。
和抽象類中的抽象方法同樣:
一、不能在接口中對方法具體實現進行定義。而是由具體類來實現(而抽象類中的非抽象方法能夠沒必要再定義,只有抽象方法和接口是同樣要求要在具體類中實現)。
二、和抽象類同樣,能夠在接口中定義常量,並由具體類直接繼承。
三、具體類必須實現抽象類的全部抽象方法(非抽象方法除外),一樣,具體類如經過implements實現了接口後,必須完成接口中的全部方法。
接口實現過程:一、定義接口,二、用..implement X,Y,…和具體類對接。
class age implements Info //如要多個接口 class age (extends emJob) implements Info,interB…
{
public $age=15;
public $name='Join';
function getage() {
echo 「年級是$this->age」;
}
function getname() {
echo 「姓名是$this->name」;
}
function getN(){
echo ‘<h3>在接口中定義的常量N的值是:'.$this::N.' </h3>'; //直接繼承接口中的常量值。
}
}
$age=new age;
echo $age::N; //22,直接調用接口中的常量值。
$age->getN();
關於抽象類和接口類的使用區分:什麼時候用接口,什麼時候用抽象?
一、相關性:當建立的模型由一些緊密相關的對象採用時,用抽象。對於不相關對象採用的功能,用接口。
二、多重繼承:PHP類能夠繼承多個接口,但不能擴展多個抽象類。
三、公共行爲實現:抽象類可在其中實現公共的方法,但接口不行。
4、命名空間(PHP6)
類庫腳本A.inc.php和腳本B.inc.php中都一個類的名稱爲 class CNAME,而且這兩個文件要在同一個文件如index.php中被調用。這時要用到命名空間。
步聚:
一、打開上面的A和B兩個文件,分別在上面的最前面各加一行:
namespace SPACEA; 和 namespace SPACEB; 名字自定。
二、在index.php中實例化類時,在類的前面添加命名空間和雙冒號作爲前綴:
include ‘a.inc.php';
include ‘b.inc.php';
$a=new SPACEA::CNAME();
$b=new SPACEB::CNAME();
這樣就不會衝突了。
但在PHP6正式發佈前,這個功能還未定下來。
5、實現迭代器和迭代。
參《PHP聖經》P142;
6、使用Reflection(反射)API 。簡易實例:class a{ …. }$c = new ReflectionClass(‘a'); //PHP 內置類。echo ‘<pre>'.$c.'</pre>';輸出類a的結構和內容。參《PHP聖經》P145;