Правильно ли я понимаю смысл статических и не статических объектов (this self)?

Всё было бы намного проще если бы в PHP были статические классы (как в C#)...
Когда класс, призванный быть статическим (так его спроектировали) может иметь экземпляр класса, это ни есть хорошо (ИМХО).

Но к вопросу.

Просто пример рабочего кода.
class MyClass
{
    private $myField;
    private static $myStaticField;

    public function MyMethod($value)
    {
        $this->myField = $value;
        echo $this->myField;
    }

    public static function MyStaticMethod($value)
    {
        self::$myField = $value;
        echo self::$myField;
    }

    public static function MyStaticMethod1($value)
    {
        self::$myStaticField = $value;
        echo self::$myStaticField;
    }


}

$myClass = new MyClass();
$myClass->MyMethod(0);
//$myClass::MyStaticMethod(0); // Access to undeclared static property:
$myClass::MyStaticMethod1(1);


Правильно ли я понимаю, что:
1) $this всегда используется для доступа к нестатическим полям и методам класса
2) self всегда используется для доступа к статическим полям и методам класса
3) синтаксис $this при обращении к полю класса содержит знак $ у this и не содержит у поля ($this->myField),
а синтаксис self наоборот содержит знак $ у поля и не содержит у self (self::$myField) - это немного странно т.к. могли бы сделать однотипно (ИМХО).
4) лучше (идеологически верно) создавать либо полностью статические классы (где всё статика), либо не статические классы (где предполагается множество экземпляров)
  • Вопрос задан
  • 143 просмотра
Пригласить эксперта
Ответы на вопрос 2
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
1. $this указывает на текущий экземпляр класса, в контексте которого был вызван метод. Но доступ к нестатическим свойствам и методам возможен для любого экземпляра (к публичным из любого контекста, к приватным и защищённым изнутри класса).
2. self используется для доступа к классу, в котором описан метод, static для доступа к классу, в котором вызван метод, parent для доступа к родительскому классу.
4. В нестатических классах C# не запрещено создавать статические методы. Если эти статические методы в классе нужны, то ничто не мешает их создать.
Ответ написан
Комментировать
Amega
@Amega
Senior PHP Developer
Говоря о self, static и $this, это вопрос не только о статических/нестатических свойствах/методах, но и о Позднем статическом связывании. Поэтому ваше понимание лишь отчасти верное. Думаю, здесь нет смысла пересказывать приведенную документацию, но приведу пример, который, надеюсь, наглядно покажет некоторые различия.

<?php

class A {
	protected int $num;
	
	public function __construct(int $num)
	{
		$this->num = $num;
	}
	
	protected function getNum(): int
	{
		print(__METHOD__ . PHP_EOL);
		return $this->num;
	}
	
	public function getThisNum(): int
	{
		return $this->getNum();
	}
	
	public function getStaticNum(): int
	{
		return static::getNum();
	}
	
	public function getSelfNum(): int
	{
		return self::getNum();
	}
}

class B extends A {
	protected function getNum(): int {
		print(__METHOD__ . PHP_EOL);
		return $this->num + 5;
	}
}

$b = new B(5);
print($b->getThisNum() . PHP_EOL);
print($b->getStaticNum() . PHP_EOL);
print($b->getSelfNum() . PHP_EOL);

B::getNum
10
B::getNum
10
A::getNum
5


Поясню вкратце. Метод `getNum` определен в базовом классе A, но переопределено в классе B. При этом мы дальше создаем экземпляр класса B и работаем уже "через" него. Но все используемые нами методы определены только в классе A и унаследованы в B. Происходит тут примерно следующее:

  1. $this - это ссылка на текущий объект (экземпляр класса B), но в области видимости A. Это тоже не самая тривиальная связка для понимания. Но суть в том, что поскольку нам отсюда виден метод getNum, определенный в классе B, будет вызван он. Если метод getNum был бы приватным, то его "версия" в B была бы не видна, и вызвался бы этот метод из A. Ниже приведу еще дополнительные примеры по поводу этого.


  2. Вызывается static::getNum. В данном случае мы "принудительно" вызываем метод того класса, экземпляром которого мы сейчас являемся, то есть B. Если бы метод getNum был приватным, здесь была бы ошибка, поскольку пытаемся дернуть метод, недоступный нам по области видимости.


  3. Вызывается self::getNum. В данном случае мы вызываем метод именно того класса, в котором находимся, то есть A, несмотря на то, что работаем по факту с экземпляром B.



Говоря об областях видимости, полезно будет также разобраться с замыканиями (Closure), а еще лучше - непосредственно поиграться с ними. Или если быть точнее, с привязкой их (bind) к разным объектам.

Для примера можно взглянуть на этот код
<?php

class A {
	private $num = 1;
}

class B extends A {
	private $num = 2;
}

$closure = function() {
	return $this->num;
};

$closureAA = $closure->bindTo(new A(), 'A');
$closureAB = $closure->bindTo(new A(), 'B');
$closureBA = $closure->bindTo(new B(), 'A');
$closureBB = $closure->bindTo(new B(), 'B');

print($closureAA() . PHP_EOL);
// будет ошибка, поскольку из B пытаемся получить приватное поле A
// print($closureAB() . PHP_EOL);
print($closureBA() . PHP_EOL);
print($closureBB() . PHP_EOL);

1
1
2
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы