Pull to refresh

Вышла PHP 7 beta 1

Reading time 5 min
Views 29K
Собственно представлена первая бета-версия PHP 7, хороший анонс с изменениями был на хабре ранее (по альфе).

В тексте новости на сайте опубликована ссылка на документ UPGRADING, где описываются несовместимости «семерки». Помимо выкинутых, как обычно, DEPRECATED функций и расширений (исчезла масса SAPI модулей), заметные изменения произошли в самом языке. Ниже — о части из них.

По порядку из официального документа:

Изменения в обработке переменных

1. Косвенные ссылки на переменные, свойства и методы теперь разбираются слева направо. Восстановить прежний порядок можно фигурными скобками.
$$foo['bar']['baz']   // разбирается как ($$foo)['bar']['baz']    - ранее как ${$foo['bar']['baz']}
$foo->$bar['baz']   // разбирается как ($foo->$bar)['baz']    - ранее как $foo->{$bar['baz']}
$foo->$bar['baz']() // разбирается как ($foo->$bar)['baz']() - ранее как $foo->{$bar['baz']}()
Foo::$bar['baz']()   // разбирается как (Foo::$bar)['baz']()   - ранее как Foo::{$bar['baz']}()


2. Ключевое слово global принимает только простые переменные. Вместо global $$foo->bar следует писать global ${$foo->bar}

3. Скобки вокруг переменных или вызовов функций больше не влияют на поведение. Например, код, где результат функции передается по ссылке:
      function getArray() { return [1, 2, 3]; }

      $last = array_pop(getArray());
      // Strict Standards: Only variables should be passed by reference
      $last = array_pop((getArray()));
      // Strict Standards: Only variables should be passed by reference


сейчас выбросит ошибку strict standards вне зависимости от скобок (ранее во втором вызове ее не было).

4. Элементы массива или свойства объекта, которые были автоматически созданы во время присвоений по ссылке сейчас будут иметь другой порядок. Код:
      $array = [];
      $array["a"] =& $array["b"];
      $array["b"] = 1;
      var_dump($array);

сейчас сгенерирует массив [«a» => 1, «b» => 1], тогда как ранее был [«b» => 1, «a» => 1].

Изменения в обработке list()

1. list() теперь присваивает переменные в прямом порядке (ранее — в обратном), например:
      list($array[], $array[], $array[]) = [1, 2, 3];
      var_dump($array);

сейчас выдаст $array == [1, 2, 3] вместо [3, 2, 1]. Изменился только порядок присвоения, т.е. нормальное использование list() не затронуто.

2. Присвоения с пустым списком list() стали запрещены, следующие выражения ошибочны:
      list() = $a;
      list(,,) = $a;
      list($x, list(), $y) = $a;


3. list() больше не поддерживает распаковку строк (ранее поддерживалась в некоторых случаях). Код:
      $string = "xy";
      list($x, $y) = $string;

установит $x и $y в значение null (без предупреждений) вместо $x == «x» и $y == «y». Более того, list() теперь гарантированно работает с объектами, реализующими интерфейс ArrayAccess, т.е. вот так заработает:
      list($a, $b) = (object) new ArrayObject([0, 1]);

Ранее в обе переменные был бы занесен null.

Изменения в foreach

1. Итерации в foreach() больше не влияют на внутренний указатель массива, который доступен через семейство функций current()/next()/…
      $array = [0, 1, 2];
      foreach ($array as &$val) {
          var_dump(current($array));
      }

сейчас напечатает int(0) три раза. Ранее — int(1), int(2), bool(false)

2. Во время итерирования массивов по значению, foreach теперь пользуется копией массива, и его изменения внутри цикла не повлияют на поведение цикла:
      $array = [0, 1, 2];
      $ref =& $array; // необходимо, чтобы включить старое поведение
      foreach ($array as $val) {
          var_dump($val);
          unset($array[1]);
      }

Код напечатает все значения (0 1 2), ранее второй элемент выкидывался — (0 2).

3. Когда итерируются массивы по ссылке, изменения в массиве будут влиять на цикл. Предполагается, что PHP лучше будет отрабатывать ряд случаев, например, добавление в конец массива:
      $array = [0];
      foreach ($array as &$val) {
          var_dump($val);
          $array[1] = 1;
      }

проитерирует и добавленный элемент. Вывод будет «int(0) int(1)», ранее было только «int(0)».

4. Итерирование обычных (не Traversable) объектов по значению или по ссылке будет вести себя как итерирование по ссылке для массивов. Ранее — аналогично, за исключением более точного позиционирования из предыдущего пункта.

5. Итерирование Traversable объектов не изменилось.

Изменения в обработке аргументов функций

1. Больше нельзя использовать одинаковые имена для аргументов (будет ошибка компиляции):
      public function foo($a, $b, $unused, $unused) {
          // ...
      }


2. Функции func_get_arg() и func_get_args() теперь вернут текущее значение (а не исходное). Например:
      function foo($x) {
          $x++;
          var_dump(func_get_arg(0));
      }
      foo(1);

выведет «2» вместо «1».

3. Похожим образом трейсы в исключениях не будет выводить оригинальные значения, а уже измененные:
      function foo($x) {
          $x = 42;
          throw new Exception;
      }
      foo("string");

теперь выдаст:
Stack trace:
#0 file.php(4): foo(42)
#1 {main}


Ранее было бы так:
Stack trace:
#0 file.php(4): foo('string')
#1 {main}


Хоть это и не влияет на исполнение, но следует иметь это в виду при отладке. То же ограничение теперь и в debug_backtrace() и прочих функциях, исследующих аргументы.

Изменения в обработке integer

1. Некорректные восьмеричные числа будут выдавать ошибку компиляции:
      $i = 0781; // 8 - неверный разряд для восьмеричного числа


Ранее все после некорректного разряда отбрасывалось, и в $i была бы 7.

2. Побитовые сдвиги на отрицательные числа теперь бросают ArithmeticError:
      var_dump(1 >> -1);
      // ArithmeticError: Bit shift by negative number


3. Сдвиг влево на число, большее разрядности, вернет 0:
      var_dump(1 << 64); // int(0)


Ранее поведение зависело от архитектуры, на x86 и x86-64 результат был == 1, т.к. сдвиг был циклическим.

4. Аналогично сдвиг вправо даст 0 или -1 (зависит от знака):
      var_dump(1 >> 64);  // int(0)
      var_dump(-1 >> 64); // int(-1)


Изменения в обработке ошибок

1. Больше не парсятся в числа строки с шестнадцатиричными числами:
      var_dump("0x123" == "291");     // bool(false)     (ранее true)
      var_dump(is_numeric("0x123"));  // bool(false)     (ранее true)
      var_dump("0xe" + "0x1");        // int(0)          (ранее 16)

      var_dump(substr("foo", "0x1")); // string(3) "foo" (ранее "oo")
      // Notice: A non well formed numeric value encountered


filter_var() может использоваться для проверки строки на содержание шестнадцатиричного числа или конвертации в обычное число:
    $str = "0xffff";
    $int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
    if (false === $int) {
        throw new Exception("Invalid integer!");
    }
    var_dump($int); // int(65535)


2. Из-за добавления эскейп-синтаксиса для юникода, строки в двойных кавычках и heredoc должны это учитывать:
      $str = "\u{xyz}"; // Fatal error: Invalid UTF-8 codepoint escape sequence


Необходимо двойное экранирования слэша:
      $str = "\\u{xyz}";

Хотя простое "\u" без последующей { не затронуто, и вот так заработает без изменений:
      $str = "\u202e";


Про новую обработку ошибок уже здесь писали, не буду повторяться. Из интересного еще можно добавить, что конструкторы встроенных классов теперь всегда кидают исключения, тогда как ранее некоторые просто возвращали null.

Из других изменений документ отмечает теперь отсутствие $this для нестатических методов, вызванных статически (ранее метод использовал $this вызывающего контекста).

Пополнился, что логично, список недоступных для классов, трейтов и интерфейсов имен — добавлены bool, int, float, string, null, false, true, а также для будущего использования: resource, object, mixed, numeric.

Конструкт yield не требует больше скобок при использовании в выражениях. Он теперь право-ассоциативный оператор с приоритетом между «print» и "=>". Поэтому поведение может измениться:

      echo yield -1;
      // ранее интерпретировалось как
      echo (yield) - 1;
      // а сейчас как
      echo yield (-1);


      yield $foo or die;
      // ранее интерпретировалось как
      yield ($foo or die);
      // а сейчас как
      (yield $foo) or die;


Эти случаи рекомендуется принудительно уточнять скобками.

Из заметных изменений в стандартной библиотеке функций отмечу только удаление call_user_method() и call_user_method_array(), остальное не столь значительно (выкинули dl() в php-fpm, переименовали и оптимизировали zend_qsort -> zend_sort, добавили zend_insert_sort, немного поменяли поведение setcookie при пустом имени cookie и убрали фатальную ошибку ob_start внутри буферизации).
Tags:
Hubs:
+28
Comments 62
Comments Comments 62

Articles