Когда использовать себя сверх $ this?

1699

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

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

  • 0
    возможный дубликат нового я против новой статики
  • 0
    Я собираюсь спросить, в чем разница между: продолжение A; $ this-> A и self :: A
Теги:
class
scope

22 ответа

1594
Лучший ответ

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

Используйте $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() функции what > - точный тип текущего объекта. Если объект имеет type X, он таким образом > вызывает X::foo(). Если объект имеет значение type Y, он вызывает Y::foo(). Но s > self:: foo(), X::foo() всегда вызывается.

Из http://www.phpbuilder.com/board/showthread.php?t=10354489:

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

  • 315
    Этот ответ слишком упрощен. Как указывалось в других ответах, self используется с оператором разрешения контекста :: для ссылки на текущий класс; это можно сделать как в статическом, так и в нестатическом контексте. Кроме того, вполне допустимо использовать $this для вызова статических методов (но не для ссылки на поля).
  • 47
    Также рассмотрите возможность использования static :: вместо :: self, если вы используете 5.3+. В противном случае это может вызвать невыразимые головные боли, см. Мой ответ ниже, почему.
Показать ещё 5 комментариев
677

Ключевое слово self does NOT относится только к "текущему классу", по крайней мере, не таким образом, что ограничивает вас статическими членами. В контексте нестатического члена 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();

Это выведет:

Привет, я Ludwig the geek
   До свидания с Людвигом человек

sayHello() использует указатель $this, поэтому vtable вызывается для вызова Geek::getTitle(). sayGoodbye() использует self::getTitle(), поэтому vtable не используется и вызывается Person::getTitle(). В обоих случаях мы имеем дело с методом объекта-экземпляра и имеем доступ к указателю $this внутри вызываемых функций.

  • 3
    Этот ответ будет еще лучше, если вы начнете с общего правила, а не исключения. Это вопрос стиля, а не технических знаний. Это лучший пример, который я когда-либо видел, о разнице между self :: и $ this->, но стыдно скрывать это, опровергая сначала понятие.
  • 3
    @adjwilli: Почему этот плохой стиль? Разве это не поднимает сознание, если ожидание (тезис) ОП сначала отвергается (антитезис), а затем объяснение дается как обобщение?
Показать ещё 2 комментария
429

НЕ ИСПОЛЬЗУЙТЕ 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";
    }

}

Calling Deceased::status() мы ожидаем увидеть "Человек умер", однако мы видим, что "Человек жив", поскольку область содержит определение исходного метода, когда был определен call to self::getStatus().

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

См. Документацию по PHP

Поэтому, чтобы ответить на вопрос, а не на вопрос...

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

  • 5
    Как насчет констант класса?
  • 1
    Я думаю, что то же самое идет
Показать ещё 4 комментария
229

Чтобы действительно понять, о чем мы говорим, когда говорим о self versus $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 типов "вещей", которые содержит класс:

  • Свойства. Подумайте об этом как о переменных, которые будут содержать каждый экземпляр.

    class Foo {
        public $bar = 1;
    }
    
  • Статические свойства. Подумайте об этом как о переменных, которые совместно используются на уровне класса. Это означает, что они никогда не копируются каждым экземпляром.

    class Foo {
        public static $bar = 1;
    }
    
  • Методы - это функции, которые каждый экземпляр будет содержать (и работать с экземплярами).

    class Foo {
        public function bar() {}
    }
    
  • Статические методы. Это функции, которые совместно используются во всем классе. Они работают не, но вместо этого действуют только статические свойства.

    class Foo {
        public static function bar() {}
    }
    
  • Константы - Константы разрешенных классов. Не углубляйтесь сюда, но добавляя для полноты:

    class Foo {
        const BAR = 1;
    }
    

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

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

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

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

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

Доступ к состоянию

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

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

С внешней стороны экземпляра/класса наши правила довольно просты и предсказуемы. У нас есть два оператора, и каждый говорит нам немедленно, если мы имеем дело с экземпляром или классом static:

  • -> - 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) с помощью объекта-оператора: $foo->bar() приведет к версии экземпляра $a.

Итак, как мы ожидаем.

Значение оператора :: меняется. Это зависит от контекста вызова текущей функции:

  • В статическом контексте

    В статическом контексте любые вызовы, сделанные с помощью ::, также будут статическими. Рассмотрим пример:

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

    Вызов Foo::bar() вызовет метод baz() статически, и, следовательно, $this будет заполнен not. Стоит отметить, что в последних версиях 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;
    }
}

Не всегда true.

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

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

TL/DR

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

TL/DR # 2

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

TL/DR # 3

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

  • 1
    Слово предостережения # 1: $ это не будет определено при вызове статического метода: 3v4l.org/9kr0e
  • 0
    Ну ... $this не будет определено, если вы следуете "Строгим Стандартам" и не вызываете методы статически, которые не определены как статические. Я вижу результат, который вы объяснили здесь: 3v4l.org/WeHVM Согласен, действительно странно.
Показать ещё 5 комментариев
104

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

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

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

97

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

Example: 
$derek = new Person();

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

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

Статические методы (т.е. 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 function prettyName ничего не знает об объекте. Он просто работает с параметрами, которые вы проходите, как обычная функция, которая не является частью объекта. Зачем же беспокоиться, если бы мы могли просто иметь это не как часть объекта?

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

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

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

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

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

Надеюсь, что помогает разобраться :)

  • 2
    У вас есть $ ronny во втором абзаце текста, но если я не ошибаюсь, это должен был быть $ derek.
  • 0
    Отличный ответ. Я просто хочу отметить, что при обращении к статическому атрибуту необходимо использовать знак $ . Например, self::$templates_path
28

От этого сообщения в блоге:

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

В 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 относится к классу текущего объекта.

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

19

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

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

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

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

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

  • 6
    Предложение: Прочтите этот ответ, когда спотыкаетесь о кислоту.
12

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

Выход: родительский ребенок

12

Поскольку здесь никто не говорил о спектаклях, вот небольшой тест, который я сделал (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.
  • 0
    Старый добрый PHP. :) Но звонок = 0,001мс. Это так плохо?
Показать ещё 3 комментария
11

Я считаю, что вопрос не в том, можно ли вызвать статический член класса, вызвав 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;
    }
}
  • 0
    Особенно забавно, что вы начинаете свой ответ с «Я полагаю, вопрос был не в том, можете ли вы вызвать статический член класса, вызвав ClassName :: staticMember. Вопрос в том, в чем разница между использованием self :: classmember и $ this-> classmember» и затем вы продолжаете показывать никаких различий вообще. Фактически, вы показываете пример, где эти два варианта работают одинаково. -1
  • 0
    Тем не менее полезно. Сфера была о разрешении, и эта часть не ясна в руководстве по PHP. Я все еще нахожу это полезным
Показать ещё 1 комментарий
10

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

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

5

Кроме того, поскольку $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

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

Иными словами, используйте self for static и this for none-static members or methods.

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

4

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

1

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

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

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

1

Случай 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;
   }
}
0

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню