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


基於 PHP5.3

 PHP 的類及其實例:

class Myclass{

   public $prop = 123;

}

$obj = new Myclass();

 

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

 

1、成員的訪問控制:

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

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

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

 

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

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

class Singleton {
    private static $instance=null;
    public $k = 88;
    private function __construct(){

    }

    public static function getInstance(){
        if(self::$instance==null){
                self::$instance = new self();
        }

        return self::$instance;
    }

    public function  __clone(){ //pretend clone oprationg
        throw('Singleton class can not be cloned');
        return self::getInstance();
    }
}

//new Singleton();  // Error
$in = Singleton::getInstance();  

 

 

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

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

class Myclass{

   public $prop = 123;

  final public static function  methodA(){//不可繼承的,公開的靜態方法

        return 'this is a final method';

  }

}

 

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

abstract class Myclass{

   public $prop = 123;

   abstract public function  methodA(); //抽象方法沒有實現函數體

}

 

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

class Myclass{

   public $prop = 123;

   const x =999;

  public static function methodA(){

        return 'this is a final method';

  }

  public function getConst(){

      return self::x;  //或者 $this::x;

  }

}

 $instance = new Myclass();

 

echo Myclass::x;

echo $instance::x;

echo $instance->getConst();

 

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

class P{
   const m = 100;
   const n = self::m;
   static $k = 99;
   public function getStatic(){
    return self::$k;
  }
  
    public function getStatic2(){
    return static::$k;
  }
  
}

 

class S extends P{
  const m=200;
  static $k = 88;
  public function getPConst(){
    return parent::n;
  }
  
}

 

$p = new P();
$s = new S();
echo $p::n; //100
echo '<br />';
echo $s::n; //200 該常量名繼承自父類,在編譯期就已經直接取 self::m 的值替換了 ,注意區別類的方法中使用 self::m 
echo '<br />';
echo $s->getPConst(); //100
echo '<br />';
echo $s->getStatic(); //99 調用方法時
echo '<br />';
echo $s->getStatic2(); //111

 

5、類的靜態成員及訪問

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

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

 

class Myclass{

   public static $x = 99;

   public function getX(){

        return self::$x;

    }

}

echo Myclass::x; //99

 

 

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

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 A::showStatic(); //11

echo $obj1->getStatic(); //11

echo $obj1->getClassStatic(); //11

echo $obj1->getProp(); //22

 

echo B::showStatic(); //11 調用的是父類的方法,訪問父類的靜態成員

echo $obj2->getStatic(); //11 調用的是父類的方法,方法中的 self 指向持有該靜態方法的類

echo $obj2->getClassStatic(); //88

echo $obj2->getProp(); //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;

  }

 

//用於靜態方法

//A類中:

  public static function testStatic(){
          echo "<p>testStatic of A </p>";
  }

  public function callStatic(){
       static::testStatic();
  }

 

//B類中:

    public static function testStatic(){
          echo "<p>testStatic of B </p>";
    }

 

//B類繼承A類的 callStatic 方法,可以正確訪問各自類的 testStatic 方法。

 

 

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

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

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

 

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

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

 

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

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

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

 

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

類在實現接口的方法時,這些方法也必須是 public 的,具體實現的(不能是 abstract )。

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

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

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

interface Ix extends Iy,Iz{
   public function a();
}

 
class A implements Iy,Iz{

   .......

}

 

9、類型約束

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

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

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

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

 

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