PHPの遅延静的バインディングとは正確には何ですか?


回答:


198

PHPマニュアルの「レイトスタティックバインディング」を必ずお読みください。ただし、簡単にまとめておきます。

基本的に、selfキーワードは継承の同じルールに従っていないという事実に要約されます。 self常にそれが使用されるクラスに解決されます。つまり、親クラスでメソッドを作成し、それを子クラスから呼び出すと、self期待どおりに子を参照できなくなります。

レイトスタティックバインディングでは、staticキーワードの新しい使用方法が導入され、この特定の欠点に対処しています。を使用staticすると、最初に使用したクラス、つまり ランタイムクラスに「バインド」します。

これらは、その背後にある2つの基本的な概念です。方法selfparentおよびstatic動作中の操作staticは微妙な場合があるため、詳細に進むのではなく、マニュアルページの例を検討することを強くお勧めします。各キーワードの基本を理解したら、どのような結果が得られるかを確認するには、例が非常に必要です。


私はこの記事が本当に便利で説明的であるとわかりました、チェックしてください[リンク](techflirt.com/tutorials/oop-in-php/late-static-binding.html
Sadegh Shaikhi

「... selfキーワードは継承のルールに従っていません。self常に、それが使用されるクラスに解決されます。」-これはself、非静的メソッドの場合と同様に、を介して子オブジェクトから親の静的メソッドを呼び出せないという意味ではありません。あなたは多分正しいことを意味するかもしれませんが、それを言い換える必要があります。static::代わりにを使用してどのメンバーを参照するかを決定できるので、子が同じ名前のメンバーを持っている場合にのみ、すべてが本当に重要です。
DanMan 2018年

81

PHPから:Late Static Bindings-Manual

PHP 5.3.0以降、PHPは遅延静的バインディングと呼ばれる機能を実装しています。これは、静的継承のコンテキストで呼び出されたクラスを参照するために使用できます。

レイトスタティックバインディングは、実行時に最初に呼び出されたクラスを参照するキーワードを導入することで、この制限を解決しようとします。...新しいキーワードを導入せず、static予約済みの使用を決定しました。

例を見てみましょう:

<?php
    class Car
    {
        public static function run()
        {
            return static::getName();
        }

        private static function getName()
        {
            return 'Car';
        }
    }

    class Toyota extends Car
    {
        public static function getName()
        {
            return 'Toyota';
        }
    }

    echo Car::run(); // Output: Car
    echo Toyota::run(); // Output: Toyota
?>

レイトスタティックバインディングは、最後の「非転送呼び出し」で指定されたクラスを格納することで機能します。静的メソッド呼び出しの場合、これは明示的に名前が付けられたクラスです(通常は::演算子の左側にあるクラス)。非静的メソッド呼び出しの場合、それはオブジェクトのクラスです。「転送コールは、」によって導入された静的なの一つでありself::parent::static::、、または、クラス階層に上がる場合forward_static_call()。この関数get_called_class()を使用して、呼び出されたクラスの名前の文字列を取得し、static::そのスコープを紹介できます。


1
この投稿は、引用マーカーなしのphp.net記事のそのままのコピーの約80%です。
WoodrowShigeru

22

明確な動作はありません。

次のコードは「alphabeta」を生成します。

class alpha {

    function classname(){
        return __CLASS__;
    }

    function selfname(){
        return self::classname();
    }

    function staticname(){
        return static::classname();
    }
}

class beta extends alpha {

    function classname(){
        return __CLASS__;
    }
}

$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta

ただし、クラス名関数の宣言をベータクラスから削除すると、結果として「alphaalpha」が得られます。


1
非常に素晴らしい。PHPマニュアルにも同じことが示されていますが、これははるかに明確です。参考までに:php.net/manual/en/language.oop5.late-static-bindings.php(例4を参照)
musicin3d

11

「PHPマスターが最先端のコードを書く」という本から引用しています。

レイトスタティックバインディングは、php 5.3で導入された機能です。これにより、親クラスから静的メソッドを継承し、呼び出される子クラスを参照できます。

つまり、静的メソッドを持つ抽象クラスを作成し、self :: method()の代わりにstatic :: method()表記を使用して子クラスの具象実装を参照できます 。

公式のphpドキュメントもご覧ください。http//php.net/manual/en/language.oop5.late-static-bindings.php


レイトスタティックバインディングを説明する最も明確な方法は、簡単な例です。以下の2つのクラス定義を見て、読んでください。

class Vehicle {
    public static function invokeDriveByStatic() {
        return static::drive(); // Late Static Binding
    }
    public static function invokeStopBySelf() {
        return self::stop(); // NOT Late Static Binding
    }
    private static function drive(){
        return "I'm driving a VEHICLE";
    }
    private static function stop(){
        return "I'm stopping a VEHICLE";
    }
}

class Car extends Vehicle  {
    protected static function drive(){
        return "I'm driving a CAR";
    }
    private static function stop(){
        return "I'm stopping a CAR";
    }
}

親クラス(車両)と子クラス(車)があります。親クラスには2つのパブリックメソッドがあります。

  • invokeDriveByStatic
  • invokeStopBySelf

親クラスには、2つのプライベートメソッドもあります。

  • drive
  • stop

子クラスは2つのメソッドをオーバーライドします。

  • drive
  • stop

次に、パブリックメソッドを呼び出します。

  • invokeDriveByStatic
  • invokeStopBySelf

自問してください:どのクラスがinvokeDriveByStatic/を呼び出しますinvokeStopBySelfか?親または子クラス?

以下を見てください:

// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE

// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR

// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE

staticキーワードはシングルトンデザインパターンで使用されています。リンクを参照してください:https : //refactoring.guru/design-patterns/singleton/php/example


7

違いを示す最も簡単な例。
注:self :: $ c

class A
{
    static $c = 7;

    public static function getVal()
    {
        return self::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 7

遅い静的バインディング、static :: $ cに注意

class A
{
    static $c = 7;

    public static function getVal()
    {
        return static::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 8

4

例えば:

abstract class Builder {
    public static function build() {
        return new static;
    }
}

class Member extends Builder {
    public function who_am_i() {
         echo 'Member';
    }
}

Member::build()->who_am_i();

4

「なぜこれを使うの?」から見てみると パースペクティブ、それは基本的に静的メソッドが解釈/実行されているコンテキストを変更する方法です。

ではself、コンテキストは、最初にメソッドを定義したものです。でstatic、それはあなたがそれを呼び出しているものです。


1

また、子クラスの静的変数を更新するかどうかも確認してください。子Bが子Cを更新する、この(やや)予期しない結果が見つかりました。

class A{
    protected static $things;
}

class B extends A {
    public static function things(){
        static::$things[1] = 'Thing B';
        return static::$things; 
    }
}

class C extends A{
    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}

print_r(C::things());
// Array (
//   [2] => Thing C
// )

B::things();

print_r(C::things()); 
// Array (
//    [2] => Thing C
//    [1] => Thing B
// )

たとえば、各子クラスで同じ変数を宣言することで修正できます。

class C extends A{
    protected static $things; // add this and B will not interfere!

    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.