PHP類的變量與成員,及其繼承、訪問與重寫要注意的問題


PHP的類及其實例:

<?php
class Myclass{
public  $prop = 123;
}
$obj =  new Myclass();
?> 

類的成員屬性(屬性的稱呼相對於‘方法’而言)包括類常量和類變量,其中類常量在定義時不可為空,類的屬性在定義時如果被賦值,只能使用變量和數組,並且不能是表達式,因為類屬性在編譯期被初始化,PHP在編譯器不執行表達式。

1、成員的訪問控制

public:可以繼承,可以在類的方法之外被訪問,如$obj->prop;

protected:可以繼承,不可以在類的方法之外被訪問;

private:不可以繼承,不可以在類的方法之外訪問;

 

PHP4使用var來聲明類的屬性,在PHP5之后不再使用,PHP5.3之前使用被警告,在PHP5.3之后可以在public之前或單獨使用作為public的別名。

 

這三個訪問控制關鍵字也可以修飾構造函數,當private和protected修飾類的構造函數時,只能通過一個public static的靜態方法調用構造函數以實例化對象,因為該構造函數無法在類之外被訪問了,比如,單例類的實現:

<?php
class Singleton{
private  static  $instance =  null;
public  $k = 88;
private  function __construct(){
}
public  static  function getInstance(){
if(self:: $instance ==  null){
// self::$instance = new Singleton();
self:: $instance =  new self();
}
return self:: $instance;
}
public  function __clone(){
throw  new  Exception('Singleton class can not be cloned');
return self:: $instance;
}
}
// $in = new Singleton();
$in = Singleton::getInstance();
var_dump( $in);
?> 

2、繼承禁止:final關鍵字,僅用於修飾類或類的方法

如果一個類被final修飾,這個類不能被繼承,如果一個方法被final修飾,則這個方法不能被子類重寫(override)。

<?php
class Myclass{
public  $prop = 123;
final  public  static  function methodA(){
return 'this is a final method';
}
}
?> 

3、抽象類和抽象方法,abstract僅用於類和方法,抽象類不能直接用於實例化對象,只能用於產生子類

<?php
abstract  class Myclass{
public  $prop = 123;
abstract  public  function methodA(); // 抽象方法沒有實現函數體
}
?> 

4、類的常量及其訪問:類的常量不能使用訪問控制修飾符,他是public的,可繼承,可以被子類重寫。訪問類的常量必須使用雙冒號::可以使用類名或類的實例(對象)來訪問,因為是常量,所以名稱不能使用表示變量的符號$。

<?php
class Myclass{
public  $prop = 123;
const X = 999;
final  public  static  function methodA(){
return 'this is a final method';
}
public  function getConst(){
return self::X; // 或者$this::X
}
}
$in =  new Myclass();
echo  $in->getConst();
echo Myclass::X;
?> 

類的常量是一個值,在代碼編譯器常量名被替換為相應的值,在運行期不可修改,因此類的常量與類本身無關,在類實例化對象之前就已經存在,因此類的常量可以直接使用類名訪問

<?php
class P{
const M = 100;
const N = self::M;
public  static  $k = 99;
public  function getStatic(){
return self:: $k;
}
public  function getStatic2(){
return  static:: $k;
}
}
class S  extends P{
const M = 200;
public  static  $k = 88;
public  function getPConst(){
return parent::N;
}
}
$p =  new P();
$s =  new S();
echo  $p::N.'<br>'; // 100
echo  $s::N.'<br>'; // 200 該常量名繼承自父類,在編譯期就已經直接取 self::M 的值替換了 ,注意區別類的方法中使用 self::M
echo  $s->getPConst().'<br>'; // 100
echo  $s->getStatic2().'<br>'; // 88
?> 

5、類的靜態成員訪問

static可以修飾類的屬性和方法,被static修飾的成員歸屬於類而非類的實例。靜態成員必須使用類名加雙冒號::來訪問,因此在實例化對象之前靜態成員就存在了,因此,在靜態方法內禁止使用指向實例本身的偽變量$this(或習慣上稱為$this指針),可以使用關鍵字self代替類名(相當於類的魔術常量__CLASS__)。

 

static不能修飾類的構造函數,也不能修飾接口聲明的方法。

