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

Вы сталкиваетесь с классической проблемой. Вам нужно using CParent::doIt; в вашем классе CChild.

Изменить:

Вот мой ответ по существу на тот же вопрос: Переопределение перегруженной базы Base в C ++

1910
задан YanDatsiuk 24 June 2019 в 19:03
поделиться

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() того, что является точным типом текущего объекта. Если объект имеет значение 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 [+1122]

1635
ответ дан allen 24 June 2019 в 19:03
поделиться

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

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

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

6
ответ дан Mike 24 June 2019 в 19:03
поделиться

Я считаю, что вопрос не в том, можно ли вызвать статический член класса, вызвав 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;
    }
}
14
ответ дан Akintunde-Rotimi 24 June 2019 в 19:03
поделиться

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

20
ответ дан Akintunde-Rotimi 24 June 2019 в 19:03
поделиться

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

5
ответ дан Akintunde-Rotimi 24 June 2019 в 19:03
поделиться

Вот пример правильного использования $ 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();
?> 
20
ответ дан Mohit Bumb 24 June 2019 в 19:03
поделиться

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

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

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

115
ответ дан STT LCU 24 June 2019 в 19:03
поделиться

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

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

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

7
ответ дан Rakesh Singh 24 June 2019 в 19:03
поделиться
  • Указатель на объект $ 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
ответ дан Xeoncross 24 June 2019 в 19:03
поделиться

НЕ ИСПОЛЬЗУЙТЕ 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 для этого вам нужно будет найти ключ.

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

Поэтому ответить на вопрос не так, как задано ...

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

448
ответ дан bluish 24 June 2019 в 19:03
поделиться

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

Example: 
$derek = new Person();

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

ClassName :: используется для ссылки на этот тип класса и его статические переменные, статические методы. Если это поможет, вы можете мысленно заменить слово «статический» на «общий». Поскольку они являются общими, они не могут ссылаться на $ this, что относится к конкретному экземпляру (не общему). Статические переменные (то есть static $ 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 Pattern).

Статические методы (то есть 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);

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

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

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

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

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

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

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

96
ответ дан Akintunde-Rotimi 24 June 2019 в 19:03
поделиться

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

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

1
ответ дан trincot 24 June 2019 в 19:03
поделиться

Поскольку здесь никто не говорил о выступлениях, вот небольшой тест, который я сделал (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();
14
ответ дан tleb 24 June 2019 в 19:03
поделиться

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

731
ответ дан Marcin Orlowski 24 June 2019 в 19:03
поделиться

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

13
ответ дан Holger Just 24 June 2019 в 19:03
поделиться

В 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 недоступно или когда вы не хотите, чтобы классы-потомки перезаписывали текущий метод.

25
ответ дан Akib Bagwan 24 June 2019 в 19:03
поделиться

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

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

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

.
7
ответ дан fyrye 24 June 2019 в 19:03
поделиться

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

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

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

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

class classC {
     public function __construct() { 
     self::

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

[110]

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

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

[111]counter++; $this->num = self::

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

[110]

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

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

[111]counter; } }
2
ответ дан perror 24 June 2019 в 19:03
поделиться

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

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

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  
21
ответ дан Tarun Singhal 24 June 2019 в 19:03
поделиться

Чтобы по-настоящему понять, о чем мы говорим, когда говорим о 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 не определена . Это потому, что нет никакого экземпляра, связанного со статическим вызовом.

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

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

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

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

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

  • -> - объект-оператор - это всегда используется, когда мы обращаемся к экземпляру.

    $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

Таким образом, счетчик идентификаторов является общим для обоих экземпляров и дочерних элементов (потому что мы используя self для доступа к нему. Если бы мы использовали static, мы могли бы переопределить его в дочернем классе).

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

Обратите внимание, что мы каждый раз выполняем метод Person::getName() instance . Но мы используем parent::getName(), чтобы сделать это в одном из случаев (дочерний случай). Вот что делает этот подход мощным.

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

Обратите внимание, что вызывающий контекст - это то, что определяет, используется ли экземпляр. Следовательно:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

Не всегда всегда верно.

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

Теперь действительно странно здесь. Мы вызываем другой класс, но $this, который передается методу Foo::isFoo(), является экземпляром $bar.

Это может вызвать всевозможные ошибки и концептуальные WTF-ошибки. Поэтому я настоятельно рекомендую избегать использования оператора :: из методов экземпляра для чего-либо, кроме этих трех виртуальных «сокращенных» ключевых слов (static, self и parent).

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

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

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

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

TL / DR

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

TL / DR # 2

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

TL / DR # 3

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

240
ответ дан Community 24 June 2019 в 19:03
поделиться

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

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

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

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

15
ответ дан Akintunde-Rotimi 24 June 2019 в 19:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: