新しい自己対新しい静的


513

PHP 5.3ライブラリをPHP 5.2で動作するように変換しています。私の邪魔になる主なものはのような遅い静的バインディングの使用です、return new static($options);これをに変換するreturn new self($options)と同じ結果が得られますか?

違いは何であるnew selfとはnew static

回答:


890

同じ結果が得られますか?

あんまり。ただし、PHP 5.2の回避策はわかりません。

違いは何であるnew selfとはnew static

selfnewキーワードが実際に記述されているのと同じクラスを指します。

static、PHP 5.3の新しい静的バインディングでは、メソッドを呼び出した階層内のクラスを指します。

次の例では、はB両方のメソッドをから継承しAます。self呼び出しがバインドされているAそれはで定義されているためAのに対し、第1の方法の実装staticと呼ばれるクラスにバインドされている(も参照get_called_class())。

class A {
    public static function get_self() {
        return new self();
    }

    public static function get_static() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A

理にかなっています。最善の策は、遅延静的バインディングを使用している関数にクラス名を渡して、新しい$ className($ options);を返すことだと思います。
マイク

12
クラス名を「渡す」必要はありませんget_called_class()。いつでも行うことができます。これはと実質的に同じですが__CLASS__、LSB互換です。
シャドウハンド

7
get_called_classは<PHP5.3には存在しません。したがって、PHP5.2でインスタンス化されたオブジェクトのクラス名を取得する場合、この関数は、ライブラリをPHP 5.3からPHP 5.2に変換しようとしても役に立ちません
txwikinger

2
self :: theFunction()として呼び出された関数は、「物理的に属しているクラスのコンテキストで実行します」のように動作します。static :: theFunction()として呼び出された関数は、「実際には外部の世界から呼び出されたクラスのコンテキストで実行します」のように動作します。(継承シナリオを想定)。ありがとう
Shubhranshu

2
私の頭の中では、私は直感的なものは何でも取り、それを逆にします。あなたはネーミングに基づいて考え、selfそれ自体を返し、staticオーバーライドできないものを返します...しかし、見た目は逆です。PHPの命名、規則、全体的なスタイルに感心するのを止めることはありません。-_-
ahnbizcad

23

このコードのメソッドが静的でない場合は、を使用して5.2で回避策を得ることができますget_class($this)

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

結果:

string(1) "B"
string(1) "B"

17
メソッドが静的でない場合、遅延静的バインディングは完全に無関係になります。
BoltClock

1
たとえば、「copy」メソッドで使用できます。この場合、オブジェクトはを使用せずにコピーされますがclone、プロパティを再作成して設定するだけです。$copy = new static(); $copy->set($this->get()); return $copy;
MariusBalčytis12年

9
@BoltClock確かに違いますか?あなたがサブクラスのインスタンスメソッド内からオーバーライドされた静的メソッドを呼び出している場合は、あなたの好みself::やはstatic::その静的メソッドの基本クラスのサブクラスかのバージョンが使用されているかどうかに影響を与えるために起こっています。そのような状況が本質的に悪い習慣を示していると考える何らかの理由がない場合(そして、これがそうあるべき理由は何も見当たらない)、との選択はself::static::非静的メソッド内と同じくらい適切です。静的メソッド。私はあなたのコメントを誤解しましたか、それとも私たちが単に間違っているのですか?
マークアメリー

4
@Mark Amery:うーん、そのことは考えていなかった。あなたは絶対的に正しいです。問題のインスタンスメソッドでは静的メソッドが呼び出されないと想定していましたが、あなたの例に基づいて、それが非常に単純な仮定であることがわかります。
BoltClock

遅延静的バインディングdoc => php.net/manual/en/language.oop5.late-static-bindings.php
DevWL

7

他の回答に加えて:

static ::はランタイム情報を使用して計算されます。

つまりstatic::、プロパティの値が次の理由により、クラスのプロパティでは使用できません。

コンパイル時に評価できなければならず、実行時の情報に依存してはなりません。

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

使用する self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

@Grapestainがコメントで言及されているように、オブジェクトがインスタンス化される前の早い段階でエラーが発生したことは、私が作成したコードの致命的なエラーコメントには示されていません。


4
public $name = static::class;例に示されているように、エラーは7 行目ではなく2行目にスローされることに注意してください。「static :: classはコンパイル時のクラス名解決に使用できません」というエラーは、PHPクラスのコンパイル時に$ nameフィールドにアクセスしようとしたところではなく、はるか以前に問題があることを示しています。最初の例では、7行目(または6行目)には到達しません。
sbnc.eu 2019

@Grapestain例で行ったコメントは、最終結果を示すためのものであり、実際にエラーが発生した場所を示すものではありません。しかし、とにかくそれを指摘してくれてありがとう。
雨の

そうです、私は批判するつもりはありませんでした。他の人に役立つことを願って、最初に私を混乱させた理由を明確にしただけです。とにかく役立つ例!
sbnc.eu 2019
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.