PHP 類的使用與總結_PHP教程

來源:互聯網
上載者:User
一:結構和調用(執行個體化):

class className{} ,調用:$obj = new className();當類有建構函式時,還應傳入參數。如$obj = new className($v,$v2…);

二:建構函式和解構函式:
1、建構函式用於初始化:使用__construct(),可帶參數。
2、但解構函式不能帶參數(用於在銷去一個類之前執行一些操作或功能)。解構函式用__destruct()做名稱。在指令碼執行結束時,會銷掉記憶體中的對象,因此可不用析造函數,但有些比如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 “
”; 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 ‘

這是數字!

’;
}
function displayArr() {
echo ‘

這是數組!

’;
}
function displayOther() {
echo ‘

不是數組也不是數字!

’;
}
}

$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(‘

平均稅率是 %d%%。

’,$this::TAX*100);
}
}
$s = new BallShop;
$s->open(); //你賣了ID為 :2314的商品
$shop->getTax();

十:類型提示:
注意,類型提示功能只能用於參數為對象的提示,而無法用於為整數,字串,浮點等類型提示。有些類的方法需要傳入的參數為所期望的物件類型,可以用下面的方法達到強制實施此替則。要達到類型提示,只要在方法的對象型參數前加一個已存在的類的名稱,如:function funname(OtherClassName $otherclassINSName,$c….),注意,OtherClassName必須是存在的類。如下:
class em{ var $k=56; }
class test{
function __construct()
{ echo $this->addab(new em(),2); }

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);

十一、類的管理:
1、instanceof關鍵字:用於分析一個對象是否是某一個類的執行個體或子類或是實現了某個特定的介面:如下例,但要注意: 類名沒有任何引號等定界符,否則會出錯。如test不能用’test’
class test2{}
class test{}
class testChilern Extends test{}
$a = new test2();
$m = new test();
$i = ($m instanceof test);
if($i)echo ‘$m是類test的執行個體!
’; // get this value
switch ($a instanceof test){
case true :
echo ‘YES
’;
break;
case false :
echo ‘No
’; //get this value
break;
}
$d=new testChilern();
if($d instanceof test)echo ‘$d是類test的子類!
’; // get this value
2、確定類是否存在:boolean class_exists(string class_name): class_exists(‘test’);
3、返回類名:string get_class(object),成功時返回執行個體的類名,失敗則返回FALSE:
$a = new test2(); echo get_class($a); //返回 test2
4、瞭解類的公用屬性:array get_class_vars(‘className’) ,返回關鍵數組:包含所有定義的public屬性名稱及其相應的值。這個函數不能用執行個體名做變數
5、返回類方法:get_class_methods(‘test’); //或: get_class_methods($a);可用執行個體名做參數,返回包括建構函式在內的所有非私人方法。
6、print_r(get_declared_classes())瞭解當前PHP版本中所有的類名。PHP5有149個。
7、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]=>) ,
*/
8、返回父類的名稱:get_parent_class($b);//或get_parent_class(‘test2′); 返回test
9、確定介面是否存在:boolean interface_exists($string interface[,boolean autoload])
10、確定物件類型: boolean is_a($obj,’className’),當$obj屬於CLASSNAME類時,或屬於其子類時,返回TRUE,如果$obj與class類型無關則返回FALSE。如:is_a($a,’test’)
11、確定是否是某類的子物件:當$b是繼承自TEST類時,返回TRUE,否則FALSE。boolean is_subclass_of($b,’test’);
12、確定類或執行個體中,是否存在某方法。method_exists($a,’getv’) //或用method_exists(‘test’,'getv’),此函數適用於非public定義的範圍的方法。
以上函數執行個體:
class test{
public $v=2;
private $c=5;
function __construct(){
$this->v=5;
}
private function getv(){
return $this->v;
}
}
class test2 extends test{}

