$ thisでselfを使用するのはいつですか?


回答:


1728

簡潔な答え

$this現在のオブジェクトを参照するために使用します。self現在のクラスを参照するために使用します。つまり、 $this->member非静的メンバーに使用self::$memberし、静的メンバーに使用します。

完全な回答

ここでの例で正しいの使用$thisself非静的及び静的メンバ変数の:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?>

ここでの例で間違ったの用法$thisself非静的および静的メンバ変数のために:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo self::$non_static_member . ' '
           . $this->static_member;
    }
}

new X();
?>

ここでの例である多型を持つ$thisメンバ関数のためには:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        $this->foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

次に、メンバー関数にを使用して多態性の動作抑制する例を示しselfます。

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        self::foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

アイデアは、現在のオブジェクトの正確なタイプが何であれ$this->foo()foo()メンバー関数を呼び出すことです。type Xしたがって、オブジェクトがの場合、それはを呼び出しますX::foo()。オブジェクトがの場合はtype Y、を呼び出しますY::foo()。しかし、self :: foo()を使用すると、X::foo()常に呼び出されます。

http://www.phpbuilder.com/board/showthread.php?t=10354489から:

http://board.phpbuilder.com/member.php?145249-laserlight


330
この答えは非常に単純化しています。他の回答で指摘されているように、現在のクラスを参照するためにselfスコープ解決演算子と共に使用され::ます。これは、静的と非静的の両方のコンテキストで実行できます。さらに、$this静的メソッドの呼び出しに使用することは完全に合法です(フィールドを参照することはできません)。
Artefacto 2010

50
5.3以降の場合は、:: selfではなくstatic ::を使用することも検討してください。そうでなければ、それはあなたに未解決の頭痛を引き起こすかもしれません、理由については以下の私の答えを見てください。
Sqoo

25
-1。この回答は誤解を招くものです。詳細については、他の回答をお読みください。
ペーチェリエ2013

6
単純化しすぎているかもしれませんが、頭を爆発させずに私の基本的なレベルの質問に答えました。さらに役立つ情報がいくつかありましたが、今のところ、クラス属性を$ this-> attribで、クラス定数をself :: constantでヒットする理由を理解しようとしています。これは私がそれをよりよく理解するのに役立ちました
MydKnight 2015

どう$this::ですか?
James

742

キーワード自己んしない、少なくともない静的メンバーにあなたを制限した方法で、「現在のクラス」に過ぎない参照してください。非静的メンバーのコンテキスト内で、現在のオブジェクトselfのvtable(vtableのwikiを参照)をバイパスする方法も提供します。を使用parent::methodName()して関数の親バージョンを呼び出すことができるのと同じように、self::methodName()を呼び出してメソッドの現在のクラス実装を呼び出すことができます。

class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();

これは出力します:

こんにちは、ルートヴィヒのオタク、
グッバイです。

sayHello()$thisポインタを使用するため、vtableを呼び出してを呼び出しますGeek::getTitle()sayGoodbye()を使用self::getTitle()しているため、vtableは使用されず、Person::getTitle()呼び出されます。どちらの場合も、インスタンス化されたオブジェクトのメソッドを処理しており$this、呼び出された関数内のポインターにアクセスできます。


3
この答えは、例外ではなく、一般的なルールから始めた場合に、さらに良いでしょう。技術的な専門知識ではなく、スタイルの問題です。これは、私がこれまでに見たself ::と$ this->の違いの最も良い例ですが、最初に概念を反証してそれを隠すのは残念です。
adjwilli 2014

3
@adjwilli:なぜその悪いスタイルなのですか?OPの期待(論文)が最初に否定(アンチテーゼ)され、それから総合的に説明されると意識を高めませんか?
2014年

1
「現在のクラス」には本当に問題があると思います。その単語の組み合わせは、「配置されているクラスself」/「クラスの定義は文字どおりの部分」と「オブジェクトのクラス」(実際にはstatic)の両方として理解できます。
Jakumi

どう$this::ですか?
James

1
@James-使用する正当な理由はありません$this::。考えられるすべてのケースは、より一般的に使用される構文ですでにカバーされています。あなたが何を意味するかに応じて、使用$this->self::またはstatic::
ToolmakerSteve

461

DO NOTを使用self::、使用static::

自己の別の側面があります::言及する価値があります。厄介なself::ことに、実行の時点ではなく定義の時点のスコープを参照します。次の2つのメソッドを持つ単純なクラスを考えてみます。

class Person
{

    public static function status()
    {
        self::getStatus();
    }

    protected static function getStatus()
    {
        echo "Person is alive";
    }

}

呼び出すPerson::status()と、「Person is alive」が表示されます。これから継承するクラスを作成するとどうなるかを考えてみましょう:

class Deceased extends Person
{

    protected static function getStatus()
    {
        echo "Person is deceased";
    }

}

呼び出しDeceased::status()では、「Person is故人」が表示されると予想されますが、呼び出し先self::getStatus()が定義されたときにスコープには元のメソッド定義が含まれているため、表示されるのは「Person is alive」です。

PHP 5.3には解決策があります。static::解決演算子の実装は、それが呼ばれるクラスのスコープにバインドされていますというのファンシーな方法である「遅延静的バインディング」。の行status()static::getStatus()と、期待どおりの結果なります。PHPの古いバージョンでは、これを行うための手がかりを見つける必要があります。

PHPのドキュメントを参照

したがって、尋ねられたとおりではない質問に答えるために...

$this->現在のオブジェクト(クラスのインスタンス)をstatic::参照し、クラスを参照


6
クラス定数についてはどうですか?
Kevin Bond

53
「Deeased :: status()を呼び出すと、「Person is deceased」が表示されます。」いいえ。これは静的関数呼び出しであるため、関連する多態性はありません。
cquezel 2013

2
PHPのすべての欠陥のうち、私はこれがまったく狂っているとは思いません。プログラマーが(vtableで検索するのではなく)現在のクラスでメソッドを指定できるようにするには、他にどのような方法がありますか?彼らが別の名前を付けていた場合(おそらく先頭のアンダースコアが付いている場合)、この機能を必要とする人々は、醜いと非難します。そうでなければ、彼らが使うかもしれない正気な名前が何であれ、メソッドディスパッチがどのように機能するかにさえ気付かない可能性が高い、「狂った」振る舞いであると批判する人々は常に簡単に混乱するでしょう。
TNE

2
例は私を混乱させているようです。私はgetStatusメソッドを、クラスではなくクラスインスタンスに対して呼び出すものと考えています。
ジャニスElmeris

1
@Sqoo- 「self ::を使用しないでください:、staticを使用してください:」は奇妙な点です。これらは意図的に同じ操作ではありません。あなたが本当にしている点は、「 'self ::'ではなく、実際のクラス名 'MyClass ::'を使用する方が明確です。つまり、の動作がself::必要な場合、それを得ることができます。紛らわしい、例えば、特定のクラス名を使用してMyClass::
ToolmakerSteve

248

self対について話しているときに何が話しているのかを本当に理解するには$this、概念レベルと実用レベルで何が起こっているのかを実際に掘り下げる必要があります。私はどの回答もこれを適切に実行しているとは本当に感じていません。

クラスオブジェクトが何であるかについて話すことから始めましょう。

クラスとオブジェクト、概念的に

だから、何であるクラスは?多くの人はそれを青写真またはオブジェクトのテンプレートとして定義します。実際、PHPのクラスについてはこちらをご覧ください。そして、それが実際にはある程度です。クラスを見てみましょう:

class Person {
    public $name = 'my name';
    public function sayHello() {
        echo "Hello";
    }
}

ご存知のように、そのクラスに呼び出されるプロパティと$nameと呼ばれるメソッド(関数)がありsayHello()ます。

それはだ非常ことに注意することが重要なクラスは静的な構造です。つまりPerson、一度定義されたクラスは、どこを見ても常に同じです。

一方、オブジェクトは、クラスのインスタンスと呼ばれるものです。つまり、クラスの「青写真」を取得し、それを使用して動的コピーを作成します。このコピーは、格納されている変数に具体的に関連付けられています。したがって、インスタンスへの変更は、そのインスタンスに対してローカルです。

$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"

演算子を使用して、クラスの新しいインスタンスを作成しますnew

したがって、クラスはグローバル構造であり、オブジェクトはローカル構造であると言います。面白い->構文については心配しないでください。少し後で説明します。

もう1つ説明する必要があるのは、インスタンスが特定のクラスであるどうかを確認できることです。インスタンスがクラスまたはの子を使用して作成された場合は、ブール値を返します。instanceof$bob instanceof Person$bobPersonPerson

状態の定義

それでは、クラスが実際に何を含んでいるかを少し掘り下げましょう。クラスに含まれる「もの」には5つのタイプがあります。

  1. プロパティ -これらは、各インスタンスに含まれる変数と考えてください。

    class Foo {
        public $bar = 1;
    }
  2. 静的プロパティ -これらは、クラスレベルで共有される変数と考えてください。つまり、各インスタンスによってコピーされることはありません。

    class Foo {
        public static $bar = 1;
    }
  3. メソッド -これらは、各インスタンスに含まれる(およびインスタンスで動作する)関数です。

    class Foo {
        public function bar() {}
    }
  4. 静的メソッド -これらはクラス全体で共有される関数です。彼らはないではないインスタンス上で、代わりにのみ静的プロパティを操作します。

    class Foo {
        public static function bar() {}
    }
  5. 定数 -クラス解決済み定数。ここではこれ以上詳しく説明しませんが、完全を期すために追加します。

    class Foo {
        const BAR = 1;
    }

したがって、基本的に、情報が共有されている(したがって静的)か共有されていない(したがって動的)かを識別する静的に関する「ヒント」を使用して、クラスおよびオブジェクトコンテナに情報を格納しています。

状態と方法

メソッドの内部では、オブジェクトのインスタンスは$this変数によって表されます。そのオブジェクトの現在の状態がそこにあり、プロパティを変更(変更)すると、そのインスタンスが変更されます(他のインスタンスは変更されません)。

メソッドが静的に呼び出された場合、$this変数は定義されていません。これは、静的呼び出しに関連付けられたインスタンスがないためです。

ここで興味深いのは、静的呼び出しがどのように行われるかです。それでは、どのように状態にアクセスするかについて話しましょう:

アクセス状態

その状態を保存したので、それにアクセスする必要があります。これは少しトリッキー(または得ることができる方法インスタンス/クラス(通常の関数呼び出しから、またはグローバルスコープから言う)の外側、およびインスタンスの内部から:ので、2つの視点にのスプリットこれを聞かせて、より多くのビットより) / class(オブジェクトのメソッド内から)。

インスタンス/クラスの外側から

インスタンス/クラスの外側から見ると、ルールは非常にシンプルで予測可能です。2つの演算子があり、インスタンスまたはクラスstaticを処理しているかどうかは、それぞれすぐにわかります。

  • ->- オブジェクトオペレーター -これは、インスタンスにアクセスするときに常に使用されます。

    $bob = new Person;
    echo $bob->name;

    呼び出しPerson->fooは意味がないことに注意してください(Personインスタンスではなくクラスであるため)。したがって、これは解析エラーです。

  • ::- スコープ解像度オペレータ -これは常にクラスの静的プロパティまたはメソッドにアクセスするために使用されます。

    echo Foo::bar()

    さらに、同じ方法でオブジェクトの静的メソッドを呼び出すことができます。

    echo $foo::bar()

    それはだ非常に我々はこれを行う際に注意することが重要外側から、オブジェクトのインスタンスがから隠されているbar()方法。それは実行とまったく同じであることを意味します:

    $class = get_class($foo);
    $class::bar();

したがって、$this静的呼び出しでは定義されていません。

インスタンス/クラスの内部から

ここで状況が少し変わります。同じ演算子が使用されますが、それらの意味は著しく不明瞭になります。

オブジェクト演算子は ->、まだ、オブジェクトのインスタンス状態への呼び出しを行うために使用されています。

class Foo {
    public $a = 1;
    public function bar() {
        return $this->a;
    }
}

オブジェクトオペレーターを使用bar()して$foo(のインスタンスFoo)でメソッドを呼び出す$foo->bar()と、インスタンスのバージョンがになり$aます。

それが私たちが期待する方法です。

::ただし、演算子の意味は変わります。これは、現在の関数の呼び出しのコンテキストによって異なります。

  • 静的コンテキスト内

    静的コンテキスト内では、を使用して行われた呼び出し::もすべて静的です。例を見てみましょう:

    class Foo {
        public function bar() {
            return Foo::baz();
        }
        public function baz() {
            return isset($this);
        }
    }

    呼び出すFoo::bar()と、baz()メソッドが静的に呼び出されるため、データ$thisは入力されません。最近のバージョンのPHP(5.3以降)E_STRICTでは、静的ではないメソッドを静的に呼び出すため、エラーが発生することに注意してください。

  • インスタンスコンテキスト内

    一方、インスタンスコンテキスト内では、を使用::して行われる呼び出しは、呼び出しの受信者(呼び出しているメソッド)に依存します。メソッドがとして定義されているstatic場合、静的呼び出しが使用されます。そうでない場合は、インスタンス情報を転送します。

    したがって、上記のコードを見ると、「静的」呼び出しがインスタンスコンテキスト内で発生しているため、呼び出し$foo->bar()はを返しtrueます。

理にかなっていますか?そうは思わなかった。ややこしい。

ショートカットキーワード

クラス名を使用してすべてを結び付けるのはかなり汚いので、PHPには、スコープの解決を容易にする3つの基本的な「ショートカット」キーワードが用意されています。

  • self-これは現在のクラス名を参照します。したがって、クラス内(クラスの任意のメソッド)self::baz()と同じです。Foo::baz()Foo

  • parent -これは、現在のクラスの親を指します。

  • static-これは呼び出されたクラスを指します。継承のおかげで、子クラスはメソッドと静的プロパティをオーバーライドできます。したがってstatic、クラス名の代わりに使用してそれらを呼び出すことで、現在のレベルではなく、呼び出し元の場所を解決できます。

これを理解する最も簡単な方法は、いくつかの例を検討することです。クラスを選びましょう:

class Person {
    public static $number = 0;
    public $id = 0;
    public function __construct() {
        self::$number++;
        $this->id = self::$number;
    }
    public $name = "";
    public function getName() {
        return $this->name;
    }
    public function getId() {
        return $this->id;
    }
}

class Child extends Person {
    public $age = 0;
    public function __construct($age) {
        $this->age = $age;
        parent::__construct();
    }
    public function getName() {
        return 'child: ' . parent::getName();
    }
}

ここで、継承についても見ていきます。これは悪いオブジェクトモデルであることをしばらく無視しますが、これを試してみるとどうなるか見てみましょう。

$bob = new Person;
$bob->name = "Bob";
$adam = new Person;
$adam->name = "Adam";
$billy = new Child;
$billy->name = "Billy";
var_dump($bob->getId()); // 1
var_dump($adam->getId()); // 2
var_dump($billy->getId()); // 3

したがって、IDカウンターは、インスタンスと子の両方で共有されます(selfアクセスに使用しているためです。を使用した場合static、子クラスでオーバーライドできます)。

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

毎回Person::getName() インスタンスメソッドを実行していることに注意してください。しかしparent::getName()、ケースの1つ(子ケース)でを使用しています。これが、このアプローチを強力にする理由です。

注意事項#1

呼び出しコンテキストは、インスタンスが使用されるかどうかを決定するものであることに注意してください。したがって:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

常に正しいとは限りませ

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

今は本当に。別のクラスを呼び出しています$thisが、Foo::isFoo()メソッドに渡されるのはのインスタンスです$bar

これは、あらゆる種類のバグと概念的なWTF-eryを引き起こす可能性があります。私は非常に避けてお勧めしたいので::、これらの3つの仮想「ショートカット」のキーワード以外のものにインスタンスメソッド内からオペレータを(staticself、およびparent)。

注意事項#2

静的メソッドとプロパティは全員で共有されることに注意してください。これにより、基本的にグローバル変数になります。グローバルに伴うすべての同じ問題で。そのため、本当にグローバルであることに慣れていない限り、静的なメソッドやプロパティに情報を格納することをためらっています。

注意事項#3

一般staticに、の代わりにを使用して、Late-Static-Bindingと呼ばれるものを使用することをお勧めしますself。しかし、それらは同じものではないことに注意してください。「常にのstatic代わりにを使用するのselfは、近視眼的です。代わりに、作成したい呼び出しについて考え、子クラスが解決され静的クラスをオーバーライドできるようにするかどうかを検討してください。コール。

TL / DR

残念ですが、戻って読んでください。長すぎるかもしれませんが、これは複雑なトピックであるため、長すぎます

TL / DR#2

いいよ。つまり、クラスの現在のクラス名selfを参照するために使用され$thisます。asは、現在のオブジェクトインスタンスを参照します。これselfはコピー/貼り付けのショートカットです。安全にクラス名に置き換えることができ、問題なく動作します。しかし$this、事前に決定できない動的な変数です(そして、クラスでさえないかもしれません)。

TL / DR#3

オブジェクトオペレーターが使用されている場合(->)、インスタンスを処理していることが常にわかります。scope-resolution-operatorが使用されている場合(::)、コンテキストに関する詳細情報が必要です(既にオブジェクトコンテキストにありますか?オブジェクトの外部にいますか?など)。



まあ... $this"Strict Standards"に従い、静的として定義されていないメソッドを静的に呼び出さない場合は定義されません。あなたがここで説明した結果が表示されます:3v4l.org/WeHVM同意、本当に変です。
MarkAchée2013年

2
長い説明を完全に読んだ後、もう一度上にスクロールして賛成するのが面倒だと感じました。冗談を言って、私はそれを賛成投票しました:D。ありがとう、これはとても便利です。
Mr_Green 2013年

3
self :: $ propertyとself :: propertyの違いについて明確な説明を追加するとよいでしょう。私もそれはかなり紛らわしいと思います
Tommaso Barbugli

1
WoC#1 、PHP 7以降、動作が異なります。Foo::isFoo()静的に呼び出される$thisため、定義されません。私の意見では、これはより直感的な行動です。- から拡張すると、別の異なる結果が表示さBarFooます。その場合、呼び出しFoo::isFoo()は実際にはインスタンスコンテキスト内になります(PHP7に固有ではありません)。
Kontrollfreak 2016年

117

self($ selfではない)はクラスのタイプ$this指し、as はクラスの現在のインスタンスを指しますself静的メンバー関数に使用して、静的メンバー変数にアクセスできるようにします。$this非静的メンバー関数で使用され、メンバー関数が呼び出されたクラスのインスタンスへの参照です。

thisはオブジェクトなので、次のように使用します。$this->member

selfはオブジェクトではないため、基本的には現在のクラスを自動的に参照する型であり、次のように使用します。self::member


97

$this-> クラスの変数(メンバー変数)またはメソッドの特定のインスタンスを参照するために使用されます。

Example: 
$derek = new Person();

$ derekはPersonの特定のインスタンスになりました。すべての人にはfirst_nameとlast_nameがありますが、$ derekには特定のfirst_nameとlast_nameがあります(Derek Martin)。$ derekインスタンス内では、$ this-> first_nameおよび$ this-> last_nameとして参照できます。

ClassName ::は、そのタイプのクラス、およびその静的変数、静的メソッドを参照するために使用されます。それが役立つ場合は、「静的」という単語を「共有」に精神的に置き換えることができます。共有されているため、特定のインスタンス(共有されていない)を参照する$ thisを参照することはできません。静的変数(つまり、静的$ db_connection)は、オブジェクトタイプのすべてのインスタンス間で共有できます。たとえば、すべてのデータベースオブジェクトは単一の接続(静的$ connection)を共有します。

静的変数の例: 単一のメンバー変数を持つデータベースクラスがあるとします:static $ num_connections; 次に、これをコンストラクターに入れます。

function __construct()
{
    if(!isset $num_connections || $num_connections==null)
    {
        $num_connections=0;
    }
    else
    {
        $num_connections++;
    }
}

オブジェクトにコンストラクタがあるように、オブジェクトにもデストラクタがあります。デストラクタは、オブジェクトが死んだとき、または設定が解除されたときに実行されます。

function __destruct()
{
    $num_connections--;
}

新しいインスタンスを作成するたびに、接続カウンターが1つ増えます。インスタンスの使用を破棄または停止するたびに、接続カウンターが1つ減少します。このようにして、使用しているデータベースオブジェクトのインスタンスの数を監視できます。

echo DB::num_connections;

$ num_connectionsは静的(共有)であるため、アクティブなデータベースオブジェクトの総数を反映します。このテクニックを使用して、データベースクラスのすべてのインスタンス間でデータベース接続を共有するのを見たことがあるかもしれません。これは、データベース接続の作成に時間がかかるためです。1つだけを作成して共有することをお勧めします(これはシングルトンパターンと呼ばれます)。

静的メソッド(つまり、public static View :: format_phone_number($ digits))は、最初にそれらのオブジェクトの1つをインスタンス化せずに使用できます(つまり、内部では$ thisを参照しません)。

静的メソッドの例:

public static function prettyName($first_name, $last_name)
{
    echo ucfirst($first_name).' '.ucfirst($last_name);
}

echo Person::prettyName($derek->first_name, $derek->last_name);

ご覧のとおり、パブリック静的関数prettyNameはオブジェクトについて何も認識していません。これは、オブジェクトの一部ではない通常の関数のように、渡したパラメーターを処理するだけです。では、なぜそれをオブジェクトの一部としてもらえないのなら、なぜわざわざ行うのでしょうか。

  1. まず、オブジェクトに関数をアタッチすると、物事を整理しやすくなるので、どこにあるかがわかります。
  2. 次に、名前の競合を防ぎます。大きなプロジェクトでは、2人の開発者にgetName()関数を作成させる可能性があります。一方がClassName1 :: getName()を作成し、もう一方がClassName2 :: getName()を作成する場合、それはまったく問題ありません。衝突はありません。静的メソッド!

SELF ::参照する静的メソッドを持つオブジェクトの外部で コーディングする場合は、オブジェクト名View :: format_phone_number($ phone_number);を使用して呼び出す必要があります。参照する静的メソッドを持つオブジェクトにコーディングする場合は、オブジェクト名View :: format_phone_number($ pn)を使用するか、またはself :: format_phone_number($ pn)ショートカットを使用できます。

同じことが静的変数にも当てはまります。 例: View :: templates_pathとself :: templates_path

DBクラス内で、他のオブジェクトの静的メソッドを参照している場合は、オブジェクトの名前を使用します。 例: Session :: getUsersOnline();

しかし、DBクラスがそれ自体の静的変数を参照したい場合、それは単にselfと言うでしょう: 例: self :: connection;

それが物事を明確にするのに役立つことを願っています:)


すばらしい答えです。指摘したいのは、静的属性を参照するときは、$記号を使用する必要があることです。例self::$templates_path
henrywright、2015年

30

このブログ投稿から:

  • self 現在のクラスを参照します
  • self 静的関数の呼び出しと静的メンバー変数の参照に使用できます
  • self 静的関数内で使用できます
  • self vtableをバイパスすることにより、ポリモーフィック動作をオフにすることもできます
  • $this 現在のオブジェクトを参照します
  • $this 静的関数の呼び出しに使用できます
  • $this静的メンバー変数の呼び出しには使用しないでください。self代わりに使用してください。
  • $this 静的関数内では使用できません

26

PHPでは、selfキーワードを使用して静的プロパティとメソッドにアクセスします。

問題は、が静的と宣言されているかどうかに関係なく$this->method()self::method()どこにでも置き換えることができることですmethod()。それであなたはどちらを使うべきですか?

このコードを考えてみましょう:

class ParentClass {
    function test() {
        self::who();    // will output 'parent'
        $this->who();   // will output 'child'
    }

    function who() {
        echo 'parent';
    }
}

class ChildClass extends ParentClass {
    function who() {
        echo 'child';
    }
}

$obj = new ChildClass();
$obj->test();

この例でself::who()$this->who()、オブジェクトのクラスに応じて、常に「親」を出力します。

これで、自分自身が呼び出さ$thisれたクラスを参照している一方で、現在のオブジェクトのクラスを参照していることがわかります

そのため、が使用$thisできない場合、または子孫クラスが現在のメソッドを上書きできないようにする場合にのみ、selfを使用する必要があります。


22

クラス定義内で$thisは、現在のオブジェクトをself参照し、現在のクラスを参照します。

を使用してクラス要素をself参照し、を使用してオブジェクト要素を参照する必要があります$this

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  

21

以下は、非静的および静的メンバー変数に対する$ thisおよびselfの正しい使用例です。

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?> 

21

http://www.php.net/manual/en/language.oop5.static.phpによると、はありません$self$thisクラス(オブジェクト)の現在のインスタンスを参照するためのと、クラスの静的メンバーを参照するために使用できるself のみがあります。ここでは、オブジェクトインスタンスとクラスの違いが関係しています。


9
提案:酸につまずくとき、この答えを読んでください。
a20 2015年

16

クラスの静的メンバーをで呼び出すことができるかどうかは問題ではなかったと思いますClassName::staticMember。質問は、使用の違い何だったself::classmember$this->classmember

あなたが使用しているかどうかなどについては、以下の例の両方が、エラーなしで動作しますself::$this->

class Person{
    private $name;
    private $address;

    public function __construct($new_name,$new_address){
        $this->name = $new_name;
        $this->address = $new_address;
    }
}

class Person{
    private $name;
    private $address;
    public function __construct($new_name,$new_address){
        self::$name = $new_name;
        self::$address = $new_address;
    }
}

「おもしろいのは、ClassName :: staticMemberを呼び出してクラスの静的メンバーを呼び出せるかどうかではなかったと思います。self:: classmemberと$ this-> classmemberの違いは何ですか」次に、違いをまったく示さないようにします。実際、2つのオプションが同じように機能する例を示しています。-1
バトルButkus

それにもかかわらず有用。スコープは解決に関するものであり、この部分はPHPマニュアルでは明確ではありません。私はまだそれが
便利

2
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
K-Gun

16

self 現在のクラス(それが呼び出されるクラス)を参照し、

$this現在のオブジェクトを参照します。自分の代わりに静的を使用できます。例を参照してください。

    class ParentClass {
            function test() {
                    self::which();  // output 'parent'
                    $this->which(); // output 'child'
            }

            function which() {
                    echo 'parent';
            }
    }

    class ChildClass extends ParentClass {
            function which() {
                    echo 'child';
            }
    }

    $obj = new ChildClass();
    $obj->test();

出力:親子


16
  • へのオブジェクトポインタ$thisは、現在のオブジェクトを参照します。
  • クラス値staticは現在のオブジェクトを参照します。
  • クラス値selfは、それが定義された正確なクラスを参照します。
  • クラス値parentは、それが定義された正確なクラスの親を参照します。

オーバーロードを示す次の例を参照してください。

<?php

class A {

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

    public static function newSelfClass()
    {
        return new self;
    }

    public function newThisClass()
    {
        return new $this;
    }
}

class B extends A
{
    public function newParentClass()
    {
        return new parent;
    }
}


$b = new B;

var_dump($b::newStaticClass()); // B
var_dump($b::newSelfClass()); // A because self belongs to "A"
var_dump($b->newThisClass()); // B
var_dump($b->newParentClass()); // A


class C extends B
{
    public static function newSelfClass()
    {
        return new self;
    }
}


$c = new C;

var_dump($c::newStaticClass()); // C
var_dump($c::newSelfClass()); // C because self now points to "C" class
var_dump($c->newThisClass()); // C
var_dump($b->newParentClass()); // A because parent was defined *way back* in class "B"

ほとんどの場合、現在のクラスを参照したいので、staticまたはを使用します$this。ただし、何を拡張するかに関係なく、元のクラスが必要になる selfため、必要になる場合があります。(とても、めったにない)


14

ここでは誰もパフォーマンスについて話さなかったので、ここに私がした小さなベンチマークがあります(5.6):

 Name     | Time    | Percent  
----------|---------|---------  
 $this->  | 0.99163 | 106.23%  
 self::   | 0.96912 | 103.82%  
 static:: | 0.93348 | 100%

これらは2 000 000回の実行の結果であり、これが私が使用したコードです。

<?php

require '../vendor/autoload.php';

// My small class to do benchmarks
// All it does is looping over every test x times and record the
//   time it takes using `microtime(true)`
// Then, the percentage is calculated, with 100% being the quickest
// Times are being rouned for outputting only, not to calculate the percentages
$b = new Tleb\Benchmark\Benchmark(2000000);

class Foo
{
    public function calling_this()
    {
        $this->called();
    }

    public function calling_self()
    {
        self::called();
    }

    public function calling_static()
    {
        static::called();
    }

    public static function called()
    {
    }
}

$b->add('$this->',  function () { $foo = new Foo; $foo->calling_this(); });
$b->add('self::',   function () { $foo = new Foo; $foo->calling_self(); });
$b->add('static::', function () { $foo = new Foo; $foo->calling_static(); });

$b->run();

1
no-op関数を2 000 000回呼び出すと、1秒続きます。PHPが大好きです。
rr-

古き良きPHP。:)しかし、呼び出し= 0.001ms。それは悪いですか?
15

私はこれが(そして同様のことが)キャッシュしない限りORMのようなものが遅く感じられる理由であり、静的なサイトジェネレーターはものだと思います。
rr-

2
理論的には1プロセッサクロックサイクルかかるはずです。そのため、この頃になっ1 / 2e9 s = 0.5 nsています
Buddy

私の答えをもう一度読んでください。注意:クラス作成します。useキーワードtbhを使用しなかった理由はわかりませんが、ベンチマークをやり直すためのPHPがなくなったため、再インストールする気がありません。
tleb 2017

13

場合selfで使用され::、オペレータは静的および非静的コンテキストの両方を行うことができる現在のクラスを指します。$thisオブジェクト自体を指します。さらに、$this静的メソッドの呼び出しに使用することは完全に合法です(ただし、フィールドを参照することはできません)。


