$ this 이상으로 언제 자기를 사용해야합니까?


답변:


1727

짧은 답변

$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 :

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


330
이 답변은 지나치게 단순합니다. 다른 답변에서 지적했듯이 현재 클래스를 참조하기 위해 self범위 확인 연산자와 함께 사용됩니다 ::. 정적 및 비 정적 컨텍스트 모두에서 수행 할 수 있습니다. 또한 $this정적 메소드를 호출하는 데 사용 하는 것이 합법적 이지만 필드를 참조하지는 않습니다.
Artefacto

50
5.3 이상에서 :: self 대신 static ::을 사용하는 것도 고려하십시오. 그렇지 않으면 말할 수없는 두통이 발생할 수 있습니다. 아래 내 대답을 참조하십시오.
Sqoo

25
-1. 이 답변은 잘못된 것입니다. 자세한 내용은 다른 답변을 읽으십시오.
Pacerier

6
지나치게 단순화되었지만 머리를 터뜨리지 않고 기본 수준의 질문에 대답했습니다. 좀 더 도움이 될만한 정보를 얻었지만 지금은 왜 $ this-> attrib로 클래스 속성과 self :: constant로 클래스 상수에 도달했는지 알아 내려고했습니다. 이것은 내가 더 잘 이해하는 데 도움이되었습니다
MydKnight

무엇에 대해 $this::?
James

742

self 키워드는 정적 멤버로 제한하는 방식이 아닌 '현재 클래스'를 가리키는 것이 아닙니다 . 정적이 아닌 멤버의 컨텍스트 내에서 현재 객체에 대한 selfvtable을 무시하는 방법 (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();

출력됩니다 :

안녕하세요, 저는 Ludwig에서 온 괴짜
안녕 Ludwig입니다

sayHello()$this포인터를 사용 하므로 vtable이 호출되도록 호출 Geek::getTitle()됩니다. sayGoodbye()를 사용 self::getTitle()하므로 vtable이 사용되지 않고 Person::getTitle()호출됩니다. 두 경우 모두 인스턴스화 된 객체의 메서드를 다루며 $this호출 된 함수 내의 포인터에 액세스 할 수 있습니다.


3
이 답변은 예외가 아닌 일반적인 규칙으로 시작한 경우에 더 좋습니다. 기술적 인 전문 지식이 아닌 스타일의 문제입니다. 이것은 self ::와 $ this->의 차이점에 대해 내가 본 가장 좋은 예이지만, 먼저 개념을 반증함으로써 그것을 숨기는 것은 부끄러운 일입니다.
adjwilli

3
@adjwilli : 왜 나쁜 스타일입니까? OP의 기대치 (논문)가 먼저 비 승인 된 다음 (설명) 설명이 종합으로 제시된다면 의식을 높이 지 않습니까?
hakre

1
"현재 클래스"는 정말 문제가 있습니다. 이 단어 조합은 "위치에있는 클래스 self"/ "클래스 정의"와 "객체의 클래스"(실제로 static) 인 것으로 이해 될 수 있습니다 .
Jakumi

무엇에 대해 $this::?
James

1
@James-사용할 이유가 없습니다 $this::. 모든 가능한 경우는 이미 더 일반적으로 사용되는 구문으로 덮여 있습니다. 당신이 무슨 뜻인지에 따라, 사용 $this->, self::또는 static::.
ToolmakerSteve

461

DO NOT USE self::사용static::

자기의 또 다른 측면이 있습니다 : 그것은 언급 할 가치가 있습니다. 성가신 self::것은 실행 시점이 아닌 정의 시점의 범위를 나타냅니다 . 다음 두 가지 방법으로이 간단한 클래스를 고려하십시오.

class Person
{

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

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

}

전화 Person::status()하면 "사람이 살아있다"는 메시지가 나타납니다. 이제 이것을 상속받은 클래스를 만들 때 어떤 일이 발생하는지 고려하십시오.

class Deceased extends Person
{

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

}

호출 Deceased::status()할 때 "사람이 사망 했음"이 표시 될 것으로 예상되지만, 호출 할 때 범위에 원래 메소드 정의가 포함되어 있으므로 "사람이 살아 남았습니다" self::getStatus().

PHP 5.3에는 해결책이 있습니다. static::해상도 연산자 구현은 호출 클래스의 범위에 바인딩 된 것을 말하는 멋진 방법이다 "늦게 정적 바인딩". 에 줄을 변경 status()하는 static::getStatus()결과는 무엇을 기대합니다. 이전 버전의 PHP에서는이를 수행하기 위해 kludge를 찾아야합니다.

PHP 문서를 참조하십시오

그래서 질문대로 대답하지 않기 위해 ...

$this->현재 객체 (클래스의 인스턴스)를 static::참조하는 반면 , 클래스는


6
클래스 상수는 어떻습니까?
Kevin Bond

53
"고인 사망 :: status ()"사람이 사망했음을 알 수 있습니다 ". 아니요. 정적 함수 호출이므로 다형성이 없습니다.
cquezel

2
PHP의 모든 결함 중에서, 나는 이것이 전혀 미쳤다고 생각하지 않습니다. 코더가 현재 클래스에서 메소드를 지정할 수있는 방법은 무엇입니까 (vtable에서 조회하는 것이 아니라)? 그들이 이름을 다르게 지정했다면 (아마도 밑줄로 표시)이 기능을 원하는 사람들은 그것을 추악하다고 비난 할 것입니다. 그렇지 않으면, 그들이 사용하는 제정신의 이름이 무엇이든, "불쾌한"행동으로 비판하는 사람들은 항상 쉽게 혼란스러워 할 것입니다.
tne

2
예제가 혼란스러워 보입니다. getStatus메서드는 클래스가 아닌 클래스 인스턴스를 호출하는 것으로 간주합니다.
Jānis Elmeris

1
@Sqoo- "self ::, use static ::"을 사용 하는 것은 이상한 점 입니다. 의도적으로 동일한 작업이 아닙니다. 난 당신이 정말 만들고있는 점이라고 생각 하면 오히려 '자기 ::'보다, 실제 클래스 이름 '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.

따라서 클래스는 전역 구조이고 객체는 로컬 구조라고합니다. 이 재미있는 ->구문 에 대해 걱정하지 마십시오 .

우리가에 대한 이야기해야 또 한가지는 우리가 할 수 있다는 것입니다 확인 인스턴스가있는 경우 instanceof: 특정 클래스 $bob instanceof Person경우 부울을 반환 $bob인스턴스가 사용되었다 Person클래스를, 또는 의 아이가 Person.

상태 정의

클래스에 실제로 포함 된 내용을 조금 살펴 보겠습니다. 클래스에는 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;
    }

따라서 기본적으로 우리는 정보가 공유되는지 (따라서 정적 인) 아닌지 (그리고 동적)를 식별하는 static 에 대한 "힌트"를 사용하여 클래스와 객체 컨테이너에 정보를 저장합니다 .

상태 및 방법

메소드 내에서 객체의 인스턴스는 $this변수 로 표시됩니다 . 해당 객체의 현재 상태가 있으며 속성을 변경 (변경)하면 해당 인스턴스가 변경되지만 다른 인스턴스는 변경되지 않습니다.

메소드가 정적으로 호출되면 $this변수 가 정의되지 않습니다 . 정적 호출과 연결된 인스턴스가 없기 때문입니다.

여기서 흥미로운 점은 정적 호출 방법입니다. 우리가 상태에 접근하는 방법에 대해 이야기 해 봅시다 :

접근 상태

이제 해당 상태를 저장 했으므로 해당 상태에 액세스해야합니다. 이 비트를 얻을 수있는 까다로운 (또는 방법으로 더 많은 비트 이상), 그래서 두 가지 관점으로이 분할하자 : 인스턴스 / 클래스의 외부에서 (일반 함수 호출에서, 또는 글로벌 범위에서 말하는), 그리고 인스턴스의 내부 / class (객체의 메소드 내에서).

인스턴스 / 클래스 외부에서

인스턴스 / 클래스 외부에서 우리의 규칙은 매우 간단하고 예측 가능합니다. 우리는 두 개의 연산자를 가지고 있으며 각각 인스턴스 또는 클래스 정적을 처리하고 있는지 즉시 알려줍니다.

  • ->- 객체 연산자 - 우리는 인스턴스를 액세스하는 경우는 항상 사용됩니다.

    $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;
    }
}

object-operator를 사용하여 (의 인스턴스 ) 에서 bar()메소드 호출 :$fooFoo$foo->bar() 인스턴스의 버전이 $a됩니다.

이것이 우리가 기대하는 방식입니다.

::연산자 의 의미는 변경됩니다. 현재 함수에 대한 호출 컨텍스트에 따라 다릅니다.

  • 정적 컨텍스트 내

    정적 컨텍스트에서 사용하는 모든 호출 ::도 정적입니다. 예를 보자.

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

    호출 Foo::bar()부르는 것이다 baz()정적 방법을, 따라서 $this것입니다 하지 채워. E_STRICT정적이 아닌 메소드를 정적으로 호출하기 때문에 최신 버전의 PHP (5.3+)에서는 오류가 발생할 수 있습니다.

  • 인스턴스 컨텍스트 내

    반면 인스턴스 컨텍스트 내에서 :: 의 수신자 (우리가 호출하는 방법)에 따라 다릅니다. 메소드가로 정의 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

호출 컨텍스트는 인스턴스 사용 여부를 결정합니다. 따라서:

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가 발생할 수 있습니다. 나는 높은 피하는 게 좋을 것 그래서 ::그 세 가상 "바로 가기"키워드를 제외하고 아무것도 인스턴스 메서드 내에서 연산자 ( static, self, 및 parent).

주의의 말 # 2

정적 메서드와 속성은 모든 사람이 공유합니다. 기본적으로 전역 변수가됩니다. 전 세계와 동일한 문제가 있습니다. 따라서 전 세계에 익숙하지 않다면 정적 메서드 / 속성에 정보를 저장하는 것이 정말 주저합니다.

주의 사항 # 3

일반적으로을 static대신 하여 Late-Static-Binding이라는 것을 사용하고 싶을 것입니다 self. 그러나 그것들은 같은 것이 아니므로 "항상 static대신에 항상 사용 하는 self것은 근시안적입니다. "라고 말하고 , 대신하고 싶은 호출에 대해 생각하고 자식 클래스가 정적 해결 을 재정의 할 수 있도록하려면 생각하십시오. 요구.

TL / DR

너무 나쁘고 돌아가서 읽어보십시오. 너무 길지만 복잡한 주제이기 때문에 너무 깁니다.

TL / DR # 2

알았어 괜찮아. 즉, 클래스에서 현재 클래스 이름self 을 참조 하는 데 사용됩니다 . 여기서 as $this는 현재 객체 인스턴스 를 나타냅니다 . 참고 self카피는 / 바로 가기를 붙여 넣습니다. 클래스 이름으로 안전하게 바꿀 수 있으며 정상적으로 작동합니다. 그러나$this 미리 결정할 수없는 동적 변수입니다 (클래스가 아닐 수도 있습니다).

TL / DR # 3

객체 연산자가 사용 된 경우 ( ->) 항상 인스턴스를 처리하고 있다는 것을 알고 있습니다. scope-resolution-operator가 사용되는 경우 ( ::) 컨텍스트에 대한 추가 정보가 필요합니다 (이미 오브젝트 컨텍스트에 있습니까? 오브젝트 외부에 있습니까? 등).


1
주의 사항 # 1 : $ 정적 메소드를 호출 할 때 $ this는 정의되지 않습니다 : 3v4l.org/9kr0e
Mark Achée

$this"엄격한 표준"을 따르고 정적으로 정의되지 않은 메소드를 정적으로 호출하지 않으면 글쎄 ... 정의되지 않습니다. 3v4l.org/WeHVM 동의 한 결과가 이상합니다.
Mark Achée 2016 년

2
긴 설명을 완전히 읽은 후 다시 위로 스크롤하여 올리는 게으른 느낌이 들었습니다. 농담, 나는 그것을 찬성했다 : D. 고마워 이것은 매우 유용합니다.
Mr_Green

3
self :: $ property와 self :: property의 차이점에 대한 명확한 설명을 추가하는 것이 좋을 것입니다. 너무 혼란 스러워요
Tommaso Barbugli

1
WoC # 1 PHP 7부터 다르게 작동합니다 . Foo::isFoo()정적으로 호출 $this되므로 정의되지 않습니다. 내 의견으로는 더 직관적 인 행동입니다. - 에서 확장 된다면 다른 결과 가 나옵니다 . 그런 다음 호출 은 실제로 인스턴스 컨텍스트 내에 있습니다 (PHP7에만 해당되지 않음). BarFooFoo::isFoo()
Kontrollfreak

117

self($ self가 아님)은 클래스 의 유형$this나타내며 , 여기서 클래스 의 현재 인스턴스 를 나타냅니다 . self정적 멤버 함수에 사용하여 정적 멤버 변수에 액세스 할 수 있습니다. $this비 정적 멤버 함수에 사용되며 멤버 함수가 호출 된 클래스의 인스턴스에 대한 참조입니다.

때문에 this개체입니다, 당신은 그것을처럼 사용$this->member

self객체가 아니기 때문에 기본적으로 현재 클래스를 자동으로 참조하는 유형입니다.self::member


97

$this-> 클래스 변수 (멤버 변수) 또는 메서드의 특정 인스턴스를 나타내는 데 사용됩니다.

Example: 
$derek = new Person();

$ derek은 이제 Person의 특정 인스턴스입니다. 모든 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--;
}

새 인스턴스를 만들 때마다 연결 카운터가 하나씩 증가합니다. 인스턴스 사용을 중단하거나 중단 할 때마다 연결 카운터가 하나씩 줄어 듭니다. 이런 식으로 우리는 우리가 사용하고있는 데이터베이스 객체의 인스턴스 수를 모니터링 할 수 있습니다 :

echo DB::num_connections;

$ num_connections는 정적 (공유)이므로 총 활성 데이터베이스 개체 수를 반영합니다. 데이터베이스 클래스의 모든 인스턴스간에 데이터베이스 연결을 공유하는 데이 기술이 사용 된 것을 보았을 것입니다. 데이터베이스 연결을 만드는 데 시간이 오래 걸리기 때문에이 작업을 수행하므로 하나만 만들어 공유하는 것이 가장 좋습니다 (싱글 톤 패턴이라고 함).

정적 메소드 (예 : public static View :: format_phone_number ($ digits))는 먼저 해당 오브젝트 중 하나를 인스턴스화하지 않고 사용할 수 있습니다 (즉, 내부적으로 $ 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);

보다시피 public static 함수 prettyName은 객체에 대해 아무것도 모른다. 객체의 일부가 아닌 일반 함수처럼 전달하는 매개 변수로 작업하고 있습니다. 그렇다면 왜 우리가 물건의 일부로 그것을 가질 수 없다면 왜 귀찮게합니까?

  1. 먼저, 객체에 기능을 연결하면 객체를 정리하는 데 도움이되므로 찾을 위치를 알 수 있습니다.
  2. 둘째, 이름 충돌을 방지합니다. 큰 프로젝트에서는 두 명의 개발자가 getName () 함수를 작성하게 할 것입니다. 하나는 ClassName1 :: getName ()을 작성하고 다른 하나는 ClassName2 :: getName ()을 작성해도 전혀 문제가되지 않습니다. 충돌이 없습니다. 예 정적 방법!

SELF :: 참조하려는 정적 메소드가있는 오브젝트 외부 에서 코딩 하는 경우 오브젝트 이름을 사용하여 호출해야합니다. View :: format_phone_number ($ phone_number); 당신이 코딩하는 경우 안에 당신이 있습니다, 참조 할 정적 메서드가있는 객체 중 하나를 오브젝트의 이름보기 :: format_phone_number ($ PN)를 사용, 또는 셀프 :: format_phone_number ($ PN)를 사용할 수 있습니다를 바로 가기

정적 변수도 마찬가지입니다. 예 : View :: templates_path와 self :: templates_path

DB 클래스 내에서 다른 객체의 정적 메서드를 참조하는 경우 객체 이름을 사용합니다. 예 : Session :: getUsersOnline ();

그러나 DB 클래스가 자체 정적 변수를 참조하려면 self라고 말하면됩니다. 예 : self :: connection;

희망을 정리하는 데 도움이되기를 바랍니다 :)


좋은 대답입니다. 정적 속성을 언급 할 때 $부호 를 사용해야한다는 것을 지적하고 싶습니다 . 예를 들어self::$templates_path
henrywright

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()항상 'parent'를 출력하지만 $this->who()객체의 클래스에 따라 다릅니다.

이제 self는 자신이 호출 $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클래스의 정적 멤버를 참조하는 데 사용할 수있는 클래스 (객체), 자기의 현재 인스턴스 참조를 들어,. 객체 인스턴스와 클래스의 차이점이 여기에 있습니다.


9
제안 : 산에 걸려 넘어 질 때이 답변을 읽으십시오.
a20

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를 사용하는 것의 차이점은 무엇입니까?" 그런 다음 아무런 차이도 보이지 않습니다. 실제로 두 옵션이 동일하게 작동하는 인스턴스를 보여줍니다. -1
Buttle Butkus

그럼에도 불구하고 유용합니다. 범위는 해결에 관한 것이며 PHP 매뉴얼에서는이 부분이 명확하지 않습니다. 여전히 유용합니다
renoirb

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

16

self 현재 클래스 (호출 된 클래스)를 나타냅니다.

$this현재 객체를 나타냅니다. self 대신 static을 사용할 수 있습니다. 예를보십시오 :

    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 기능을 200,000 번 호출하면 1 초간 지속됩니다. PHP를 좋아합니다.
rr-

좋은 오래된 PHP. :) 그러나 호출 = 0.001ms. 그게 나쁜가요?
tleb

나는 이것 (그리고 비슷한 것들)이 물건을 캐싱하지 않으면 ORM과 같은 것들이 느리게 느껴지는 이유라고 생각하며 정적 사이트 생성기가 중요합니다.
rr-

2
이론적으로 1 개의 프로세서 클럭 사이클이 필요하며, 이는 1 / 2e9 s = 0.5 ns오늘날의 상황입니다.
Buddy

내 대답을 다시 읽으십시오. 조심해 클래스만듭니다 . use키워드 tbh를 사용하지 않은 이유를 모르겠지만 더 이상 벤치 마크를 다시 실행할 PHP가 없으며 다시 설치하고 싶지는 않습니다.
tleb

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 클래스 상수에 가능

 클래스 A { 
     const FIXED_NUMBER = 4; 
     self :: POUNDS_TO_KILOGRAMS
}

클래스 외부에서 호출 classA::POUNDS_TO_KILOGRAMS하려면 상수에 액세스하십시오.

사례 2 : 정적 속성

classC {클래스
     공용 함수 __construct () { 
     self :: $ _ counter ++; $ this-> num = self :: $ _ counter;
   }
}

1

php.net에 따르면이 문맥에는 self, parent및 세 가지 특수 키워드가 static있습니다. 클래스 정의 내부에서 속성 또는 메서드에 액세스하는 데 사용됩니다.

$this반면에, 클래스에 액세스 할 수있는 한 클래스의 인스턴스와 메소드를 호출하는 데 사용됩니다.


-1

self ::  키워드는 현재 클래스에 사용되며 기본적으로 정적 멤버, 메서드 및 상수에 액세스하는 데 사용됩니다. 그러나 $ this의 경우 정적 멤버, 메서드 및 함수를 호출 할 수 없습니다.

당신이 사용할 수있는 자체 :: 다른 클래스 및 액세스 정적 멤버, 방법 및 상수 키워드를. $ 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.