$a=new test();
$b=new test2();
print_r( get_class_methods(‘test’)); //或:print_r( get_class_methods($a)); 均返回:Array ( [0] => __construct [1] => getv )
echo ‘
’;
print_r( get_class_vars(‘test’)); //返回:Array ( [v] => 2 ),和上面不一樣,不能用print_r( get_class_methods($a));
echo ‘
’;
echo get_parent_class($b);//或get_parent_class(‘test2′); 返回test
echo ‘
’;
echo is_a($b,’test’);// 返回1
echo ‘
’;
if(is_subclass_of(‘test2′,’test’))echo ‘是子類!’; //或(is_subclass_of($b,’test’)),返回1,當參數1為$a時則返回false,
echo ‘
’;
echo method_exists($a,’getv’) //或用method_exists(‘test’,'getv’)返回1,本函數也適用於用private等定義域的方法。

十一、自動載入類庫檔案:
當類多了以後,比如要在一個檔案中載入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檔案的代碼是:
class c{
public $m=7;
}
?>這裡代碼的類名稱是c,而檔案名稱也是c,
現在要在index.php調用:
function __autoload($class){
require_once “$class.class.php”;
}

$m = new c(); //建立執行個體調用的類也是c
echo $m->m;
?>
此時PHP會自動調用根目錄下的c.class.php中的類C。

但如果c.class.php中的代碼是:
class mm{
public $m=7;
}
?>
而調用頁index.php代碼是:
function __autoload($class){
require_once “$class.class.php”;
}
# __autoload(‘c’); //如果不加這一行就會出錯。
$m = new mm();
echo $m->m;
?>
會出錯,提示找不到mm.class.php檔案。這時可以加一行__autoload(‘c’);但這樣就達不到簡化代碼的目的。

類的家族化擴充:類的進階功能:

一、對象複製:
當複製一個對象的執行個體時,其屬性初始值繼承了被複製對象的當前值。
class test
{
public $p=5;
function __clone(){ //只在複製發生時起作用。用於改變在複製時某些值
$this->p=15;
}
}
$a=new test();
echo $a->p;
$a->p=8; //如果沒有__clone()方法影響,$b的P值將為8
$b = clone $a;
echo $b->p; //15

二、對象繼承:

沒有被聲明為final的類可以被繼承,沒有被final和private界定的方法也可以繼承,沒有被private界定的屬性也可以繼承。當子類繼承了父類或超類後,可以直接使用父類或超類(祖父類以及祖父的祖父)的所有允許的方法,屬性。
關鍵:理解建構函式和重載在繼承中的特性!
(一)建構函式在繼承中的特性:
1、當父類有建構函式而子類沒有:則子類會在執行個體化時會自動執行父類的建構函式。這時如果要建立子類的執行個體,需要引入父類建構函式中所需的參數,否則出錯。即使是“子類的子類”如果沒有建構函式,也要在建立執行個體時輸入其父類的父類的建構函式所需參數。PHP會從執行個體所在的子類會向上搜尋合造的建構函式,一旦找到就停止,使用該建構函式。而不會再向上搜尋,因此:子類本身如果沒有建構函式,則以其最靠近的一個超類並且有建構函式的為準。
class cA{
public $name,$age;
function __construct($n) {
$this->name = $n;
$this->age = 25;
}
function __set($n,$v) {
$this->$n = $v;
}
function __get($n) {
return $this->$n;
}
}

class cB extends cA{
function funB1() { echo ‘

Class cB execute success!

’; }
}

