Вопрос: Когда использовать self over $ this?


В PHP 5, в чем разница между использованием selfа также $this?

Когда каждый из них подходит?


1762


источник


Ответы:


Короткий ответ

использование $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()функция-член any> - это точный тип текущего объекта. Если объект имеет 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


1486



Ключевое слово self делает НЕ ссылаются только на «текущий класс», по крайней мере, не таким образом, чтобы ограничивать вас статическими членами. В контексте нестатического элемента, selfтакже обеспечивает способ обхода vtable ( см. wiki на vtable ) для текущего объекта. Так же, как вы можете использовать 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указатель внутри вызываемых функций.


708



НЕ ИСПОЛЬЗУЙ 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::относится к классу


426



Чтобы понять, о чем мы говорим, когда говорим о 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;
    }
    

Поэтому в основном мы сохраняем информацию о контейнере класса и объекта, используя «подсказки» о статический которые определяют, является ли информация общей (и, следовательно, статической) или нет (и, следовательно, динамической).

Состояние и методы

Внутри метода экземпляр объекта представлен $thisпеременная. Текущее состояние этого объекта есть, и изменение (изменение) любого свойства приведет к изменению этого экземпляра (но не других).

Если метод называется статически, $thisпеременная не определен , Это связано с тем, что нет никакого экземпляра, связанного со статическим вызовом.

Интересно, как делаются статические вызовы. Итак, давайте поговорим о том, как мы обращаемся к государству:

Доступ к государству

Итак, теперь, когда мы сохранили это состояние, нам нужно получить к нему доступ. Это может немного запутаться (или путь более чем немного), поэтому давайте разделим это на две точки зрения: извне экземпляра / класса (например, из обычного вызова функции или из глобальной области) и внутри экземпляра / класса (из метода на объект).

Из вне экземпляра / класса

С внешней стороны экземпляра / класса наши правила довольно просты и предсказуемы. У нас есть два оператора, и каждый говорит нам немедленно, если мы имеем дело с экземпляром или классом 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()сделать это в одном из случаев (детский случай). Именно это делает этот подход мощным.

Word Of Caution # 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).

Word Of Caution # 2

Обратите внимание, что статические методы и свойства разделяются всеми. Это делает их в основном глобальными переменными. Со всеми теми же проблемами, что и с глобальными. Поэтому я бы очень не решался хранить информацию в статических методах / свойствах, если вам не нравится, что это действительно глобально.

Слово предостережения № 3

В общем, вы захотите использовать так называемое Late-Static-Binding, используя staticвместо self, Но обратите внимание, что это не одно и то же, поэтому «всегда используйте staticвместо selfдействительно близоруки. Вместо этого остановитесь и подумайте о вызове, который хотите сделать, и подумайте, хотите ли вы, чтобы дочерние классы могли переопределять статическое разрешение вызов.

TL / DR

Слишком плохо, вернитесь и прочитайте. Это может быть слишком долго, но это так долго, потому что это сложная тема

TL / DR # 2

Хорошо. Вкратце, selfиспользуется для ссылки имя текущего класса внутри класса, где as $thisотносится к текущему объекту пример , Обратите внимание, что selfявляется копией / вставкой. Вы можете спокойно заменить его своим именем класса, и он будет работать нормально. Но $this- динамическая переменная, которая не может быть определена заранее (и может даже не быть вашим классом).

TL / DR # 3

Если используется оператор-оператор ( ->), затем вы всегда знайте, что вы имеете дело с экземпляром. Если используется оператор разрешения области действия ( ::), вам нужна дополнительная информация о контексте (мы уже в объектном контексте? Являются ли мы вне объекта? и т. д.).


225



self (not $self) refers to the type of class, where as $this refers to the current instance of the class. self is for use in static member functions to allow you to access static member variables. $this is used in non-static member functions, and is a reference to the instance of the class on which the member function was called.

Because this is an object, you use it like: $this->member

Because self is not an object, it's basically a type that automatically refers to the current class, you use it like: self::member


108



$this-> is used to refer to a specific instance of a class's variables (member variables) or methods.

Example: 
$derek = new Person();

$derek is now a specific instance of Person. Every Person has a first_name and a last_name, but $derek has a specific first_name and last_name (Derek Martin). Inside the $derek instance, we can refer to those as $this->first_name and $this->last_name

ClassName:: is used to refer to that type of class, and its static variables, static methods. If it helps, you can mentally replace the word "static" with "shared". Because they are shared, they cannot refer to $this, which refers to a specific instance (not shared). Static Variables (i.e. static $db_connection) can be shared among all instances of a type of object. For example, all database objects share a single connection (static $connection).

Static Variables Example: Pretend we have a database class with a single member variable: static $num_connections; Now, put this in the constructor:

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

Just as objects have constructors, they also have destructors, which are executed when the object dies or is unset:

function __destruct()
{
    $num_connections--;
}

Every time we create a new instance, it will increase our connection counter by one. Every time we destroy or stop using an instance, it will decrease the connection counter by one. In this way, we can monitor the number of instances of the database object we have in use with:

echo DB::num_connections;

Because $num_connections is static (shared), it will reflect the total number of active database objects. You may have seen this technique used to share database connections among all instances of a database class. This is done because creating the database connection takes a long time, so it's best to create just one, and share it (this is called a Singleton Pattern).

Static Methods (i.e. public static View::format_phone_number($digits)) can be used WITHOUT first instantiating one of those objects (i.e. They do not internally refer to $this).

Static Method Example:

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

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

As you can see, public static function prettyName knows nothing about the object. It's just working with the parameters you pass in, like a normal function that's not part of an object. Why bother, then, if we could just have it not as part of the object?

  1. First, attaching functions to objects helps you keep things organized, so you know where to find them.
  2. Second, it prevents naming conflicts. In a big project, you're likely to have two developers create getName() functions. If one creates a ClassName1::getName(), and the other creates ClassName2::getName(), it's no problem at all. No conflict. Yay static methods!

SELF:: If you are coding outside the object that has the static method you want to refer to, you must call it using the object's name View::format_phone_number($phone_number); If you are coding inside the object that has the static method you want to refer to, you can either use the object's name View::format_phone_number($pn), OR you can use the self::format_phone_number($pn) shortcut

The same goes for static variables: Example: View::templates_path versus self::templates_path

Inside the DB class, if we were referring to a static method of some other object, we would use the object's name: Example: Session::getUsersOnline();

But if the DB class wanted to refer to its own static variable, it would just say self: Example: self::connection;

Hope that helps clear things up :)


93



From this blog post:

  • self refers to the current class
  • self can be used to call static functions and reference static member variables
  • self can be used inside static functions
  • self can also turn off polymorphic behavior by bypassing the vtable
  • $this refers to the current object
  • $this can be used to call static functions
  • $this should not be used to call static member variables. Use self instead.
  • $this can not be used inside static functions

27



In PHP, you use the self keyword to access static properties and methods.

The problem is that you can replace $this->method() with self::method()anywhere, regardless if method() is declared static or not. So which one should you use?

Consider this code:

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();

In this example, self::who() will always output ‘parent’, while $this->who() will depend on what class the object has.

Now we can see that self refers to the class in which it is called, while $this refers to the class of the current object.

So, you should use self only when $this is not available, or when you don’t want to allow descendant classes to overwrite the current method.


23



Inside a class definition, $this refers to the current object, while self refers to the current class.

It is necessary to refer to a class element using self, and refer to an object element using $this.

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

19



Here is an example of correct usage of $this and self for non-static and static member variables:

<?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();
?> 

17