<?php
class Myclass{
public  static  $x = 99;
public  function getX(){
return self:: $x;
}
public  static  function getX2(){
return self:: $x;
}
}
echo Myclass:: $x."<br>";
echo Myclass::getX2()."<br>";
$MC =  new Myclass();
echo  $MC->getX2()."<br>";
?> 

靜態成員可以使用訪問控制關鍵字修飾,可以被繼承和重寫,需要注意的是,如果一個子類繼承了父類的靜態方法(沒有重寫該方法),那么子類調用的實際是父類的靜態方法。因為靜態成員持有者是類不是對象,所以類的多個實例是共享一個靜態屬性,在一個實例中修改靜態屬性會影響到另一個實例的靜態屬性:

<?php
class A{
public  static  $a1 = 11;
public  $a2 = 22;
public  static  function showStatic(){
return self:: $a1;
}
public  function getStatic(){
return self:: $a1;
}
public  function getClassStatic(){
$className = get_called_class();
return  $className:: $a1;
}
public  function getProp(){
return  $this->a2;
}
}
 
class B  extends A{
public  static  $a1 = 88;
public  $a2 = 99;
}
 
$obj1 =  new A();
$obj2 =  new B();
 
echo  $obj1->getStatic()."<br>"; // 11
echo  $obj1->getClassStatic()."<br>"; // 11
echo  $obj1->getProp()."<br>"; // 22
 
echo B::showStatic()."<br>"; // 11調用的是父類的方法,訪問父類的靜態成員
echo  $obj2->getStatic()."<br>"; // 調用的是父類的方法,方法中的slef指向持有該靜態方法的類
echo  $obj2->getClassStatic()."<br>"; // 88
echo  $obj2->getProp()."<br>"; // 99
?> 

 

后期靜態綁定:為了避免子類重寫靜態屬性后,使用繼承來的方法仍然方法父類的靜態屬性,PHP5.3增加了一個新的語法,后期靜態綁定,使用static關鍵詞替代self關鍵字,使得static指向與get_called_class()返回的相同類,即當前調用該靜態方法的對象所屬的類,該關鍵字對於靜態方法的訪問同樣有效。

public function getClassStatic(){

$className = get_called_class();

return $className::$a1;

}

//可以寫成

public function getClassStatic(){

return static::$a1;

}

6、類的方法中幾個指向類或實例的關鍵字

$this->propName    $this指向類的實例

parent::xxx      parent指向父類,可以訪問父類的靜態常量、靜態屬性,不能訪問父類的非靜態屬性可以調用父類的方法(不能是private方法,無論是否靜態)

self::xxx   self指向定義了當前被調用的方法的類,用於訪問靜態成員和類的常量

static::xxx  訪問實例化了調用當前方法的實例的那個類,用於訪問靜態成員和類的常量,它跟self的差別是訪問靜態成員是“后期靜態綁定”

 

7、類的繼承中的重寫問題

重寫的成員的訪問控制程度不能被縮小,例如,public的成員不能重寫為protected

非靜態成員不能重寫為靜態成員,靜態成員也不能重寫為非靜態成員

 

8、接口中定義的方法必須是public

類在實現接口的方法時,這些方法也必須是public的。

接口也可以定義接口常量,用法和類的常量一致,但是接口不可以定義非函數成員。

接口與接口之間可以繼承,接口的繼承可以是多繼承,用逗號隔開(子類與父類的繼承是單繼承)。

一個口可以實現多個接口,用逗號隔開。

<?php
interface Ix  extends Iy,Iz{
    public  function a();
}
 
 
class A  implements Iy,Iz{
 
    // .......
 
}
?> 

9、類型約束

PHP的函數(或類的方法)可以在聲明是限定參數的類型,但只能限定array或object(class/interface),如果限定為string,PHP會認為是限定為一個string類的object參數。

如果類型被限定為某一個接口,則傳入的參數必須是實現該接口的類的實例。

在接口實現、子類重寫父類方法時,不能修改已經限定的參數類型。

在方法、函數調用時,如果傳入了與限定的參數類型不同的數據將會報錯,但是可以接收null參數。

<?php
interface Im{
    public  function a( classm  $m);
}
 
 
 
class A  implements Im{
     public  function a( $x){    //  error ,參數$x必須限定為 classm 類型以匹配接口的定義
        var_dump( $x);
    }
}
?> 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM