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

PHP self 關鍵字深度解析:靜態成員存取、編譯時綁定與晚期靜態綁定對比

     編輯:PHP 相關知識

self:類自身的「靜態名片」

self 代表**當前定義的類**,用於存取**靜態屬性、常數、靜態方法**。它在**編譯時綁定**,不指向任何實例化物件。

核心語法

self::$staticProperty
self::CONSTANT
self::staticMethod()

必須配合 ::(作用域解析操作符)使用。

經典範例:計數器靜態屬性

<?php
class Counter {
    private static $firstCount = 0; // 類層級,所有實例共享
    private $lastCount;             // 實例層級,各自獨立
    
    public function __construct() {
        // 使用 self 存取靜態屬性
        $this->lastCount = ++self::$firstCount;
    }
    
    public function printLastCount() {
        echo $this->lastCount . "\n";
    }
}

$obj1 = new Counter(); // self::$firstCount = 1, $obj1->lastCount = 1
$obj1->printLastCount(); // 1

$obj2 = new Counter(); // self::$firstCount = 2, $obj2->lastCount = 2
$obj2->printLastCount(); // 2

$obj3 = new Counter(); // self::$firstCount = 3, $obj3->lastCount = 3
$obj3->printLastCount(); // 3

echo "總計建立: " . Counter::$firstCount; // 錯誤:private 不可外部存取
// 需提供公共靜態方法
?>

self 的關鍵特性

  1. 編譯時綁定:self 解析為書寫該代碼的類,不隨繼承變化。
  2. 僅限靜態成員:不能用 self->property 存取實例屬性。
  3. 不可在實例上下文外使用:但可在非靜態方法中用 self:: 存取靜態成員。

self vs static:繼承場景的關鍵差異

<?php
class Base {
    public static $name = 'Base';
    
    public static function whoSelf() {
        echo "self: " . self::$name . "\n"; // 永遠指向 Base
    }
    
    public static function whoStatic() {
        echo "static: " . static::$name . "\n"; // 指向實際調用類
    }
}

class Child extends Base {
    public static $name = 'Child';
}

Base::whoSelf();    // self: Base
Base::whoStatic();  // static: Base

Child::whoSelf();   // self: Base  ← 編譯時綁定在 Base
Child::whoStatic(); // static: Child ← 晚期靜態綁定
?>

實戰場景:Active Record 基類

<?php
abstract class Model {
    protected static $table = 'base';
    
    // 使用 static 獲取子類表名
    public static function table() {
        return static::$table;
    }
    
    // 使用 self 獲取基類預設連線
    protected static function getDefaultConnection() {
        return self::$pdo ??= new PDO('sqlite::memory:');
    }
}

class User extends Model {
    protected static $table = 'users';
}

class Post extends Model {
    protected static $table = 'posts';
}

echo User::table();  // users(static 解析到 User)
echo Post::table();  // posts
?>

self vs $this 對比表

特性self$this
指向當前類(靜態)當前實例(動態)
存取成員靜態屬性/常數/方法實例屬性/方法
語法self::$prop、self::CONST、self::method()$this->prop、$this->method()
綁定時機編譯時執行時
繼承行為固定在定義處類隨實例類型變化
可用位置靜態/非靜態方法僅非靜態方法

常見錯誤

  • 嘗試用 self 存取實例屬性:
    class Foo {
        public $x = 1;
        public function bar() {
            echo self::$x; // Error: Access to undeclared static property
        }
    }
    
  • 靜態方法中用 $this:
    class Foo {
        public static function bar() {
            echo $this->x; // Error: Using $this when not in object context
        }
    }
    
  • 誤以為 self 會隨繼承改變:見上文 self vs static 範例。

現代用法:靜態工廠方法

<?php
class User {
    private static $instances = [];
    public readonly string $name;
    
    private function __construct(string $name) {
        $this->name = $name;
    }
    
    // 靜態工廠:單例模式變體
    public static function getInstance(string $name): self {
        return self::$instances[$name] ??= new self($name);
    }
    
    // 克隆禁止
    private function __clone() {}
    public function __wakeup() { throw new Exception("不可反序列化"); }
}

$u1 = User::getInstance('Alice');
$u2 = User::getInstance('Alice');
$u3 = User::getInstance('Bob');

echo ($u1 === $u2) ? "同一實例\n" : "不同實例\n"; // 同一實例
echo ($u1 === $u3) ? "同一實例\n" : "不同實例\n"; // 不同實例
?>

總結

self 是 PHP 類靜態成員的**編譯時入口**,配合 static(晚期靜態綁定)構成靜態多型的雙支柱。掌握 self 固定在定義類、static 隨調用類變化的本質差異,是設計可擴展基類、工廠模式、Active Record 等靜態導向架構的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved