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

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

когда каждое подходящее?

22 ответов


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

использовать $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() функция-член whatever >является точным типом текущего объекта. Если объект имеет значение 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 (см. wiki на vtable) для текущего объекта. Так же, как вы можете использовать parent::methodName() для вызова родительской версии функции, поэтому вы можете вызвать self::methodName() для вызова текущей реализации классов a метод.

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 указатель внутри вызываемых функций.


НЕ ИСПОЛЬЗОВАТЬ 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() мы ожидали бы увидеть "человек умер", однако то, что мы видим, - "человек жив", поскольку область содержит исходное определение метода при вызове .

PHP 5.3 имеет решение. the static:: оператор разрешения реализует "позднюю статическую привязку", которая является причудливым способом сказать, что она привязана к области вызываемого класса. Измените строку в status() to static::getStatus() и результаты, что вы ожидаете. В старых версиях PHP для этого вам нужно будет найти kludge.

посмотреть PHP документации

так что ответ на вопрос не так задал ...

$this-> относится к текущему объекту (экземпляру класса), тогда как static:: относится к классу


чтобы понять, о чем мы говорим, когда мы говорим о self и $this, мы должны на самом деле копаться в том, что происходит на концептуальном и практическом уровне. Я действительно не чувствую, что любой из ответов делает это должным образом, поэтому вот моя попытка.

давайте начнем с разговора о том, что класс и объект есть.

Классы И Объекты, Концептуально

так что и a класс? Многие люди определяют это как план или шаблон для объекта. На самом деле, вы можете прочитать больше о классах в 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 который возвращает boolean, если $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 переменная не определен. Это происходит потому, что нет экземпляра, связанного со статическим вызовом.

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

Доступ К Государственной

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

Снаружи Экземпляр/Класс

из вне экземпляра класса, наши правила довольно просты и предсказуемы. У нас есть два оператора, и каждый немедленно сообщает нам, имеем ли мы дело с экземпляром или статическим классом:

  • -> - является динамической переменной, которая не может быть определена заранее (и даже не может быть вашим классом).

    TL / DR #3

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


self (не $self) относится к тип класса, где в качестве $this относится к текущему экземпляр класса. self используется в статических функциях-членах для доступа к статическим переменным-членам. $this используется в нестатических функциях-членах и является ссылкой на экземпляр класса, в котором вызывалась функция-член.

, потому что this является объектом, вы используете его как:$this->member

потому что self не является объектом, это в основном тип, который автоматически ссылается на текущий класс, вы используете его как:self::member


$this-> используется для ссылки на конкретный экземпляр переменных класса (переменных-членов) или методов.

Example: 
$derek = new Person();

$Дерек теперь является конкретным экземпляром человека. У каждого человека есть first_name и last_name, но $derek имеет определенные first_name и last_name (Дерек Мартин). Внутри экземпляра $derek мы можем ссылаться на них как $this - >first_name и $this - >last_name

ClassName:: используется для ссылки на этот тип класса и его статические переменные, статические методы. Если это поможет, вы можете мысленно заменить слово " статический "на"общий". Поскольку они являются общими, они не могут ссылаться на $this, который ссылается на конкретный экземпляр (не общий). Статические переменные (например, static $db_connection) могут совместно использоваться всеми экземплярами типа объекта. Например, все объекты базы данных имеют одно соединение (static $connection).

Пример Статических Переменных: Притворяться, что у нас есть класс базы данных с одной переменной-члена : статические $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 является статическим (общим), он будет отражать общее количество активных объектов базы данных. Возможно, вы видели этот метод, используемый для обмена подключениями к базе данных между всеми экземплярами класса базы данных. Это делается потому, что создание соединения с базой данных занимает много времени, поэтому лучше всего создать только один и поделиться им (это называется Одноэлементным шаблоном).

статические методы (т. е. открытый статический вид:: 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);

как вы можете видеть, публичная статическая функция prettyName ничего не знает об объекте. Он просто работает с параметрами, которые вы передаете, как обычная функция, которая не является частью объекта. Зачем тогда беспокоиться, если мы можем просто иметь его не как часть объекта?

  1. во-первых, присоединение функции объектов помогают вам держать вещи организованными, поэтому вы знаете, где их найти.
  2. во-вторых, это предотвращает конфликты именования. В большом проекте, скорее всего, два разработчика создадут функции getName (). Если один создает ClassName1::getName(), а другой создает ClassName2::getName(), это вообще не проблема. Никакого конфликта. Ура статические методы!

SELF:: Если вы кодируете за пределами объект, который имеет статический метод, к которому вы хотите обратиться, Вы должны вызвать его, используя представление имени объекта:: format_phone_number ($phone_number); Если вы кодируете внутри объект, который имеет статический метод, на который вы хотите ссылаться, вы можете или используйте представление имени объекта:: format_phone_number ($pn), или вы можете использовать ярлык self::format_phone_number ($pn)

то же самое касается статических переменных: пример: View:: templates_path versus self:: templates_path

внутри класса DB, если бы мы ссылались на статический метод какого-либо другого объекта, мы бы использовали имя объекта: пример: сессия::getUsersOnline();

но если бы класс DB хотел ссылаться на свою собственную статическую переменную, он просто сказал бы self: пример: self:: соединение;

надеюсь, что это поможет прояснить ситуацию:)


С этот блог:

  • self относится к текущему классу
  • self может использоваться для вызова статических функций и ссылки на статические переменные-члены
  • self может использоваться внутри статических функций
  • self также можно отключить полиморфное поведение, минуя vtable
  • $this относится к текущему объекту
  • $this смогите быть использовано к статические функции-вызов
  • $this не следует использовать для вызова статических переменных-членов. Использовать .
  • $this не может использоваться внутри статических функций

в 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() зависит от класса объекта.

теперь мы можем видеть, что self относится к классу, в котором он называется, пока $this относится к класс текущего объекта.

Итак, вы должны использовать self только тогда, когда $this недоступно или если вы не хотите, чтобы классы-потомки перезаписывали текущий метод.


внутри определения класса $this относится к текущему объекту, а self - к текущему классу.

необходимо ссылаться на элемент класса, используя self, и ссылаться на элемент объекта, используя $this.

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

вот пример правильного использования $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();
?> 

согласно http://www.php.net/manual/en/language.oop5.static.php нет $self. Есть только $this, для ссылки на текущий экземпляр класса (объекта) и self, который может использоваться для ссылки на статические члены класса. Здесь в игру вступает разница между экземпляром объекта и классом.


поскольку никто здесь не говорил о выступлениях, вот небольшой тест, который я сделал (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();

self относится к текущему классу (в котором он называется),

$this ссылается на текущий объект. Вы можете использовать static вместо self. См. пример:

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

выход: родитель ребенок!--4-->


Я считаю, что вопрос не в том, Можете ли вы вызвать статического члена класса, вызвав 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;
    }
}

  • указатель объекта $this to относится к текущему объекту.
  • значение класса "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 потому что вы хотите исходный класс независимо от того, что расширяет его. (Очень, очень редко)


, когда self используется :: оператор относится к текущему классу, что может быть сделано как в статическом, так и в нестатическом контекстах. $this относится к самому объекту. Кроме того, это совершенно законно использовать $this вызывать статические методы (но не ссылаться на поля).


$this относится к текущему объекту класса,self относится к текущему классу (не объекту). Класс является чертежом объекта. Таким образом, вы определяете класс, но строите объекты.

другими словами, использовать self for static и this for none-static members or methods.

также в дочернем / Родительском сценарии self / parent в основном используется для идентификации дочерних и родительских членов класса и методов.


кроме того, начиная с $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

использование кода выше не является общей или рекомендуемой практикой, а просто иллюстрирует его использование и действует как " вы знаешь?- в связи с вопросом оригинального плаката.

он также представляет использование echo $foo::NAME; в противоположность $this::NAME;


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


Случай 1: Используйте self может использоваться для констант класса

 class classA { 
     const FIXED_NUMBER = 4; 
     self::POUNDS_TO_KILOGRAMS
}

если вы хотите вызвать его вне класса, используйте classA::POUNDS_TO_KILOGRAMS для доступа к константам

случай 2: для статических свойств

class classC {
     public function __construct() { 
     self::$_counter++; $this->num = self::$_counter;
   }
}

Я столкнулся с тем же вопросом, и простой ответ:

  • это требуется экземпляр класса
  • self:: не

всякий раз, когда вы используете статические методы или статические атрибуты и хотите вызвать их без создания экземпляра объекта класса, который вам нужно использовать self:: называть их, потому что это всегда требуется на объекте быть созданным.


согласно php.net в этом контексте есть три специальных ключевых слова:self, parent и static. Они используются для доступа к свойствам или методам из определения класса.

$this, С другой стороны, используется для вызова экземпляра и методы класса, как этот класс работает.