Ответ 1
Это очень важный вопрос.
1. Приоритет между [...]
Во-первых, никогда не бывает двусмысленности в отношении того, что PHP должен сначала оценить, глядя на
правая сторона [
, так как скобка требует закрытия, чтобы идти с ней, и поэтому
каждый оператор между ними имеет приоритет над открывающей скобкой.
Пример:
$a[1+2]
+
имеет приоритет, т.е. первый 1 + 2 должен быть оценен до того, как PHP сможет определить,
элемент для из $a.
Но список приоритетов операторов не об этом.
2. Ассоциативность
Во-вторых, существует порядок оценки последовательных пар []
, как здесь:
$b[1][2]
PHP сначала оценит $b[1]
, а затем применит к нему [2]
. Это слева направо
оценки и является тем, что предполагается с левой ассоциативностью.
Но вопрос заключается не столько в ассоциативности, сколько в отношении приоритетов в отношении других операторов.
3. Приоритет над операторами в левой части
В списке указано, что операторы clone
и new
имеют приоритет над [
, и это непросто проверить.
Прежде всего, большинство конструктов, в которых вы бы объединили new
с квадратными скобками, считаются недействительными
синтаксис. Например, оба этих утверждения:
$a = new myClass()[0];
$a = new myClass[0];
даст ошибку синтаксического анализа:
синтаксическая ошибка, неожиданная '['
PHP требует, чтобы вы добавляли круглые скобки, чтобы сделать синтаксис действительным. Таким образом, мы не можем проверить правила приоритета, подобные этому.
Но есть и другой способ, используя переменную, содержащую имя класса:
$a = new $test[0];
Это допустимый синтаксис, но теперь задача состоит в том, чтобы создать класс, который создает что-то который действует как массив.
Это не так просто, поскольку свойство объекта ссылается следующим образом: obj->prop
, not
как obj["prop"]
. Однако можно использовать класс ArrayObject, который может иметь дело с квадратными скобками. Идея состоит в том, чтобы расширить этот класс и переопределить метод offsetGet, чтобы убедиться, что только что созданный объект этого класса возвратил элементы массива.
Чтобы сделать объекты доступными для печати, я закончил использование магического метода __ toString, который выполняется, когда объект должен быть перенесен в строку.
Итак, я придумал эту настройку, определив два похожих класса:
class T extends ArrayObject {
public function __toString() {
return "I am a T object";
}
public function offsetGet ($offset) {
return "I am a T object array element";
}
}
class TestClass extends ArrayObject {
public function __toString() {
return "I am a TestClass object";
}
public function offsetGet ($offset) {
return "I am a TestClass object array element";
}
}
$test = "TestClass";
С помощью этой настройки мы можем проверить несколько вещей.
Тест 1
echo new $test;
Этот оператор создает новый экземпляр TestClass, который затем необходимо преобразовать в string, поэтому метод __toString вызывается в этом новом экземпляре, который возвращает:
Я объект TestClass
Это как и ожидалось.
Тест 2
echo (new $test)[0];
Здесь мы начинаем с одних и тех же действий, так как скобки принудительно выполняют операцию new
. На этот раз PHP не преобразует созданный объект в строку, а запрашивает из него элемент массива 0. На этот запрос отвечает метод offsetGet, и поэтому выведенный выше вывод выводит:
Я - элемент массива объекта TestClass
Тест 3
echo new ($test[0]);
Идея состоит в том, чтобы заставить противоположный порядок исполнения. К сожалению, PHP не позволяет использовать этот синтаксис, поэтому для того, чтобы получить предполагаемый порядок оценки, вам придется разбить оператор на две части:
$name = $test[0];
echo new $name;
Итак, теперь выполняется [
, беря первый символ значения
$ test, т.е. "T", а затем new
. Вот почему я
определял также класс Т. echo
вызывает этот экземпляр __toString, который дает:
Я объект T
Теперь идет заключительный тест, чтобы увидеть, какой порядок, когда нет круглых скобок:
Тест 4
echo new $test[0];
Это допустимый синтаксис и...
4. Вывод
Вывод:
Я объект T
Таким образом, PHP применял [
до оператора new
, несмотря на то, что указано в
таблица приоритетов операторов!
5. Сравнивая clone
с new
Оператор clone
имеет аналогичное поведение в сочетании с [
. Как ни странно, clone
и new
не полностью равны в терминах правил синтаксиса. Повторный тест 2 с помощью clone
:
echo (clone $test)[0];
выдает ошибку синтаксического анализа:
синтаксическая ошибка, неожиданная '['
Но тест 4, повторенный с помощью clone
, показывает, что [
имеет приоритет над ним.
@bishop сообщил, что это воспроизводит долговременную ошибку документации # 61513: "clone
приоритет оператора неверен" .