8

私は同じ質問に遭遇しました、そして簡単な答えは:

  • $this クラスのインスタンスが必要です
  • self:: しない

使用しているときはいつでも、静的メソッド静的属性をし、クラスのオブジェクトがなくても、それらを呼びたいあなたが使用する必要がインスタンス化self:するので、それらを呼び出すために$this常に作成されるオブジェクトに必要です。


7

$this現在のクラスオブジェクトをself参照し、現在のクラス(オブジェクトではない)を参照します。クラスはオブジェクトの青写真です。したがって、クラスを定義しますが、オブジェクトを作成します。

つまり、言い換えると、とを使用self for staticthis for none-static members or methodsます。

また、子/親のシナリオでself / parentは、主に子と親のクラスメンバーとメソッドを識別するために使用されます。


7

さらに、以来、$this::まだ議論されていません。

情報提供のみを目的として、PHP 5.3以降では、インスタンス化されたオブジェクトを処理して現在のスコープ値を取得するときに、を使用するのstatic::ではなく、を使用することもでき$this::ます。

http://ideone.com/7etRHy

class Foo
{
    const NAME = 'Foo';

    //Always Foo::NAME (Foo) due to self
    protected static $staticName = self::NAME;

    public function __construct()
    {
        echo $this::NAME;
    }

    public function getStaticName()
    {
       echo $this::$staticName;
    }
}

class Bar extends Foo
{
    const NAME = 'FooBar';

    /**
     * override getStaticName to output Bar::NAME
     */
    public function getStaticName()
    {
        $this::$staticName = $this::NAME;
        parent::getStaticName();
    }
}

$foo = new Foo; //outputs Foo
$bar = new Bar; //outputs FooBar
$foo->getStaticName(); //outputs Foo
$bar->getStaticName(); //outputs FooBar
$foo->getStaticName(); //outputs FooBar

上記のコードを使用することは一般的または推奨される方法ではありませんが、単にその使用法を説明するためのものであり、「ご存知ですか?」元の投稿者の質問を参照してください。

それはまたの使用表す$object::CONSTANTための例echo $foo::NAME;とは対照的に$this::NAME;


5

使用selfあなたは、このように保存し、そのクラスのオブジェクト/インスタンスを作成せずに、クラスのメソッドを呼び出したい場合はRAMを(時には、その目的のために自己を使用します)。つまり、実際にはメソッドを静的に呼び出しています。thisオブジェクトの視点に使用します。


2

ケース1:selfクラス定数に使用できる

 クラスclassA { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}

クラスの外で呼び出したい場合は、を使用classA::POUNDS_TO_KILOGRAMSして定数にアクセスします

ケース2:静的プロパティの場合

クラスclassC {
     パブリック関数__construct(){ 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}

1

php.netによるが、この文脈では3つの特殊なキーワードは次のとおりですselfparentstatic。これらは、クラス定義内からプロパティまたはメソッドにアクセスするために使用されます。

$this一方、クラスがアクセス可能である限り、任意のクラスのインスタンスとメソッドを呼び出すために使用されます。


-1

self ::  キーワードは現在のクラスに使用され、基本的には静的メンバー、メソッド、定数にアクセスするために使用されます。しかし、$ thisの場合、静的メンバー、メソッド、関数を呼び出すことはできません。

別のクラスでself ::キーワードを使用して、静的メンバー、メソッド、および定数にアクセスできます。親クラスから拡張される場合、$ thisキーワードの場合も同じです。親クラスから拡張される場合、別のクラスの非静的メンバー、メソッド、および関数にアクセスできます。

以下のコードは、self ::および$ thisキーワードの例です。コードをコピーしてコードファイルに貼り付け、出力を確認するだけです。

class cars{
    var $doors=4;   
    static $car_wheel=4;

  public function car_features(){
    echo $this->doors." Doors <br>";
    echo self::$car_wheel." Wheels <br>"; 
  }
}

class spec extends cars{
    function car_spec(){
        print(self::$car_wheel." Doors <br>");
        print($this->doors." Wheels <br>");
    }
}

/********Parent class output*********/

$car = new cars;
print_r($car->car_features());

echo "------------------------<br>";

/********Extend class from another class output**********/


$car_spec_show=new spec;

print($car_spec_show->car_spec());
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.