程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 談談PHP繼承的那些事,我的個人見解,php繼承那些事見解

談談PHP繼承的那些事,我的個人見解,php繼承那些事見解

編輯:關於PHP編程

談談PHP繼承的那些事,我的個人見解,php繼承那些事見解


  網上經常流傳出php是語言鄙視鏈最低端的那個,曾經大學學java,畢設用java,剛出來培訓用java的我,在最初工作的2、3年時對php的面向對象也是頗有意見,總覺得【不倫不類】,更別提對js的看法了。但是這些觀點都在經歷越來越多的項目之後逐漸的淡化,甚至改觀。這裡面包含著自己對項目、技術有著更多的理解,同時,在這些年裡,Web環境、技術也在不停的更新。不過今天不是來聊這些東西的,對於以上的問題,我的觀點可以總結為:技術是工具、手段,不合適就升級、換,就這麼簡單。

  話歸原題。雖然寫php已經是將近8年的功底了,但因為工作關系,經常需要涉及前後端的各種代碼,容易精分,也總會記岔。最近發生的一件事情讓我覺得,或許寫下來能夠讓自己清醒一點。

  在某一年寫某個模塊時用到了static成員,在實現子類的過程中發現他們也共享著父類這個成員的值,具體來說就是我在某個子類A中改變了那個成員值,在另外一個子類B使用的時候結果意外的得到了A覆蓋後的值。當時以為,原來static成員是在從聲明的地方開始的整個類別樹中共享的。後來一直隱約記得這個結論,在平常的代碼裡面更謹慎的使用static成員,除非確認寫的類是個獨立的工具類,不然不輕易使用static。

  直到有一天我的老大跟我商量升級我之前寫的一個BaseModel,他無意中問我:好像你不喜歡用static成員?我說沒有啊,因為考慮到BaseModel會被經常繼承成各種Model,如果我在這裡用了static的話,將來容易踩坑。他表示不理解,然後過來與我辯論。我很義正言辭的說明了因為static成員會被共享,如果要調用兩個不同的子類的時候,那個static成員的變量的值就會像一個全局變量一樣不可控。他不同意。於是本著科學的精神,我們寫下了一個簡短的代碼來驗證:

  class A {

  protected static $var1 = null;

  public static function test(){

  echo get_called_class()。' '.static::$var1.'<br/>';

  }

  }

  class B extends A {

  protected static $var1 = 'b';

  }

  class C extends A {

  protected static $var1 = 'c';

  }

  B::test();

  C::test();

  很顯然,這次是我敗了。 我期待的結果是c c,不過其實是b c。 那麼這樣看起來其實子類的static成員是只在子類這一層共享的。但是我總覺得不對勁,明明在寫BaseModel的時候我已經又栽過跟頭了,為什麼這個驗證出來並不支持我那個時候遇到的問題呢?於是我發現我記岔了。年輕多好。後來想起來,原來我這裡不用static的原因僅僅是因為設計需要。

  我以為我錯了。直到前幾天又寫了幾個父子類(不是BaseModel了),大膽的用上了static成員,結果是轟轟烈烈的在自測中又摔了一跤。怎麼回事!然後我仔細留意了一下自己這次的用法,將上面的例子改了一下運行:

  class A {

  protected static $var1 = null;

  protected static $var2 = null;

  public static function test(){

  if(!static::$var2){

  static::$var2 = static::$var1;

  }

  echo get_called_class()。' '.static::$var1.'<br/>';

  }

  }

  class B extends A {

  protected static $var1 = 'b';

  }

  class C extends A {

  protected static $var1 = 'c';

  }

  B::test();

  C::test();

  結果是

  B b

  C b

  如果說上次的結論是對了,那麼這次又怎麼解釋?這裡明明就是表示$var2是A,B,C共享的。$var1和$var2的差別這樣看起來僅僅是有聲明和沒聲明的區別。於是我又改成這樣:

  class A {

  protected static $var1 = null;

  protected static $var2 = null;

  public static function test(){

  if(!static::$var2){

  static::$var2 = static::$var1;

  }

  echo get_called_class()。' '.static::$var1.'<br/>';

  }

  }

  class B extends A {

  protected static $var1 = 'b';

  protected static $var2 = null;

  }

  class C extends A {

  protected static $var1 = 'c';

  protected static $var2 = null;

  }

  B::test();

  C::test();

  結果是

  B b

  C c

  我當時內心是崩潰的。於是我上了Stack Overflow,發現栽坑的不止我一個。

  只有顯式的聲明出來的static成員才會被視為是只從屬於子類的。

  只有顯式的聲明出來的static成員才會被視為是只從屬於子類的。

  只有顯式的聲明出來的static成員才會被視為是只從屬於子類的。

  重要的事情說三遍!不過如果子類很多的話, 動態決定值的成員 每個都這樣去聲明,就從寫代碼這件事上失去了用static的意義。一個更好的方法是,把$var2變成一個數組,每個類要用的值放在$var[__CLASS__]裡面使用。

  不過不管怎麼說,如非必要,還是盡量不用static成員繼承吧。

  還有一個有點類似的“坑”。我們說到private成員的時候,都知道private是指私有的,不會被子類繼承。但是有時候寫代碼的時候會忘記,直到載跟頭了才想起來原來是private導致子類找不到該有的成員,或者說是private都在子類聲明了,但是因為調用函數時是調用父類函數,結果得到的是父類這個private的值而不是子類的。遇到這種情況不可能又將函數原樣的重寫在子類裡。所以使用private要特別小心。

  曾經在使用Rackspace的SDK的時候就看到有些類裡面使用了private成員,但是由於他們給出了不必要的打開文件權限,導致代碼在我們的服務器上運行不了。那麼這個時候本想寫個子類覆蓋一下這個成員的初始值就好了,結果就因為這是個private成員,而最後需要把所有引用到的地方都拷到自己寫的子類裡面。為什麼我們不直接改SDK,讓成員變成protected?因為開發包也許下次就升級了呢?修正之後我們把子類移除就好了。如果修改庫代碼成了習慣,想升級的時候就沒這麼歡了。所以說,private成員的使用一定要慎之又慎,如果你也在開發SDK,就更需要考慮使用者是不是需要繼承?如果你必須寫private,你是不是能夠保證代碼能夠適應各種場景的使用?

  除非你有非常充分的理由,static和private都是需要慎重使用的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved