14

バージョン5.3以降、PHPは静的メソッドの遅延バインディングをサポートしています。これは間違いなく便利な機能ですが、実際に使用する必要があるのはごくわずかです(たとえば、Active Recordパターン)。

次の例を検討してください。

1.コンビニエンスコンストラクター(::create()

class SimpleObject
{
    public function __construct() { /* ... */ }

    public static function create()
    {
        return new static; // or: return new self;
    }
}

このクラスが拡張される可能性がある場合(ただし、同じパッケージ内のどのクラスによっても拡張されない場合)、拡張を容易にするためだけに(::create()メソッドを書き直さずに、さらに重要なことに、覚えておく必要なしに)遅延静的バインディングを使用する必要があります。それをするために)?

注:このイディオムは、構築されたばかりのオブジェクトでメソッドを呼び出すことができないことを回避するために使用されますnew SimpleObject()->doStuff()。PHPでは無効です。


2.クラス定数

class TagMatcher
{
    const TAG_PATTERN = '/\<([a-z\-]+?)\>/i';

    private $subject;

    public function construct($subject) { $this->subject = $subject; }

    public function getAllTags()
    {
        $pattern = static::TAG_PATTERN;
        preg_match_all($pattern, $this->subject);
        return $pattern[1];
    }
}

この例で使用する理由static::は、前の例と同様です。これは、このクラスを拡張して定数をオーバーライドするだけで、異なる形式のタグに一致させることができるという理由だけで使用されます。


それで、それをすべてまとめると、後期静的バインディングのこれらの使用法(および同様の使用法)はやり過ぎですか?目立ったパフォーマンスの低下はありますか?また、遅延バインディングを頻繁に使用すると、オペコードキャッシュによる全体的なパフォーマンスの向上が低下しますか?

4

3 に答える 3

16

それで、それをすべてまとめると、後期静的バインディングのこれらの使用法(および同様の使用法)はやり過ぎですか?目立ったパフォーマンスの低下はありますか?また、遅延バインディングを頻繁に使用すると、オペコードキャッシュによる全体的なパフォーマンスの向上が低下しますか?

後期静的バインディングの導入により、PHPのオブジェクトモデルの欠陥が修正されました。それはパフォーマンスではなく、セマンティクスです。

たとえば、メソッドの実装でを使用しない場合は常に静的メソッドを使用するのが好き$thisです。メソッドが静的であるからといって、それをオーバーライドしたくないという意味ではありません。PHP 5.3より前の動作では、静的メソッドをオーバーライドしてもエラーはフラグ付けされませんでしたが、PHPは先に進み、親のバージョンをサイレントに使用していました。たとえば、以下のコードは、PHP5.3より前の「A」を出力します。これは非常に予想外の動作です。

後期静的バインディングはそれを修正し、同じコードが「B」を出力するようになりました。

<?php
class A {
  public static function who() {
    echo __CLASS__;
  }
  public static function test() {
    static::who();
  }
}

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

B::test();
?>
于 2009-11-29T20:23:19.180 に答える
3

静的メソッド(アーリーバウンドまたはレイトバウンド)は密結合を作成し、(したがって)妥当性を低下させます。いくつかの静的呼び出しを使用せずに、PHPで大規模なプログラムを作成できます。私にとって、後期静的メソッドは機能ではありません。

マルコ・デマイオの質問に答えるために編集してください、静的な方法はどのようにテスト容易性を減らすのですか?

これがすべて明らかな場合は申し訳ありませんが、静的メンバー(データとメソッドの両方)有用であり、責任を持って使用しても害はありません。私はそれらの一般的な誤用をほのめかしていました。

SQLデータベースを使用するWebアプリケーションがあるとします。ビジネス・オブジェクトは、静的インターフェースまたはポリモーフィズムを使用してデータを取得する場合があります。また

class MyBusinessObject
extends...
{
  public function doThisOrThat(...)
  {
    $results = db::query('sql string...');
    ...
  }
}

また

class MyBusinessObject
extends...
{
  public function __construct(dbconn $db)
  {
    $this->db = $db;
  }
  private $db;
  public function doThisOrThat(...)
  {
    $results = $this->db->query('sql string...');
    ...
  }
}

後者の方がテストが簡単です(たとえば、このような入力から構築されたSQL文字列がそのようなものであることをテストしたい)dbconn。意味を変更するよりも、インターフェイスの別の実装を作成する方が簡単だからです。のdb::。なぜあなたはどちらかが欲しいのですか?これは、SQL作成の動作をテストするために実際のデータベースは必要ないためです。実際、実際のデータベースがなくてもテストする方が簡単です。また、テストがCUT(Code Under Test)の別の側面に関係している場合は、SQLコンシューマーをスタブアウトする方が簡単です。

テストは常に、その共同作業者についてテストされたコードに嘘をつくことを意味し、静的インターフェイス(「ダブルコロン」または「クアドリドット」)を控えることは、嘘が大規模な手術である必要がないことを意味します。本番コードほど、テスト結果の意味は低くなります。

于 2009-11-29T20:20:41.483 に答える
1

遅い静的バインディングを使用する必要があると思うのは、PHPUnitを使用した単体テスト用の静的メソッドのモックを許可することです。私が抱えている問題は、モックを許可するためにコードを厳密に変更するのは好きではないということですが、それを乗り越えることはできます。

ただし、あなたの質問に答えるために、これがもたらすパフォーマンスコストが何であれ、ほとんどのプログラムランタイムと比較すると見劣りするでしょう。言い換えれば、それは目立った違いを生むことはありません。

于 2010-11-24T00:13:03.450 に答える