LoginSignup
47
33

More than 5 years have passed since last update.

PHP 静的メソッドのオーバーライドと遅延静的束縛

Posted at

PHPを再勉強中。

PHPでは親クラスの静的メソッドを子クラスでオーバーライドすることができます。
でもちょっと普通に期待する動作とは違うので注意が必要みたい。

サンプル

test1.php
<?php

# 親クラス
class MyParent
{
    static function foo()
    {
        return "Parent";
    }

    static function bar()
    {
        echo self::foo() . PHP_EOL;
    }
}

# 子クラス
class MyChild extends  MyParent
{
    # 親クラスのメソッドをオーバーライド
    static function foo()
    {
        return "Child";
    }
}

MyParent::bar();    # <= "Parent"と出力してほしい
MyChild::bar();     # <= "Child"と出力してほしい

親クラスの静的メソッドfoo()を子クラスでオーバーライドしています。foo()は親クラスで定義された静的メソッドbar()から呼ばれます。静的でない通常のメソッドであれば、子クラスからbar()を呼び出せば、bar()からはオーバーライドされた子クラスのfoo()が仮想メソッドとして呼ばれます。しかし静的メソッドに対して同様のことを実行すると、期待はずれの結果になります。

実行結果

$ php test1.php
Parent
Parent

子クラスでオーバーライドしたfoo()が呼ばれず、親クラスのfoo()が呼ばれています。

子クラスから親クラスの静的メソッドを呼び出した場合、そのメソッドは親クラスのコンテキスト(selfが親クラスを指す)で実行されてしまうようです。そのため、子クラスから呼び出した親クラスの静的メソッド内で子クラスでオーバーライドされたメソッドを呼び出そうとしても、仮想メソッドとしては機能せず親クラスで定義されたものが呼ばれる結果になります。

PHP(5.3移行)にはこれを回避するために、遅延静的束縛という仕組みが用意されています。

参考 : 遅延静的束縛 (Late Static Bindings)

上のプログラムを遅延静的束縛を利用したものに書き換えてみます。

test2.php
<?php

# 親クラス
class MyParent
{
    static function foo()
    {
        return "Parent";
    }

    static function bar()
    {
        echo static::foo() . PHP_EOL;
    }
}

# 子クラス
class MyChild extends  MyParent
{
    # 親クラスのメソッドをオーバーライド
    static function foo()
    {
        return "Child";
    }
}

MyParent::bar();    # <= "Parent"と出力してほしい
MyChild::bar();     # <= "Child"と出力してほしい

bar()内でfoo()を呼び出すさい、静的メンバを参照するさいのselfstaticと書き換えただけです。(このselfstaticというのは定数? 構文?よく判らない)
static::hogehogeとすると定義されたクラスではなく呼び出されたクラスのコンテキストでhogehogeが探索されるようになります。これを遅延静的束縛という(らしいです)。

実行結果

$ php test2.php
Parent
Child

期待通りの結果になりました。

47
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
33