class cC extends cB {
function funC1() { echo ‘

Class cC FunC1!

’; }
}
$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
2、當子類也有建構函式時:這時,不管父類是否有建構函式,都會執行子類自己的建構函式。
如上:
class cB extends cA{
function __construct() {
echo ‘

this is Class cB \’s __construct!

’;
}
function funB1() {
echo ‘

Class cB execute success!

’;
}
}
現在類CB有自己的建構函式時,這時建立執行個體$b=new cB(‘Jack’);參數JACK不會起作用,因為父類CA的建構函式沒有得到執行。因此$b->name和$->age就不會初始化值。需要另外賦值$b->name=’Jack’,$b->age=25;
如果這時要執行父類CA的建構函式,可以這樣:
function __construct($n) {
parent::__construct($n); // 或:cA::__construct($n);
echo ‘

this is Class cB \’s __construct!

’;
}
由於parent::__construct($n); 只會向上搜尋父類的建構函式,一找到就停止且執行當前找到的建構函式,因此在上面例子中,如果parent::__construct($n)是用在最後一層的類cC中,並且類CB,CA都有建構函式,那麼cC的執行個體只會執行cB的建構函式。不會執行cA。這時,如果CC的執行個體想都調用CA和CB的建構函式,有兩種方法:
A、在CB中也加入parent::__construct($n)
B、在CC中把建構函式改為:
function __construct($n) {
cA::__construct($n); //即:類名::建構函式。
cB::__construct();
echo ‘

this is Class cB \’s __construct!

’;
}
(二)在子類中調用父類的屬性或方法:
1、調用父類方法:在子類中調用父類的方法,有3種方法:
$this->ParentFunction(); 或
父類名::ParentFunction(); 或
parent::parentFun();
2、調用父類屬性:只能用$this->ParentProperty;
(三)重載:
在子類中,可以定義與父類相同屬性或方法,改變父類該屬性或方法的值或操作,稱做重載。如:
calss ParClass{ function pfun(){ ….}}
class ChildrenClass extends ParClass{function pfun(){ ….}}} //重載了父類的pfun的方法。
在子類中重載後,優先執行自己重載後的新定義的方法或屬性。
也可以在子類中用parent::parentFun();調用父類的方法,但所得到的值是子類自己輸入的參數運算值。而不是該方法在父類中運算的值。

三、介面:

介面:interface,可以理解成一組功能的共同規範,最大意義可能就是在多人協作時,為各自的開發規定一個共同的方法名稱。
和抽象類別中的抽象方法一樣:
1、不能在介面中對方法具體實現進行定義。而是由具體類來實現(而抽象類別中的非抽象方法可以不必再定義,只有抽象方法和介面是一樣要求要在具體類中實現)。
2、和抽象類別一樣,可以在介面中定義常量,並由具體類直接繼承。
3、具體類必須實現抽象類別的所有抽象方法(非抽象方法除外),同樣,具體類如通過implements實現了介面後,必須完成介面中的所有方法。

介面實現過程:1、定義介面,2、用..implement X,Y,…和具體類對接。
interface Info{ //定義介面
const N=22;
public function getage();
public function getname();
}

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 ‘

在介面中定義的常量N的值是:’.$this::N.’

’; //直接繼承介面中的常量值。
}
}

$age=new age;
echo $age::N; //22,直接調用介面中的常量值。
$age->getN();
關於抽象類別和介面類的使用區分:何時用介面,何時用抽象?
1、相關性:當建立的模型由一些緊密相關的對象採用時,用抽象。對於不相關對象採用的功能,用介面。
2、多重繼承:PHP類可以繼承多個介面,但不能擴充多個抽象類別。
3、公用行為實現:抽象類別可在其中實現公用的方法,但介面不行。

四、命名空間(PHP6)

類庫指令碼A.inc.php和指令碼B.inc.php中都一個類的名稱為 class CNAME,並且這兩個檔案要在同一個檔案如index.php中被調用。這時要用到命名空間。
步聚:
1、開啟上面的A和B兩個檔案,分別在上面的最前面各加一行:
namespace SPACEA; 和 namespace SPACEB; 名字自定。
2、在index.php中執行個體化類時,在類的前面添加命名空間和雙冒號做為首碼:
include ‘a.inc.php’;
include ‘b.inc.php’;
$a=new SPACEA::CNAME();
$b=new SPACEB::CNAME();
這樣就不會衝突了。
但在PHP6正式發布前,這個功能還未定下來。

五、實現迭代器和迭代。
參《PHP聖經》P142;

六、使用Reflection(反射)API 。
簡易執行個體:
class a{ …. }
$c = new ReflectionClass(‘a’); //PHP 內建類。
echo ‘

’.$c.’
’;
輸出類a的結構和內容。參《PHP聖經》P145;

轉載:http://www.onexin.net/?p=2533

http://www.bkjia.com/PHPjc/621646.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/621646.htmlTechArticle一:結構和調用(執行個體化): class className{} ,調用:$obj = new className();當類有建構函式時,還應傳入參數。如$obj = new className($v,$v2…); 二:構...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.