簡體   English   中英

非靜態方法中的靜態在實例之間共享

[英]Static within non-static method is shared between instances

我遇到了一些意外的行為,在對象方法中定義的靜態變量是跨實例共享的。 這可能是已知的行為,但是當我瀏覽PHP文檔時,我無法在對象方法中找到靜態定義的變量的實例。

這是我遇到的行為的減少:

<?php

class Foo {
  public function dofoo() {
    static $i = 0;
    echo $i++ . '<br>';
  }
}

$f = new Foo;
$g = new Foo;

$f->dofoo(); // expected 0, got 0
$f->dofoo(); // expected 1, got 1
$f->dofoo(); // expected 2, got 2

$g->dofoo(); // expected 0, got 3
$g->dofoo(); // expected 1, got 4
$g->dofoo(); // expected 2, got 5

現在,我希望$i每個實例的靜態,但實際上$i在實例之間共享。 對於我自己的啟發,有人可以詳細說明為什么會這樣,並在php.net上記錄它的位置?

這是靜態的定義

如果希望成員特定於對象的實例,則使用類屬性

例如

<?php

class Foo
{
    protected $_count = 0;
    public function doFoo()
    {
        echo $this->_count++, '<br>';
    }
}

編輯:好的,我將文檔鏈接到OOP靜態屬性。 但這個概念是一樣的。 如果您閱讀變量范圍文檔,您將看到:

注意 :靜態聲明在編譯時解析。

因此,當您的腳本編譯時(在執行之前),靜態是“設置”(不確定要使用的術語)。 無論您實例化多少個對象,當該函數被“構建”時,靜態變量引用與其他人相同的副本。

我同意當前的PHP文檔對於“范圍”對於非靜態方法中的靜態變量的確切含義並不十分清楚。

當然,正如hobodave所指出的那樣,“靜態” 通常意味着“每個類”,但靜態類屬性與(非靜態)方法中的靜態變量完全相同,因為后者是“范圍”的通過方法(類中的每個方法都可以有自己的靜態$ foo變量,但最多只能有一個名為$ foo的靜態類成員)。

而且我認為,雖然PHP 5的行為一致的(“靜態”總是意味着“每類一個共享實例”),它不是 PHP 能夠表現的唯一途徑。

例如,大多數人使用靜態函數變量來跨函數調用持久化狀態,對於全局函數,PHP行為正是大多數人所期望的。 因此,有可能想象一個PHP解釋器在方法調用中維護某些方法變量的狀態,並且“按實例”這樣做,這實際上是我第一次將本地方法變量聲明為靜態時也應該發生的事情。

這就是靜態,它是類的所有實例中的相同變量。

您希望編寫此代碼,以便該變量是該類實例的私有成員。

class Foo {
  private $i = 0;
  public function dofoo() {
    echo $this->i++ . '<br>';
  }
}

static關鍵字可以與變量一起使用,也可以與類方法和屬性一起使用 靜態變量是在PHP 4中引入的(我想,它可能早一些)。 PHP 5中引入了靜態類成員/方法。

因此,根據手冊,一個靜態變量

變量范圍的另一個重要特征是靜態變量。 靜態變量僅存在於本地函數作用域中,但在程序執行離開此作用域時它不會丟失其值。

這與您描述的行為一致。 如果需要每個實例變量,請使用常規類成員。

很長一段時間7年,但無論如何它在這里。

所有類都有一個默認的構造函數為什么我這樣說?!? 因為如果在構造函數中定義默認行為,則每個類的實例都會受到影響。

例:

namespace Statics;

class Foo
{
    protected static $_count;

    public function Bar()
    {
        return self::$_count++;
    }

    public function __construct()
    {
        self::$_count = 0;
    }
}

導致:

require 'Foo.php';

use Statics\Foo;

$bar = new Foo();
echo $bar->bar().'<br>';
echo $bar->bar().'<br>';
echo $bar->bar().'<br>';

$barcode = new Foo();
echo $barcode->bar().'<br>';
echo $barcode->bar().'<br>';
echo $barcode->bar().'<br>';

0
1
2
0
1
2

來自上層階級的每個新實例都將從0開始! 靜態計數行為不會在多個實例之間共享,因為它將從構造函數中指定的值開始。

如果需要跨多個實例共享數據,您需要做的就是定義一個靜態變量並在構造函數外部分配默認數據!

例:

namespace Statics;

class Foo
{
    //default value
    protected static $_count = 0;

    public function Bar()
    {
        return self::$_count++;
    }

    public function __construct()
    {
       //do something else
    }
}

導致:

require 'Foo.php';

use Statics\Foo;

$bar = new Foo();
echo $bar->bar().'<br>';
echo $bar->bar().'<br>';
echo $bar->bar().'<br>';

$barcode = new Foo();
echo $barcode->bar().'<br>';
echo $barcode->bar().'<br>';
echo $barcode->bar().'<br>';

0
1
2
3
4
5

正如您所看到的結果完全不同,類實例之間的內存空間分配是相同的,但它可以根據您定義默認值的方式產生不同的結果。

我希望它有所幫助,而不是上述答案是錯誤的,但我覺得從這個角度理解所有概念是很重要的。

此致,來自葡萄牙!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM