web-dev-qa-db-ja.com

double-colon(::)を使用した非静的メソッドの呼び出し

メソッドstatic(class :: method)の構文で非静的メソッドを使用できないのはなぜですか?何らかの構成の問題ですか?

class Teste {

    public function fun1() {
        echo 'fun1';
    }
    public static function fun2() {
        echo "static fun2" ;
    }
}

Teste::fun1(); // why?
Teste::fun2(); //ok - is a static method
47
NakaBr

PHPは、静的メソッドと非静的メソッドで非常に緩やかです。ここで気づかないことの1つは、非静的メソッドを呼び出す場合、nsクラスの非静的メソッド内からC$this内のnsCのインスタンスを参照します。

class A 
{
    public function test()
    {
        echo $this->name;
    }
}

class C 
{
     public function q()
     {
         $this->name = 'hello';
         A::test();
     }
}

$c = new C;
$c->q();// prints hello

厳密なエラー報告がある場合、これは実際には何らかの種類のエラーですが、そうでない場合はそうではありません。

33
davidtbernal

これは、PHPの既知の「癖」です。しばらく前に実際にオブジェクトをインスタンス化したかどうかを判断するための逆伝播を防ぐように設計されています(PHPはコンパイルされず、解釈されます)。ただし、非静的メンバーにアクセスするオブジェクトがインスタンス化されていない場合、スコープ解決演算子を介して致命的なエラーが発行されます。

PHP.net提供:

class User {
    const GIVEN = 1;  // class constants can't be labeled static nor assigned visibility
    public $a=2;
    public static $b=3;

    public function me(){
        echo "print me";
    }
     public static function you() {
        echo "print you";
    }
}

class myUser extends User {
}

// Are properties and methods instantiated to an object of a class, & are they accessible?
//$object1= new User();        // uncomment this line with each of the following lines individually
//echo $object1->GIVEN . "</br>";        // yields nothing
//echo $object1->GIVE . "</br>";        //  deliberately misnamed, still yields nothing
//echo $object1->User::GIVEN . "</br>";    // yields nothing
//echo $object1->a . "</br>";        // yields 2
//echo $object1->b . "</br>";        // yields nothing
//echo $object1->me() . "</br>";        // yields print me
//echo $object1->you() . "</br>";        // yields print you

// Are  properties and methods instantiated to an object of a child class,  & are accessible?
//$object2= new myUser();        // uncomment this line with each of the following lines individually
//echo $object2->GIVEN . "</br>";        // yields nothing
//echo $object2->a . "</br>";        // yields 2
//echo $object2->b . "</br>";        // yields nothing
//echo $object2->me() . "</br>";        // yields print me
//echo $object2->you() . "</br>";        // yields print you

// Are the properties and methods accessible directly in the class?
//echo User::GIVEN . "</br>";        // yields 1
//echo User::$a . "</br>";            // yields fatal error since it is not static
//echo User::$b . "</br>";            // yields 3
//echo User::me() . "</br>";        // yields print me
//echo User::you() . "</br>";        // yields print you

// Are the properties and methods copied to the child class and are they accessible?
//echo myUser::GIVEN . "</br>";        // yields 1
//echo myUser::$a . "</br>";        // yields fatal error since it is not static
//echo myUser::$b . "</br>";        // yields 3
//echo myUser::me() . "</br>";        // yields print me
//echo myUser::you() . "</br>";        // yields print you
?>
25
David Titarenco

これはPHP 4の後方互換性です。PHP 4では、オブジェクトメソッドと静的クラスメソッドとして記述されたグローバル関数を区別できませんでした。作業。

ただし、PHP 5- http://php.net/oop5 を使用したオブジェクトモデルの変更に伴い、静的キーワードが導入されました。

そして、PHP 5.1.3から、次のようなものに関する適切で厳密な標準警告が表示されます。

厳格な標準:非静的メソッドFoo :: bar()を静的に呼び出さないでください

および/または:

厳格な標準:非静的メソッドFoo :: bar()は、互換性のないコンテキストから$ thisを想定して静的に呼び出されるべきではありません

開発セットアップで有効にする必要があります。そのため、言語が十分に異なることができなかったため、実行時に「定義」された時点との後方互換性にすぎません。

最近ではコード内で既に定義できますが、それでも「間違った」と呼んでもコードは壊れません。

エラーメッセージをトリガーし、異なるPHPバージョン: http://3v4l.org/8WRQH で変更された動作を示すデモ

16
hakre

PHP 4には(関数宣言コンテキスト内に)静的キーワードはありませんでしたが、::を使用してメソッドを静的に呼び出すことができました。これは、後方互換性のためにPHP 5に続きました。

13
webbiedave

これは可能ですが、fun1()という関数で$thisを使用すると、コードでエラーが発生します

6
Jake N

警告PHP 7、非静的メソッドの静的呼び出しは非推奨であり、E_DEPRECATED警告を生成します。非静的メソッドの静的呼び出しのサポートは将来削除される可能性があります。

リンク

6
Malus Jan

ほとんどの言語では、インスタンスメソッドを実行するためにクラスのインスタンスが必要です。スコープ解決演算子を使用してインスタンスメソッドを呼び出すと、PHPは一時インスタンスを作成します。

1
Jacob Relkin

なぜPHPがこれを許可しているのかはわかりませんが、習慣にするのは好ましくありません。クラスの非静的プロパティにアクセスしようとしないため、この例は機能します。

次のような単純なもの:

<?php
class Foo {

    private $color;

    public function bar() {
        echo 'before';
        $this->color = "blue";
        echo 'after';
    }
}

Foo::bar();

致命的なエラーになります

1
brian_d

クラス内から非静的メソッドself :: test()を呼び出すと、Class :: test()を呼び出すときのように、厳格な標準の警告が発行されないことに気付きました。私のクラスは拡張されていないため(PHP 5.5でテスト済み)、これはLSBに関連していないと思いますか?

0
bpile