簡體   English   中英

PHP - 靜態 vs 實例方法

[英]PHP - Static vs Instance Method

我有點困惑,因為我在 PHP 的 OOP 方面沒有太多經驗。 我總是聽說使用實例方法比使用靜態方法更好,這是為什么呢?

我需要一個深刻的答案和解釋,請。

例如,為什么下面應該使用實例方法來完成?

控制器:

public function getProperty($id){
        $property = Property::getProperty($id);
        return $property;
}

模型:

public static function getProperty($id){
        //$query = DB::table('properties')...
        //Some Code;
        return $query;         
}

我正在閱讀有關 setter/getter、實例與靜態等的信息。但我需要一個完整的答案來了解事物的方式原因

一般來說,正如您已經說過的,實例方法是更好的做法。 這並不是說靜態方法是徹頭徹尾的邪惡,它們只是具有不同且獨特的目的。

需要注意的是用實例的方法處理,當你與對象的工作,而用靜態方法您使用的是的工作是很重要的 使用靜態方法時,您將無法訪問通常可用於實例的任何非靜態屬性。

以下面的代碼為例:

class Foo
{
    private $bar;
    private static $tavern;

    public function changeBar($value)
    {
        $this->bar = $value;
    }

    public function getBar()
    {
        return $this->bar;
    }

    public static function changeTavern($value)
    {
        self::$tavern = $value;
    }

    public static function getTavern()
    {
        return self::$tavern;
    }
}

Foo類有一個靜態屬性$tavern和一個非靜態屬性$bar

如果創建了Foo的實例,則該對象可以使用所有屬性和方法。

如果Foo被引用靜態那么只有$tavern財產, changeTavern()方法和getTavern()方法可用於

讓我們看看下面的代碼:

$foo = new Foo();
$foo->changeBar('Tipsy Turvy');
echo $foo->getBar(); // prints Tipsy Turvy

由於$fooFoo一個實例,它可以訪問整個類。 調用changeBar()將修改$bar屬性。 直接從靜態方法更改$bar屬性將觸發錯誤,因為$bar可用於對象而不是

// Calling this method would trigger an error
public static function changeBar($value)
{
    $this->bar = $value; // PHP will crash and burn if you try this.
}

如果您想從靜態方法訪問類屬性,這些屬性也必須聲明為靜態。 這將在上述類的上下文中起作用。 您還會注意到Foo的實例讀取靜態屬性沒有問題。

Foo::changeTavern('Stumble Inn');
echo Foo::getTavern(); // prints Stumble Inn
echo $foo->getTavern(); // also prints Stumble Inn

關於靜態代碼要記住的另一件事是它的行為不像一個實例。 Foo的第一個實例被構建時,屬性$bar$tavern都沒有價值。 如果您要創建Foo另一個實例,您會發現這些屬性中只有一個不再包含值。 (我相信你現在可以猜到是哪一個了。)

$anotherFoo = new Foo();
echo $anotherFoo->getBar(); // prints nothing
echo $anotherFoo->getTavern(); // prints Stumble Inn
echo Foo::getTavern(); // prints Stumble Inn

同樣,靜態代碼意味着您直接使用- 實例意味着您正在使用對象 重要的是要注意,您編寫的任何類型的類都應該具有某種狀態,都應該用作實例。

靜態類可能有點難以調試和測試。 測試可能會出現問題,因為創建新實例時靜態屬性不會更改。 調試也很困難,因為靜態屬性的值在類的所有實例中都是相同的。 對其中一個進行更改,您將對所有這些更改進行更改。 跟蹤哪個實例進行了更改是很痛苦的。

比喻地說,使用像糖這樣的靜態類 - 有節制地並且僅在必要時使用。

希望這有助於闡明這個話題。

實例方法並不比靜態方法好,它們只是為了不同地使用。 例如,將工廠方法設為非靜態是很瘋狂的。

當方法與類的當前實例有關(使用此對象的某些狀態,可能是配置參數)時,通常創建實例方法,如果它只屬於整個類,例如創建新對象,處理原語.. .

例如, ActiveRecords模式通常使用實例作為記錄的映射,因此實例方法讀取/操作記錄,以及靜態方法,如搜索、批量更新/刪除等。

我會同意克蘇魯。 使用靜態方法意味着您不需要創建類的實例來啟動函數。

我很想用一個基於他的 ActiveRecord 模式的小例子來解釋。

讓我們坐下來,我們正在使用一個表示表“訂單”的類編寫我們自己的 AR 模式,該表包含(如您想象的那樣)多個訂單記錄。

如果您使用 PDO 作為連接類,則需要在某處啟動它。 在這個例子中,初始化是在“order”類的靜態方法中啟動的。 因為在能夠查詢數據庫以獲取訂單之前,您需要能夠“運行它”。

class order {
   public $data;

   public static $connection;

   public static function dbConnect($host, $database, $username, $password)   
   {
       try {
           self::$connection = new PDO(
               'mysql:host='.host.';dbname='.database, 
               $username,
               $password
           );
       } catch (PDOException $e) {
           print "Error!: " . $e->getMessage() . "<br/>";
           die();
       }
   }

    public function getOrderById($id)
    {
        $stmt = self::$connection->prepare('SELECT * FROM orders WHERE id = :id LIMIT 1');
        $stmt->execute(
            array('id', $id)
        );

        $this->data = $stmt->fetch();
    }
}

$order::dbConnect('localhost', 'myDb', 'user', '123test');
$order1 = new Order();
$order1->getOrderById(1);

$order2 = new order();
$order2->getOrderById(2);

print_r($order1->data);

print_r($order2->data);

請忽略您可以對實際結果集進行大量優化或將其保存到實際對象的事實。 這段代碼的主要目的是解釋我何時使用靜態與實例的事實。

首先,它並不總是更好,但在大多數情況下確實如此。 不使用靜態方法有幾個原因:

  1. 如果類具有靜態方法,則更難對其進行測試
  2. 如果您希望同一方法的行為略有不同,則擴展此類會更困難
  3. 通常,您在類中的靜態方法只是使其成為全局變量的一種方式,這幾乎總是一個壞主意
  4. 如果您突然決定在靜態方法中需要一些類變量(將所有 Class::Method() 調用更改為 $c = new Class(); $c->Method()),則重構此類將變得非常糟糕

我強烈邀請您閱讀更多有關單元測試的信息。 當其他一些類將您的類與靜態方法一起使用時,將其進行測試可能是一個挑戰。

暫無
暫無

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

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