久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

PHP中的static

 硬核項(xiàng)目經(jīng)理 2021-05-31

PHP中的static

關(guān)于靜態(tài)變量和方法的問(wèn)題也是面試中經(jīng)常會(huì)出現(xiàn)的問(wèn)題,這種問(wèn)題多看手冊(cè)搞明白原委就能解決,,只是確實(shí)關(guān)于靜態(tài)變量的問(wèn)題還是比較繞的,,這里我們就結(jié)合手冊(cè)用實(shí)際的代碼來(lái)看!


class Test
{
static $v = 'a';

static function showV()
{
echo self::$v;
}

function showVV()
{
echo self::$v;
}

static function showVVV()
{
// $this->showVV(); // 會(huì)直接報(bào)錯(cuò)
}
}

先準(zhǔn)備一個(gè)類(lèi),,這里面有靜態(tài)變量,、靜態(tài)方法,其中showV()方法是靜態(tài)方法調(diào)用靜態(tài)變量,,showVV()方法是普通方法調(diào)用靜態(tài)變量,,showVVV()方法是普通方法調(diào)用靜態(tài)方法。

從注釋中可以看出第一個(gè)問(wèn)題,,普通方法使用$this調(diào)用靜態(tài)方法會(huì)報(bào)錯(cuò),,也就是說(shuō),$this這個(gè)東東對(duì)于一切靜態(tài)的東西都是不友好的,,不信您打開(kāi)注釋試試,,也可以去調(diào)用靜態(tài)的$v變量,直接就是語(yǔ)法錯(cuò)誤的提示,。

接下來(lái),,我們實(shí)例化類(lèi),并開(kāi)始一些測(cè)試

$t = new Test();
$t->showV();
//echo $t->v; // 報(bào)異常
echo Test::$v;
//Test::showVV(); // 報(bào)異常
$t->showVV();
  • 1行:實(shí)例化的類(lèi)直接調(diào)用showV(),,這是沒(méi)問(wèn)題的,,靜態(tài)方法可以通過(guò)普通的方式調(diào)用,當(dāng)然我們正規(guī)的應(yīng)該是使用Test::showV()來(lái)進(jìn)行調(diào)用,,注意這里面試的時(shí)候會(huì)是坑

  • 2行:正常調(diào)用

  • 2行:直接->v是不行的,,方法可以進(jìn)行普通調(diào)用,但屬性不行

  • 3行:用靜態(tài)調(diào)用的方式是沒(méi)問(wèn)題的

  • 4行:正常獲取靜態(tài)變量

  • 5行: 使用::當(dāng)然不能調(diào)用非靜態(tài)方法啦

  • 6行:正常方法中可以使用靜態(tài)變量

那么問(wèn)題來(lái)了,,靜態(tài)方法中不能使用$this,,如何獲得變量?jī)?nèi)容呢?請(qǐng)參考單例模式,,將來(lái)我們會(huì)在設(shè)計(jì)模式的系列文章中講到,,這里先賣(mài)個(gè)關(guān)子,大家也可以自己研究下,。

上面是正常來(lái)說(shuō)一些比較簡(jiǎn)單的靜態(tài)屬性和方法的演示,,接下來(lái)好玩的東西就來(lái)了。

初始化特性

class Calculate
{
function cacl()
{
static $a = 1;
echo $a;
$a++;
}

static function cacl2()
{
static $a = 1;
echo $a;
$a++;
}

static $b = 1;

static function cacl3()
{
        echo self::$b;
        self::$b++;
}
}

$calculate = new Calculate();
$calculate->cacl(); // 1
$calculate->cacl(); // 2

Calculate::cacl2(); // 1
Calculate::cacl2(); // 2

Calculate::cacl3(); // 1
Calculate::cacl3(); // 2

看著代碼很多,其實(shí)都是在講一件事兒,,如果是普通的$a和$b,,那么每次都在重新賦值,echo出來(lái)的都是0,,但是靜態(tài)屬性可不一樣,。靜態(tài)屬性是運(yùn)行時(shí)計(jì)算的,只在第一次賦值的時(shí)候是真正的賦值操作,,而后并不會(huì)進(jìn)行賦值,,可以相當(dāng)于這一行代碼不存在。

**靜態(tài)變量只在局部的作用域中存在,,離開(kāi)這個(gè)作用域也不會(huì)丟失,,當(dāng)然也不能再次初始化。**學(xué)過(guò)前端的同學(xué)一定會(huì)拍案而起,,這不是閉包的作用域嘛,??確實(shí)很像,,而且用處也非常像,,比如我們做一個(gè)遞歸:

function test1()
{
static $count = 0;

$count++;
echo $count;
if ($count < 10) {
test();
}
$count--;
}

test1();

在不了解static之前,結(jié)束遞歸我們可能需要給方法傳遞一個(gè)數(shù)字進(jìn)來(lái),,但現(xiàn)在似乎是不需要了,,使用內(nèi)部的靜態(tài)變量就可以解決了。

引用對(duì)象問(wèn)題


class Foo
{
public $a = 1;
}

function getRefObj($o)
{
static $obj;
var_dump($obj);
if (!isset($obj)) {
$obj = &$o;
}
$obj->a++;
return $obj;
}

function getNoRefObj($o)
{
static $obj;
var_dump($obj);
if (!isset($obj)) {
$obj = $o;
}
$obj->a++;
return $obj;
}

$o = new Foo;
$obj1 = getRefObj($o); // NULL
$obj2 = getRefObj($o); // NULL

