1. 程式人生 > >一文解決 PHP靜態(區域性/全域性)變數、auto(區域性/全域性)變數、類中static

一文解決 PHP靜態(區域性/全域性)變數、auto(區域性/全域性)變數、類中static

一、靜態區域性變數、auto區域性變數、類中static

這是我的概念:

類屬性,類方法:是給類使用的,在類中使用 self::和 static:: 代表,供呼叫

例項屬性,例項方法:是給例項使用的,在類中使用 this-> 代表,供呼叫

<?php
/**
 * User: X.W.X
 * Date: 2018-09-14
 * Time: 13:57
 * FileName: test.php
 * Introduce:
 */

// 當前 php7.0版本 好像還沒有 靜態函式,靜態類的概念,所以 不測試
// 以下是主要測試內容:
// 測試 靜態區域性變數和auto區域性變數 的區別
// 測試 類中 靜態屬性和非靜態屬性 的區別
// 測試 類中 靜態方法和非靜態方法 的區別
class TestStatic{

    // 類中有寫static的屬性和方法 ==> 類屬性和類方法
    // 類中沒寫static的屬性和方法 ==> 例項屬性和例項方法

    // 有static ==> 類屬性
    // 可使用 self::或者static:: 呼叫 ==> 二者的區別:  self:: 和 static:: 都代表者類,但self::始終代表當前類,而static:: 代表最後一次被重寫的類
    public static $echo_static;
    // 無static ==> 例項屬性
    // 可使用 $this-> 呼叫
    public $echo_auto;
    protected $echo_protected;

    // 例項方法 ==> 測試(普通變數=auto變數)
    public function test_auto(){
        // auto變數必須初始化 ==> 出函式之後,會被刪除回收 ==> 再次進入函式,繼續被初始化
        $i = 0;
        $this->echo_auto = $this->echo_auto.strval($i).',';
        $i++;
    }

    // 靜態方法(類方法) ==> 測試(靜態變數=static變數)
    public static function test_static() {
        // 只初始化一次 ==> 出函式之後,會被記住不回收,但其作用範圍被侷限在函式內,因此跟全域性變數有所區別 
        // ==> 再次進入函式,不會被初始化,會從記住的值繼續開始
        static $i;
        self::$echo_static = self::$echo_static.strval($i).',';
        $i++;
    }

    public function common()
    {
        foreach (range(0, 10) as $index) {
            // 展示 例項呼叫
            $this->test_auto();
            // 展示 靜態呼叫
            static::test_static();
        }
    }


    public function testInstanceInherit(){
        // get_called_class() 獲得當前呼叫類名
        $class = get_called_class();
        echo '當前類名: '.$class." 測試 公開例項方法 重寫".PHP_EOL;
    }

    public static function testClassInherit(){
        $class = get_called_class();
        echo '當前類名: '.$class." 測試 公開類方法 重寫".PHP_EOL;
    }

}

// 生成例項
$test = new TestStatic();
// 測試 static變數和auto變數
$test->common();
// 測試 例項呼叫例項方法,注意:不使用$符號
echo $test->echo_auto.PHP_EOL;
//echo $test->echo_static.PHP_EOL; // 例項呼叫類屬性 報錯,Accessing static property
// 測試 類呼叫類方法,注意:使用$符號,為什麼呢?這是我的愚見:無例項化,那些類屬性沒被建立,因此使用$符號
echo TestStatic::$echo_static.PHP_EOL;
//echo TestStatic::$echo_auto.PHP_EOL; // 類呼叫例項屬性 報錯,Access to undeclared static property
/*
result:
    0,0,0,0,0,0,0,0,0,0,0,
     ,1,2,3,4,5,6,7,8,9,10,
*/

/**
 * 從以上結果可看出,php7.0版本
 * auto變數必須初始化 ==> 出函式之後,會被刪除回收 ==> 再次進入函式,繼續被初始化
 * static變數非必須初始化,預設初始化為null且只初始化一次 
 * ==> 出函式之後,會被記住不回收,但其作用範圍被侷限在函式內,因此跟全域性變數有所區別 
 * ==> 再次進入函式,不會被初始化,會從記住的值繼續開始
 */

