首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 訪問控制面試題深度解析:private 繼承與方法內部訪問的陷阱

     編輯:PHP 綜合知識

題目代碼

<?php
class Foo {
    private $name = 'hdj';
    public function getName() { return $this->name; }
}
class Bar extends Foo {
    public $name = 'deeka';
}
$bar = new Bar;
var_dump($bar->name);      // 輸出?
var_dump($bar->getName()); // 輸出?
?>

輸出結果


string(5) "deeka"   // $bar->name
string(3) "hdj"     // $bar->getName()

核心原理解析

1. 屬性遮蔽而非覆蓋

  • Foo::$name 為 private,**子類不可見、不可繼承、不可覆蓋**。
  • Bar::$name 為 public,**新聲明的一個完全獨立屬性**,僅名字相同。
  • 對象內存中同時存在兩個 name 槽位:Foo::name(私有)與 Bar::name(公開)。

2. 訪問權限在「定義處」靜態綁定

  • Foo::getName() 內部 $this->name 編譯時綁定到 Foo::$name(私有)。
  • 即便 $this 實際是 Bar 實例,訪問權限檢查基於方法所在類,而非運行時類型。
  • 因此 $bar->getName() 返回父類私有屬性 'hdj'。

3. 對象屬性訪問規則

訪問方式訪問到的屬性原因
$bar->name(外部直接訪問)Bar::$name (public)查找順序:當前類 → 父類;找到 public 即返回
$bar->getName()(內部方法訪問)Foo::$name (private)方法定義在 Foo,訪問權限綁定 Foo,private 可見
$bar->getName() 若在 Bar 中重寫Bar::$name (public)方法定義在 Bar,訪問權限綁定 Bar

驗證代碼:記憶體中確有兩個槽位

<?php
$bar = new Bar;
$ref = new ReflectionObject($bar);
foreach ($ref->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE) as $prop) {
    $prop->setAccessible(true);
    echo $prop->getDeclaringClass()->getName() . '::$' . $prop->getName() . ' = ' . var_export($prop->getValue($bar), true) . "\n";
}
/*
輸出:
Foo::$name = 'hdj'
Bar::$name = 'deeka'
*/

最佳實踐避坑指南

  1. 避免同名屬性跨層級聲明:子類需新語義時改名(如 $childName),或改用 protected 共享同一槽位。
  2. 統一使用 getter/setter:外部永不直接訪問屬性,內部邏輯集中在方法中,避免遮蔽導致的認知偏差。
  3. 理解 private 意為「僅當前類可見」:非「子類不可用」,子類可擁有同名私有屬性,互不干擾。
  4. 測試覆蓋:針對繼承鏈編寫單元測試,驗證屬性隔離行為。

延伸:protected 與 public 差異

  • protected:子類可見,可直接 $this->name 讀寫,**同一槽位**,真正共享。
  • public:同 protected 但外部也可見。
  • 若需父子共享狀態 → protected;若需父子各自獨立狀態 → private + 子類新聲明(但建議改名)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved