Новая личность против новой статики

513

Я конвертирую библиотеку PHP 5.3 для работы на PHP 5.2. Главное, что стоит на моем пути, это использование позднего статического связывания, например return new static($options);, если я преобразую это в return new self($options), получу ли я те же результаты?

В чем разница между new selfи new static?

Майк
источник

Ответы:

891

я получу те же результаты?

На самом деле, нет. Хотя я не знаю обходного пути для PHP 5.2.

В чем разница между new selfи new static?

selfотносится к тому же классу, в котором newключевое слово фактически написано.

staticв поздних статических привязках PHP 5.3 относится к любому классу в иерархии, для которой вы вызвали метод.

В следующем примере Bоба метода наследуются от A. selfВызов связан с , Aпотому что это определено в Aреализации «S первого способа, в то время как staticпривязан к называемому классу (также см get_called_class()).

class A {
    public static function get_self() {
        return new self();
    }

    public static function get_static() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A
BoltClock
источник
имеет смысл. Я думаю, что лучше всего передать имя класса функции, использующей позднюю статическую привязку, а затем вернуть new $ className ($ options);
Майк
12
Вам не нужно «передавать» имя класса, вы всегда можете это сделать get_called_class(), что фактически совпадает с __CLASS__LSB-совместимостью.
Shadowhand
7
get_called_class не существует в <PHP5.3. Следовательно, если вы хотите получить имя класса экземпляра объекта в PHP5.2, эта функция не помогает при попытке преобразовать библиотеку из PHP 5.3 в PHP 5.2
txwikinger
2
Функция, называемая self :: theFunction (), ведет себя как «Я буду выполнять в контексте класса, к которому я физически принадлежу». и функция, называемая static :: theFunction (), ведет себя как «я буду выполнять в контексте класса, который был фактически вызван внешним миром». (Предполагая сценарий наследования). Спасибо
Шубхраншу
2
В своей голове я просто беру все, что интуитивно понятно, и делаю все наоборот. Вы можете подумать, основываясь на именовании, selfвернет себя и staticвернет что-то, что не может быть переопределено ... Но вот и все наоборот. Я никогда не перестаю удивляться именам, соглашениям и общему стилю PHP. -_-
Анбизкад
23

Если метод этого кода не статичен, вы можете обойти его в 5.2 с помощью get_class($this).

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

Результаты:

string(1) "B"
string(1) "B"
Мариус Балчитис
источник
17
Если метод не является статичным, поздние статические привязки становятся совершенно неактуальными.
BoltClock
1
Например, вы можете использовать его в методе «копировать», где объект копируется без использования clone, а просто путем повторного создания и установки свойств. $copy = new static(); $copy->set($this->get()); return $copy;
Мариус Балчитис
9
@BoltClock Конечно нет? Если вы вызываете переопределенный статический метод из метода экземпляра подкласса, то ваш выбор self::или static::будет влиять на то, используется ли версия этого статического метода базовым классом или подклассом. В отсутствие какой-либо причины полагать, что такая ситуация по своей сути указывает на плохую практику (и я не вижу никаких причин, почему это должно быть так), выбор между self::и static::столь же уместен в нестатических методах, как и в статические методы. Я неправильно понял ваш комментарий или один из нас просто неправ?
Марк Эмери
4
@ Марк Эмери: Хм, я не думал об этом. Ты абсолютно прав. Я предполагал, что никакие статические методы не будут вызываться в рассматриваемом методе экземпляра, но на основании вашего примера я вижу, как это было бы очень наивным предположением.
BoltClock
Поздние статические привязки doc => php.net/manual/en/language.oop5.late-static-bindings.php
DevWL
7

В дополнение к ответам других:

static :: будет вычислено с использованием информации времени выполнения.

Это означает, что вы не можете использовать static::в свойстве класса, потому что значения свойств:

Должен быть в состоянии быть оцененным во время компиляции и не должен зависеть от информации времени выполнения.

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

С помощью self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

Обратите внимание, что комментарий к фатальной ошибке в коде, который я сделал, не указывает, где произошла ошибка, ошибка произошла раньше, чем объект был создан как @Grapestain, упомянутый в комментариях.

дождь
источник
4
Обратите внимание, что ошибка выводится в строке 2 public $name = static::class;, а не в строке 7, как показано в примере. В сообщении об ошибке говорится: «static :: class нельзя использовать для разрешения имен классов во время компиляции», что указывает на то, что проблема заключается не в том, где вы пытаетесь получить доступ к полю $ name, а гораздо раньше - при компиляции класса PHP. Строка 7 (или 6) не будет достигнута в первом примере.
sbnc.eu
@Grapestain Комментарий, который я сделал в этом примере, должен был показать конечный результат, а не указывать, где на самом деле произошла ошибка. Но в любом случае спасибо за указание на это.
дождь
Правильно, я не хотел критиковать, просто пояснил, что смутило меня первым в надежде, что это поможет другим. Полезный пример в любом случае!
sbnc.eu