class TestStaticSub extends TestStatic
{
    public function testInstanceInherit(){
        $class = get_called_class();
        echo '當前類名: '.$class." 測試 公開例項方法 重寫".PHP_EOL;
        echo '當前類名: '.$class." 這是 重寫內容".PHP_EOL;
    }

    public static function testClassInherit(){
        $class = get_called_class();
        echo '當前類名: '.$class." 測試 公開類方法 重寫".PHP_EOL;
        echo '當前類名: '.$class." 這是 重寫內容".PHP_EOL;
    }
}

// 父類TestStatic 例項
$test_static = new TestStatic();
// 子類TestStaticSub 例項
$test_static_sub = new TestStaticSub();

// 父類例項 呼叫父類例項方法
$test_static->testInstanceInherit();
// 父類例項 呼叫父類類方法
$test_static->testClassInherit();
// 子類例項 被重寫,呼叫子類例項方法,==> 被重寫規則:方法名和引數要都一樣才會被重寫
$test_static_sub->testInstanceInherit();
// 子類例項 被重寫,呼叫子類類方法
$test_static_sub->testClassInherit();

echo PHP_EOL;
// 父類 呼叫 父類類方法
TestStatic::testClassInherit();
//TestStatic::testInstanceInherit(); // 父類 呼叫 父類例項方法 報錯,Non-static method
// 子類 呼叫 子類方法
TestStaticSub::testClassInherit();
//TestStaticSub::testInstanceInherit(); // 子類 呼叫 子類例項方法 報錯,Non-static method
// 從下面 結果 可看出 不管是類方法還是例項方法,只要方法名和引數相同,都會被重寫 形成類多型
// 那有 類多型 有沒有 例項多型呢?
/*
result:
    當前類名: TestStatic 測試 公開例項方法 重寫
    當前類名: TestStatic 測試 公開類方法 重寫
    當前類名: TestStaticSub 測試 公開例項方法 重寫
    當前類名: TestStaticSub 這是 重寫內容
    當前類名: TestStaticSub 測試 公開類方法 重寫
    當前類名: TestStaticSub 這是 重寫內容

    當前類名: TestStatic 測試 公開類方法 重寫
    當前類名: TestStaticSub 測試 公開類方法 重寫
    當前類名: TestStaticSub 這是 重寫內容
*/

/**
 * 從以上結果可看出,php7.0版本
 * 1. 類方法會被例項所繼承,但類屬性暫時在當前版本是沒被例項所繼承,不像python3語言,例項預設繼承類中的類屬性和類方法
 * 2. 也就是說,當前PHP版本中 ==> 例項是調用不了類屬性,但可呼叫類方法、例項屬性、例項方法
 * 3. 若父類和子類中 名字和引數同時相同的,會被子類重寫,反而反之,
 */

結語:

類中static==>類屬性,供類使用

類中非static==>例項屬性,供例項使用

注意:例項中的屬性和方法 不會像Pyhon語言那樣 都預設把類中的屬性和方法 給繼承了,PHP7.0預設繼承只有方法,屬性要不要繼承自己開發

二、靜態全域性變數、auto全域性變數

// test1.php
const a = '常量被匯入';
$a = '普通全域性變數被匯入';
static $b = '靜態全域性變數被匯入';
global $c;
$c = 'global全域性變數被匯入';
// 此為 test.php檔案
// 測試 靜態全域性變數和auto全域性變數
include_once 'test1.php';
// 網上說:靜態全域性變數,被侷限於那個檔案內,但我不管咋測試都是被匯入
print_r(a.PHP_EOL);
print_r($a.PHP_EOL);
print_r($b.PHP_EOL);
print_r($c);
/*
result:
    常量被匯入
    普通全域性變數被匯入
    靜態全域性變數被匯入
    global全域性變數被匯入
*/

結語:

網上說的不一定是真的,需要自己驗證

三、static::、self::的區別

class A
{
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        self::who(); //AAA
//        static::who(); //ABB
    }
}
A::test();

class B extends A
{
    public static function who() {
        echo __CLASS__;
    }
}
B::test();

class C extends B
{

}
C::test();
/**
 * 若無重寫類屬性或類方法:
 *    self和static的指向是一樣的
 * 若有重寫:
 *     self ==> 指向當前類,類似於直接使用類名 那為什麼不使用直接類名而使用self?圖省力
 *     static ==> 指向最後一次重寫的類,後期繫結
 */