Какой смысл иметь $ this и self :: в PHP? - PullRequest
19 голосов
/ 27 июля 2010

Почему PHP требует, чтобы вы явно написали $this? Я бы понял, если бы вам пришлось использовать $this здесь:

function foo($bar) {
   $this->bar = $bar;
}

Но вы должны написать это явно в подробном коде, который выглядит следующим образом:

$this->var3 = globalFun($this->var, $this->var2[$this->anotherVar], $this->method());

вместо:

$var3 = globaFun($var, $var2[$anotherVar], method());

Так в чем же смысл $this?

Дополнительный бонусный вопрос:

Почему мы должны различать статические ссылки и экземпляры? Зачем нам нужно:

static function getValue() {
   return self::value;
}

Не может ли PHP определить во время выполнения, является ли рассматриваемая переменная / метод статическим? Теперь, если я хочу изменить метод со статического на нестатический, я должен заменить все эти self:: на $this-> (и наоборот).

Не было бы лучше, если бы у нас был $this, который ведет себя так же, как в Java?

Ответы [ 4 ]

15 голосов
/ 31 июля 2010

Так как это было вновь открыто, я отправлю сюда мой ответ , как и обещал.

TL; версия DR Если бы не требовалось квалифицировать доступ к элементу, то были бы не только штрафы за производительность, но и одна и та же строка кода могла одновременно означать доступ к полю и доступ к локальной переменной, в зависимости от пути к коду.

Полная версия

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

Чтобы перенести данную переменную в область действия функции, вы должны явно указать свое намерение, создав ссылку. Примеры:

$myglobal = 7;
class A {
    private $prop;
    public function meth() {
        global $myglobal; //bring a global to the current scope
        $prop =& $this->prop; //brings a property to the current scope
        $local = 4;
        $lambda = function () use (&$local) { };
    }
}

Очевидно, это просто более изощренный способ выражения того, что происходит в настоящее время. Вопрос почему это поведение?

В конце концов, в Java мы должны набирать this.prop только когда есть локальная переменная с именем prop, скрывающая свойство. Почему это не очень хороший вариант для PHP?

Я могу придумать несколько причин.

Свойства объекта определяются во время выполнения

В PHP есть нечто, называемое "динамическими свойствами". Вы можете назначать новые свойства объектам во время выполнения. Фактически, при наличии двух объектов одного и того же класса один может иметь заданное свойство $a, а другой - нет. Пример:

$obj1 = new stdClass();
$obj2 = new stdClass();
$obj1->a = 7;

В PHP определенные локальные переменные определяются во время выполнения

Переменные не должны быть объявлены; следовательно, в зависимости от пути кода, в какой-то момент переменная может быть или не быть определена. Чтобы добавить оскорбление ране, у нас также есть монстр, названный "переменными переменными". Пример:

class A {
    private $g = 3;
    public function func($varname) {
        if (rand(1,2) == 1) {
            $g = 4; //no block scope; the scope is the function's
        }
        $$varname = 5; //god knows what's happening here
        //if local variables hid properties, we'd have trouble
    }
}

В Java данный идентификатор может также представлять внутри той же функции локальную переменную и свойство, но:

  • Не в одном и том же блоке (в PHP все блоки в функции имеют одинаковую область видимости).
  • Вы получаете предупреждение, если скрываете собственность.
  • Важно отметить, что в любом конкретном случае идентификатора это либо свойство, либо локальная переменная , иногда он не может быть один и другой раз другим.

Последствия * * тысяча пятьдесят один Из-за этих фактов было бы невозможно определить во время компиляции, если $var ссылается на локальную переменную или свойство. Следовательно: Во время выполнения каждый раз, когда возникала переменная, она должна была бы искать сначала в локальной таблице символов, затем в таблице свойств экземпляра и, наконец, в списке статических свойств или в любом другом порядке (так как не может быть экземпляром, и необходимо объявить статическое свойство с тем же именем и статическими свойствами, здесь был бы некоторый потенциал оптимизации, но точка зрения остается в силе). Это означает, что символ в худшем случае придется искать в трех разных местах. Это плохо с точки зрения производительности. Данное появление символа может означать разные вещи в разных случаях. Это рецепт катастрофы.

14 голосов
/ 31 июля 2010

Хорошо, давайте избавимся от необходимости писать $this везде. Посмотрите на эту ситуацию:

class Foo {
    public function setBar($value) {
        $bar = $value;
    }
}
$foo = new Foo();
$foo->setBar('some value');

Является ли $bar локальной переменной или членом $foo?

Должна быть некоторая дифференциация. Они могли бы разрешить объявление локальных переменных с ключевым словом var, но это не было бы обратно совместимым и могло бы очень запутать людей, переходящих с более старых версий PHP.

То же самое относится к self::. Как интерпретатор узнает, является ли функция, которую вы хотите вызвать, глобальной или специфичной для класса?

6 голосов
/ 27 июля 2010

PHP не был ООП.

Сейчас так и есть, но с побочными эффектами.

1 голос
/ 27 июля 2010

На самом деле, я знаю людей, которые используют это. в Java даже там, где это не нужно, потому что они чувствуют, что это создает более четкий код;) У меня нет действительно определенного ответа, но я думаю, что внутреннее получение $ var всегда должно быть переведено в $ this-> var. Так что это не значит, что кто-то намеренно усложнил ситуацию, заставив нас сделать $ this-> var, но просто решил не использовать ярлык $ var. Если это поможет, я не знаю;)

...