$obj3 = getNoRefObj($o); // NULL
$obj4 = getNoRefObj($o); // Foo

又是一大串代碼,,啥也不說(shuō),,先復(fù)制下來(lái)運(yùn)行一下看看結(jié)果是不是一樣。在使用引用對(duì)象時(shí),,我們賦值的是內(nèi)存引用地址,。但是同樣的原因,靜態(tài)屬性是運(yùn)行時(shí)產(chǎn)生的,,而引用地址不是靜態(tài)地存儲(chǔ),,于是,賦不上值了唄,,永遠(yuǎn)會(huì)是NULL,。不信你接著用getRefObj()再生成幾個(gè)試試,。實(shí)際應(yīng)用中反正要記住,,這種情況下千萬(wàn)不要把引用值賦給靜態(tài)變量就行了,而上面原因的理解確實(shí)還是比較繞的,,能講明白最好,,講不明白就記住這個(gè)事兒。

后期靜態(tài)綁定


class A
{
static function who()
{
echo __CLASS__ . "\n";
}

static function test()
{
self::who();
}
}

class B extends A
{
static function who()
{
echo __CLASS__ . "\n";
}
}

B::test(); // A

先看這一段,使用self輸出的結(jié)果會(huì)是A,,但如果使用普通的類(lèi)實(shí)例化,,并且使用普通方法的話,輸出的會(huì)是B,,大家可以嘗試下,。原因呢,就是self是取決于當(dāng)前定義方法所在的類(lèi),。這就是靜態(tài)屬性方法的另一大特點(diǎn),,不實(shí)例化,跟隨著類(lèi)而不是實(shí)例,。

class A{...},,這個(gè)東西叫做類(lèi),是對(duì)現(xiàn)實(shí)的抽象,,我們可以理解為一個(gè)模板,,這里面的東西是假的,沒(méi)有生命的,。$a = new A了之后,,這個(gè)$a才是對(duì)象,相當(dāng)于是復(fù)制一了個(gè)模板做了一個(gè)真的東西出來(lái),,是有生命的,。就好像我們做一個(gè)錘子,需要一個(gè)模具,,這玩意就是類(lèi),,然后澆鑄金屬后成型拿出來(lái),這玩意就是對(duì)象,。一個(gè)對(duì)象有真正的內(nèi)存地址空間的,。

非靜態(tài)的屬性和方法是在對(duì)象中的,是我們澆進(jìn)去的金屬,。也就是new了之后才有的東西,,而靜態(tài)屬性和方法是依附于class A的,是運(yùn)行時(shí)進(jìn)行編譯讀取的,。

現(xiàn)在我們回過(guò)頭來(lái)看最早的例子,,普通方法中調(diào)用靜態(tài)方法或變量,實(shí)際上就是在這個(gè)實(shí)例化對(duì)象中調(diào)用了Test::showV(),,只是我們使用了self關(guān)鍵字而已,。依然是走的靜態(tài)過(guò)程而不是這個(gè)對(duì)象中真的包含了showV()這個(gè)方法,因此,,$this當(dāng)然取不到啦,!

那么,,如何讓父類(lèi)A中test()方法去調(diào)用到子類(lèi)的who()方法呢?


class AA
{
static function who()
{
echo __CLASS__ . "\n";
}

static function test()
{
static::who();
}
}

class BB extends AA
{
static function who()
{
echo __CLASS__ . "\n";
}
}

BB::test(); // BB

沒(méi)錯(cuò),,使用static::關(guān)鍵字這種形式調(diào)用,,static表示運(yùn)行最初時(shí)的類(lèi),不是方法定義時(shí)的類(lèi),。這樣就完成了后期靜態(tài)綁定,。另外,parent::和self::是會(huì)轉(zhuǎn)發(fā)這個(gè)鏈條的,。


class AAA
{
public static function foo()
{
static::who();
}

public static function who()
{
echo __CLASS__ . "\n";
}
}

class BBB extends AAA
{
public static function test()
{
        AAA::foo();
parent::foo();
self::foo();
}

public static function who()
{
echo __CLASS__ . "\n";
}
}

class CCC extends BBB
{
public static function who()
{
echo __CLASS__ . "\n";
}
}

CCC::test(); // AAA,、CCCCCC

  • CCC繼承了BBB,,BBB繼承了AAA

  • 在AAA中的foo()方法使用了static::who()來(lái)調(diào)用who()方法

  • BBB中的test()執(zhí)行了三種調(diào)用

  • 結(jié)果是parent::foo()和self::foo()都將CCC傳遞了過(guò)去,,最后使用的是CCC的who()方法

這個(gè)例子看著很繞,,但其實(shí)結(jié)論就一個(gè),,如果父類(lèi)使用了static關(guān)鍵字來(lái)調(diào)用父子類(lèi)都有的內(nèi)容,那么就是以哪個(gè)子類(lèi)在外面進(jìn)行調(diào)用了為準(zhǔn),,就像普通類(lèi)的方法調(diào)用 一樣,。反過(guò)來(lái),self就是以這個(gè)self關(guān)鍵字所在的類(lèi)為準(zhǔn),。

說(shuō)了這么多,,也算是把static靜態(tài)的特性講解的差不多了。在實(shí)際應(yīng)用中還是要綜合考慮,,不能因?yàn)殪o態(tài)屬性方便就全都使用靜態(tài)屬性和方法或者完全不使用,,還是要結(jié)合各路業(yè)務(wù)需求進(jìn)行取舍。

具體代碼: https://github.com/zhangyue0503/php/blob/master/newblog/php-static.php

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多