PHP 5에서 사용하는 것과self
그리고.$this
?
각각 언제가 적당합니까?
질문에 대한 답변
단답
사용하다
$this
현재 객체를 참조합니다.사용하다self
현재 클래스를 참조합니다.즉,$this->member
비정적 멤버의 경우 사용self::$member
스태틱 멤버용입니다.
풀답변
다음은 의 올바른 사용 예를 제시하겠습니다.$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(); ?>
다음은 잘못된 사용 예를 제시하겠습니다.$this
그리고.self
스태틱 및 스태틱멤버 변수의 경우:
<?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 에서 :
by http://board.phpbuilder.com/member.php?145249-laserlight
키워드 self는 ‘현재 클래스’만을 지칭하는 것이 아닙니다.적어도 스태틱멤버로 한정되는 것은 아닙니다.비정적 멤버의 컨텍스트 내에서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
호출된 함수 내의 포인터.
사용하지 마십시오. 사용 *
자아의 또 다른 측면: 그것은 언급할 가치가 있다.얄미운 것은 실행 시점이 아닌 정의 시점에서의 범위를 말합니다.다음 두 가지 방법으로 이 단순한 클래스를 고려합니다.
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 Alive」라고 표시됩니다.이것은, 콜의 발신시에, 스코프에 원래의 메서드 정의가 포함되어 있기 때문입니다.self::getStatus()
정의되었습니다.
PHP 5.3에는 솔루션이 있습니다.해상도 연산자는 호출된 클래스의 범위에 바인딩되어 있음을 나타내는 “late static binding”을 구현합니다.에서 회선을 변경하다status()
로.static::getStatus()
결과는 예상대로입니다.이전 버전의 PHP에서는 이를 위해 크러지를 찾아야 합니다.
PHP 매뉴얼 참조
그러니 질문에 대답하는 게 아니라…
$this->
는 현재 오브젝트(클래스의 인스턴스)를 참조하는 반면,static::
는 클래스를 말합니다.
정말 우리가 얘기를 한다 무슨 말 하는지 이해할 수 있다self
대$this
개념적이고 실용적인 차원에서 실제로 무슨 일이 일어나고 있는지 알아내야 합니다.어떤 답변도 적절한 답변을 할 수 없다고 생각합니다. 그러니 제 시도는 이렇습니다.
클래스와 오브젝트가 무엇인지부터 시작합시다.
개념적으로 클래스와 오브젝트
그럼 수업이란 무엇일까요?많은 사람들이 오브젝트의 Blueprint 또는 템플릿으로 정의합니다.실제로 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
교환입니다.
따라서 클래스는 글로벌 구조이고 오브젝트는 로컬 구조라고 합니다.그런 건 신경 쓰지 마->
구문, 잠시 후에 설명하겠습니다.
또 하나 얘기해야 할 건 인스턴스가 이 케이스가instanceof
특정 클래스:$bob instanceof Person
부울을 반환한다.$bob
인스턴스가 생성되었습니다.Person
계급, 또는 의 자녀Person
.
상태 정의
그럼 클래스에 실제로 무엇이 포함되어 있는지 조금 더 자세히 살펴보겠습니다.클래스에 포함되는 「물건」에는, 다음의 5 종류가 있습니다.
속성 – 각 인스턴스가 포함하는 변수로 간주합니다.
class Foo { public $bar = 1; }
Static Properties – 클래스 수준에서 공유되는 변수라고 생각합니다.즉, 각 인스턴스에서 복사되지 않습니다.
class Foo { public static $bar = 1; }
메서드 – 각 인스턴스가 포함(및 인스턴스에서 작동)하는 함수입니다.
class Foo { public function bar() {} }
정적 메서드 – 클래스 전체에서 공유되는 함수입니다.인스턴스에서 동작하지 않고 정적 속성에서만 동작합니다.
class Foo { public static function bar() {} }
상수 – 클래스 해결 상수입니다.더 이상 자세히 설명하지 않고, 완성도를 높이기 위해 다음과 같이 덧붙입니다.
class Foo { const BAR = 1; }
따라서 기본적으로 정보의 공유 여부(따라서 정적)를 식별하는 정적에 대한 “힌트”를 사용하여 클래스 및 객체 컨테이너에 대한 정보를 저장합니다.
상태 및 방법
메서드 내에서 오브젝트의 인스턴스는$this
변수.해당 객체의 현재 상태가 여기에 있으므로 속성을 변환(변경)하면 해당 인스턴스(다른 인스턴스 제외)가 변경됩니다.
메서드가 스태틱하게 호출되면$this
변수는 정의되어 있지 않습니다.이는 스태틱콜과 관련된 인스턴스가 없기 때문입니다.
여기서 흥미로운 점은 스태틱콜이 어떻게 이루어지는지입니다.그럼 주(州)에 접속하는 방법에 대해 설명하겠습니다.
액세스 상태
이제 상태를 저장했으므로 액세스해야 합니다.이 작업은 다소 까다로울 수 있으므로(또는 비트보다 훨씬 더 많은 경우), 인스턴스/클래스 외부(일반 함수 호출 또는 글로벌 스코프)와 인스턴스/클래스 내부(개체의 메서드 내)의 두 가지 관점으로 나눕니다.
인스턴스/클래스 외부에서
인스턴스/클래스의 외부에서는 규칙이 매우 간단하고 예측 가능합니다.두 개의 연산자가 있으며, 각 연산자가 인스턴스 또는 클래스 스태틱을 처리하고 있는지 여부를 즉시 알려줍니다.
->
– object-operator – 인스턴스에 액세스할 때 항상 사용됩니다.$bob = new Person; echo $bob->name;
중요한 건 전화는
Person->foo
(이후) 말이 안 된다Person
인스턴스가 아닌 클래스입니다).따라서 이는 해석 오류입니다.::
– scope-resolution-operator – 클래스 정적 속성 또는 메서드에 액세스할 때 항상 사용됩니다.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
) object-timeout을 사용합니다.$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
class(임의의 메서드).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()
instance 메서드를 사용합니다.하지만 우리는parent::getName()
한 케이스(아이의 케이스)로 하도록 하겠습니다.이것이 이 접근방식을 강력하게 만듭니다.
주의사항 #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()
method는 의 인스턴스입니다.$bar
.
이로 인해 각종 버그와 개념적인 WTF 에리가 발생할 수 있습니다.그래서 저는 이 모든 것을 피하는 것을 강력히 권합니다.::
instance 메서드 내의 연산자(가상 “숏컷” 키워드 3개 제외)static
,self
,그리고.parent
).
주의사항 #2
정적 메서드 및 속성은 모든 사람이 공유합니다.따라서 기본적으로 글로벌 변수가 됩니다.지구촌 대회와 같은 문제들로 말이야따라서 정보를 정적인 메서드/속성에 저장하는 것이 매우 망설여집니다.정적인 방법에 대한 정보가 글로벌하게 전달되지 않는 한 말이죠.
주의사항 #3
일반적으로 Late-Static-Binding이라고 하는 것을 사용하는 방법은 다음과 같습니다.static
대신self
단, 이 두 가지가 동일하지 않기 때문에 “항상 사용”이라는 점에 유의해 주십시오.static
대신self
정말 근시안적이야.대신에, 발신하는 콜을 정지해 생각해, 그 스태틱하게 해결된 콜을 자녀 클래스로 덮어쓸 수 있도록 합니다.
TL/DR
아쉽다. 다시 가서 읽어봐.너무 길 수도 있지만 너무 길어요.왜냐하면 이건 복잡한 주제이기 때문에
TL/DR #2
그래, 좋아.요컨대,self
클래스 내의 현재 클래스 이름을 참조하기 위해 사용됩니다.$this
는 현재 오브젝트인스턴스를 나타냅니다.주의:self
이거 copy/paste short-cut.안전하게 당신의 클래스 이름으로 그것이 잘 될 거야 대체할 수 있습니다.그렇지만$this
앞에 시간(수 있고도 당신의 수업)으로 결정될 수 없는 동적 변수 있다.
TL/DR#3
만약 object-operator(사용된다.->
), 그때 당신은 언제나 인스턴스를 다룬다는 건 알게 돼다.만약 scope-resolution-operator(사용된다.::
음, 당신( 있는 object-context에 이미 내용에 관해 더 많은 정보가 필요해?우리가 개체의 밖에서?등).
self
($self가 아닌)는 클래스의 종류를 나타냅니다만,$this
는 클래스의 현재 인스턴스를 나타냅니다. self
는 스태틱 멤버 변수에 액세스하기 위한 스태틱멤버 함수로 사용합니다. $this
는 비 스태틱멤버 함수로 사용되며 멤버함수가 호출된 클래스의 인스턴스를 참조합니다.
왜냐면this
다음과 같이 사용합니다.$this->member
왜냐면self
객체가 아니라 기본적으로 현재 클래스를 자동으로 참조하는 유형입니다.사용법은 다음과 같습니다.self::member