一:結構和調用(實例化):
class className{} ,調用:$obj = new className();當類有構造函數時,還應傳入參數。如$obj = new className($v,$v2...);
二:構造函數和析構函數:
1、構造函數用於初始化:使用__construct(),可帶參數。
2、但析構函數不能帶參數(用於在銷去一個類之前執行一些操作或功能)。析構函數用__destruct()做名稱。在腳本執行結束時,PHP會銷掉內存中的對象,因此可不用析造函數,但有些比如COOKIE等,就應當要用此函數銷掉。
知識點:在PHP4中也提供了構造函數,但使用的是與類同名的類方法,在PHP5仍能兼容這種做法,當一個類中沒有包含__construct時,會查找與類同名的方法,如果找到,就認為是構造函數,如下:
class test
{ var $b;
function test() { $this->b=5; }
function addab($c) { return $this->b+$c; }
}
$a = new test(); echo $a->addab(4); // 返回 9
3、PHP不會自動調用父類的構造函數(不支持構造函數重載),必須使用parent關鍵字顯式地調用。
class employee{
function __construct()....
}
class Manager extents Employee{
function __construct(){
parent::_construct();
echo '這個子類的父類構造函數調用了!';
}
}
當然也可以調用與該實例沒有任何關系的其它類的構造函數。只需在__construct()前加上類名即可。如:
otherClassName::__construct();
類的主家庭成員:屬性、方法、常量、靜態成員
三、類的屬性:
有兩種方法對類的屬性賦值或取值。
1、使用公共作用域public關鍵詞。
2、使用__set()和__get()來分別賦值和取值,前者稱為設置方法(setter)或修改方法(mutator),後者稱為訪問方法(accessor)或獲取方法(getter)。建議使用這種方法:優點:
A、可在__set()統一進行數據驗證。
B、便於統一管理屬性。
注意:
第一:__set()和__get()只對私有屬性起作用,對於用public定義的屬性,它們兩個都懶理搭理,如下:
class test{
protected $a=9,$b=2,$c;
public $d;
function __set($n,$v) { $this->$n = $v+2; }
function __get($name) { return $this->$name+2; }
}
$a = new test();
$a->b =5; echo "<br />"; echo $a->b;
實例只對$a,$b,$c的設置會經過__set和__get過濾與返回,對於$d,就不會起作用。如$a->d=5,再返回還是5。
第二:__set($n,$v)要帶兩個參數。而__get($n)只能有一個參數。實例:
class test{
private $a=5,$b=6,$c;
function __set($n,$v)
{
if($n=='a'&&$n>0)
$this->$n = $v;
else
$this->$n = $v+2;
}
function __get($name)
{
return $this->$name; //如果改為return $this->$name + $this->addab(); 如調用a的值,實際返回的是a+a+b的值。默認為5+5+6=16。
}
function addab()
{ return $this->a + $this->b; }
}
$e=new test();
$e->a = 11; //注意寫法:類的內部用$this->$n即變量的寫法,但外部實例要用$e->a的方式。
$e->b = 12; //get 14
$e->k = 22;
類的屬性可自由擴展,如上例的k,不管是否用__set,當一個實例建立起來後,可以用$e->newProperty = xx;直接來創造一個屬性,但不建議這麼做。
四、類的方法:
理解成類當中的函數即可。
調用:
1、內部調用:可使用$this->Fanname();或$this->addab()或test::addab();
2、實例化調用時,用$e->addab();即可。對於在該方法中沒有使用$this關鍵字的,如上例中的:
function addab() { return $this->a+$this->b; }
改為: function addab() { return 25; }那在在外部實例調用該方法,也可用“$e::addab();”或“test::addab();”
五、類的常量:
如果類的屬性理解成類中的變量,那麼類的常量和變量是不一樣的,其定義方法為:
class test{
private $a;
const PI = '3.14';
.....
//在類中調用上面的常量用兩種方法,“$this::PI”,或 “類名::PI”,這裡就是test::PI,如下:
function getvalue(){
return $this->a * $this::PI; //或$this->a * test::PI,用this關鍵字或類名均可,但都要用雙冒號。
}
}
$e= new test();
$e->PI =5; //注意,這裡用 ->只是創造了一個也是名為PI的屬性,而不是改變類中的PI常量的值。
echo $e::PI; //這個才是調用類的常量。
常量只能用雙冒號::來調用。並且不能更改其值。
在類外部實例化後調用類常量同樣也有兩種方法。方法為:
“$e::PI” 或 “test::PI”,共同點是都要用冒號,不同點是外部不能用this關鍵字,只能用實例名,但類名::PI是通用的。
六、類的靜態成員(靜態屬性或靜態方法):
如果需要創建供所有類的實例共享的字段或方法。就得用靜態成員。有兩個特征:
1、靜態成員是共產主義者,它讓腳本上的所有該類的實例調用,但不能借助類的特定實例名調用,而是在類的外部,統一使用“類名::$成員名”的方式調用。而類的內部則統一使用 “self::$成員名”來調用。
2、當每一次新創建實例時,靜態成員會從上次創建的實例最後值開始重新計算,而不是類中初始的值開始計算。
3、對於用public定義的靜態成員,可以在外部更改它的值。private等則不行。
class test{
public static $v = 0;
function __construct(){ self::$v++; }
static function getV(){ return self::$v; }
}
$a = new test();
echo test::getV(); // 返回 1
$b = new test();
echo test::getV(); // 返回 2
test::$v=8; //由於public定義的成員,改變靜態成員的值。
$c = new test();
echo test::getV(); // 返回 9
七、關鍵字:
(一)this關鍵字:用於類的內部指代類的本身。來訪問屬性或方法或常量,如$this->屬性名或方法名。$this::常量名。this還可以用在該類的子類中,來指代本身的屬性或方法。
(二)雙冒號“::”關鍵字:用於調用常量、靜態成員。
(三)self關鍵字:在類的內部與雙冒號配合調用靜態成員,如 self::$staticVar.,在類的內部,不能用$this來調用靜態成員。
(四)__toString():在類中使用__toString(),用於將類轉成字串並打印類,用處不大:如:
class test{ public $p;
public function __toString(){ return var_export($this,TRUE); }
}
$a=new test();
echo $a; //輸出:test::__set_state(array( 'p' => NULL, )),或寫成:echo $a->__toString();
(五)__clone() :當克隆對象時,這個關鍵字才會發生作用,用於更改克隆時某些值。
(六)__call():方法重載,參下面示例:
class cB{
function __call($method,$n){
if($method=='showVarType'){
if(is_numeric($n[0])){ //不能用$n。要用$n[0];
$this->displayNum();
}else if (is_array($n[0])){
$this->displayArr();
}else{
$this->displayOther();
}
}
}
function displayNum() {
echo '<h3>這是數字!</h3>';
}
function displayArr() {
echo '<h3>這是數組!</h3>';
}
function displayOther() {
echo '<h3>不是數組也不是數字!</h3>';
}
}
$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
附:記憶:以後統一在調用方法或屬性時用 "-> ",調用常量則用雙冒號“::”,不會搞暈。
八、方法和屬性的作用域:
共有6種:public(默認,可省略,也等同於php6的var聲明),private(私有,也不能由子類使用),protected(私有,但可由子類使用) ,abstract(抽象,參下文),final(阻止在子類中覆蓋—也稱重載,阻止被繼承,用於修飾類名及方法,如final class test{ final function fun(){}} ,但不能用於屬性),static(靜態)
九:抽象類和抽象方法(abstract——注意:沒有所謂抽象屬性):
抽象可以理解成父類為子類定義了一個模板或基類。作用域abstract只在父類中聲明,但在子類中實現。注意事項:
1、抽象類不能被實例化,只能被子類(具體類)繼承後實現。
2、抽象類必須在其子類中實現該抽象類的所有抽象方法。否則會出錯。
3、在抽象方法中,只是聲明,但不能具體實現:如abstract function gettow(){ return $this->p; }是錯的,只能聲明這個方法:abstract function gettow();(連方括號{}都不要出現),抽象方法和抽象類主要用於復雜的類層次關系中。該層次關系需要確保每一個子類都包含並重載了某些特定的方法。這也可以通過接口實現
4、屬性不能被命名為抽象屬性,如abstract $p = 5是錯的。
5、只有聲明為抽象的類可以聲明抽象方法,但如果方法聲明為抽象,就不能具體實現。如:
abstract class Employee
{
abstract function a(...);
abstract function b(...);
}
以後再對這個父類擴展,組成各種子類(如經理,員工,出納)。
6、抽象類中,如果要實現具體的方法,不能聲明為抽象。這樣可能實際意義更大。可以把幾個類庫中共同的部分提取到抽象類中,其它的類繼承抽象類即可。如下:
abstract class BaseShop{
Const TAX=0.06; // 在抽象類中定義常量
public function buy($gid) { // 如果定義為抽象方法abstract function buy()就不能在這裡實現主體。
echo('你購買了ID為 :'.$gid.'的商品');
}
public function sell($gid) {
echo('你賣了ID為 :'.$gid.'的商品');
}
public function view($gid) {
echo('你查看了ID為 :'.$gid.'的商品');
}
}
class BallShop extends BaseShop{
var $itme_id = null;
public function __construct()
{
$this->itme_id = 2314;
}
public function open()
{
$this->sell($this->itme_id);
}
public function getTax()
{
echo printf('<h3>平均稅率是 %d%%。</h3>',$this::TAX*100);
}
}
$s = new BallShop;
$s->open(); //你賣了ID為 :2314的商品
$shop->getTax();