PHP 7.1: Обзор новых возможностей

    image На Хабре уже был перевод с обзором несколько месяцев назад, но недавно вышел первый релиз-кандидат PHP 7.1, а значит никаких существенных изменений больше не будет и можно сказать, какие точно изменения будут в релизе. Я решил немного оживить сухой “changelog” своим вольным переводом изменений, которые принесет нам новая минорная версия 7.х ветки.

    Новая функциональность


    Добавлен возвращаемый тип «void» (RFC)


    Теперь функции и методы, которые не должны ничего возвращать, можно помечать возвращаемым типом void:

    function someNethod(): void {
        // работает если return отсутсвует
        // работает с return;
        // не работает если return null;
        // не работает если return 123;
    }

    Возврат какого-то значения из метода/функции, который помечен как void, будет генерировать исключение уровня Fatal Error. Обратите внимание, что NULL значение не приравнивается к void (отсутствию значения), то есть возращать NULL нельзя.

    Кстати, это не значит что $x = someNethod(); не вернет ничего. Как и прежде в $x будет значение NULL. Так же void нельзя использовать как тип к параметру.

    
    function bar(void $foo) {}
    // Выбросит: Fatal error: void cannot be used as a parameter type in....
    

    Добавлен новый псевдо-тип: «iterable» (RFC)


    
    function walkList(iterable $list): iterable {
        foreach ($list as $value) {
            yield $value[‘id’];
        }
    }
    

    Этот тип по сути объединяет примитивный тип array и интерфейс Traversable (а значит и его производные: Iterator, Generator, etc). Проблема возникла на почве того, что к примеру, foreach может работать с обоими типами, но функция с типом array не примет объект с интерфейсом Traversable и наоборот.

    Так же в рамках этого RFC была добавлена новая функция is_iterable(), которая работает аналогично другим is_* функциям.

    Появилась возможность разрешать null в типизированных и возвращаемых параметрах (Nullable RFC)


    
        function callMethod(?Bar $bar): ?Bar {}
        $this->callMethod($bar); // Работает
        $this->callMethod(null);   // Работает
        $this->callMethod();        // НЕ работает
    

    Обратите внимание, что использование "?" и значение null по умолчанию не одно и тоже что

    
     function callMethod(int $bar = null) {}
    $this->callMethod(1); // Работает
    $this->callMethod(null); // Работает
    $this->callMethod(); // Тоже работает
    

    Причем добавление "?" оставляет поведение обратно совместимым

    function callMethod(?Bar $bar = null) {}
     // Работает так же как и без “?”
    

    Также важный момент по наследованию:

    
    interface Fooable {
        function foo(int $i): ?Fooable;
    }
    interface StrictFooable extends Fooable {
        function foo(?int $i): Fooable; // valid
    }

    В наследнике можно делать «строже» возвращаемый тип (то есть запрещать nullable), а параметр наоборот расширять до nullable, НО не наоборот!

    Добавлена возможность использовать отрицательное значение для смещения в строках (RFC)


    echo $msg[-1]; // вернет последний символ
    echo $msg{-3}; // Причем RFC явно рекомендует использовать способ $str{} так как $str[] может сбивать с толку И в будущем может быть объявлен как устаревшим.

    Отрицательные значения так же стали разрешены в некоторых строковых функциях: strpos, stripos, substr_count, grapheme_strpos, grapheme_stripos, grapheme_extract, iconv_strpos, file_get_contents, mb_strimwidth, mb_ereg_search_setpos, mb_strpos, mb_stripos.

    Везде это означает считать смещение с конца строки.

    Разрешено использовать строковые ключи в конструкции list() (RFC)


    Так же был добавлен короткий синтаксис для list (RFC).

    
    ["test" => $a, "name" => $b] = ["name" => "Hello", "test" => "World!"];
    var_dump($a); // World!
    var_dump($b); // Hello
    

    Особенности:

    • нельзя использовать смешанный синтаксис (если указываем ключи — то указываем их везде, если нет, то используются обычные индексы 0, 1, 2… как обычно):

      
      // Parse error: syntax error, ...
      ["a" => $a, $b] = ["a" => 1, 2]
      

    • пустые элементы с ключами тоже же не разрешены:

      
      // Parse error: syntax error, ...
      list(,,,, "key" => $keyed) = $array;
      

    • если ключа в исходном массиве нет, то будет выброшено предупреждение Notice: Undefined index: name, а в переменной будет NULL

    • при использовании вложенной конструкции list способы можно комбинировать

      
      $points = [
          ["x" => 1, "y" => 2],
          ["x" => 2, "y" => 1]
      ];
      [["x" => $x1, "y" => $y1], ["x" => $x2, "y" => $y2]] = $points;
      

    Конвертация callable выражений в замыкание (RFC)


    Closure::fromCallable(callable $calback);

    Вот наглядный пример применения:

    class A {
    public function getValidator(string $name = 'byDefault') {
        return Closure::fromCallable([$this, $name]);
    }
    private function byDefault(...$options) {
    	echo "Private default with:".print_r($options, true);
    }
    public function __call ( string $name , array $args ) {
    	echo "Call $name with:".print_r($args, true);
    }
    }
    
    $a = new A();
    $a->getValidator("test")(1,2,3);
    // Call test with: Array ( [0] => 1 [1] => 2 [2] => 3 )
    $a->getValidator()(‘p1’, ‘p2’);
    // Private default with: Array ( [0] => ‘p1’, [1] => ‘p2’)
    // Внимание Closure::fromCallable передает контекст ($this) в момент вызова внутрь замыкания, тем самым разрешая обращаться к приватным методам
    // если оставить только return [$this, $name]; то 
    $a->getValidator()(‘p1’, ‘p2’);
    // вернет 
    // Call byDefault with:Array ( [0] => p1 [1] => p2 )
    // то есть вызовет только публичный метод и не будет иметь доступа к приватным методам объекта

    Поддержка модификаторов видимости для констант класса (RFC)


    
    class Token {
    	// Константа без модификатора по умолчанию “public”
    	const PUBLIC_CONST = 0;
     
            // Константы с различной областью видимости
            private const PRIVATE_CONST = 0;
            protected const PROTECTED_CONST = 0;
            public const PUBLIC_CONST_TWO = 0;
     
            // Весь список имеет одну область видимости
            private const FOO = 1, BAR = 2;
    }

    Ловить исключения можно объединяя несколько типов исключений в один блок (RFC)


    
    try {
       echo "OK";
    } catch (Exception | DomainException $e) {
       // ... обработка 2ух типов исключений сразу
    } catch (TypeError $e) {
       // ...
    }

    Выбросы ошибок уровня E_NOTICE and E_WARNING при арифметических операциях над строками содержащие не валидные числа (RFC)


    
    $numberOfApples = "10 apples" + "5 pears";
    // Выбросит
    // Notice: A non well formed numeric string encountered in example.php on line 3
    // Notice: A non well formed numeric string encountered in example.php on line 3
    $numberOfPears = 5 * "orange";
    // Warning: A non-numeric string encountered in example.php on line 3
    

    Это довольно важное изменение, которое теоритически может сломать обратную совместимость приложения если используются свои error handlers для перехвата предупреждений.

    Причем есть интересная особенность: пробел в начале строк “ 5” + “ 3” — не даст ошибок. А вот “5 ” + “3 ” — пробел в конце уже даст выдаст предупреждения.

    Для обхода последствий неявного преобразования и выброса предупреждений можно явно указывать “cast” в нужный тип: (int)“5 ” + (int)“3 ” или подавлять все принудительно @(“5 ” + “3 ”).

    Другие изменения и обратные несовместимости


    • В связи с новыми типами, добавлены новые зарезервированные слова void, iterable, и код который содержит классы, интерфейсы, трейты с такими именами будет давать ошибку в 7.1

    • Поменяли поведение в php экстеншенах, которые продолжали выкидывать Fatal Error вместо генерации Error исключения (как текущее ядро 7.0), плюс ошибки уровня E_ERROR или E_RECOVERABLE_ERROR тоже стали выбрасывать исключения там, где возможно (понятное дело, что при нехватки памяти по прежнему скрипт необратимо падает (RFC)).

    • Изменилось поведение при вызове функций / методов без передачи обязательных аргументов. Теперь вместо привычного Warning предупреждения, будет выброшено исключение ArgumentCountError (наследует тип Error RFC):

      
      function foo($a) {
         var_dump($a);   // теперь исполнение сюда не дойдет и в $a не будет NULL
      }
      foo();
      // Fatal error: Uncaught ArgumentCountError: Too few arguments to function foo(), 0 passed in...
      

    • Следующие функции больше нельзя вызвать динамически через: $func(), call_user_func(), array_map() и тд:

      1. extract()
      2. compact()
      3. get_defined_vars()
      4. func_get_args()
      5. func_get_arg()
      6. func_num_args()
      7. parse_str() с одним аргументом
      8. mb_parse_str() с одним аргументом
      9. assert() больше нельзя использовать строку в качестве агрумента

    • Функции rand() и srand() теперь просто псевдонимы (alias) к функциям mt_rand() и mt_srand().
      Это в свою очередь затронет вывод таких функций:

      1. rand()
      2. shuffle()
      3. str_shuffle()
      4. array_rand()

    • Добавлена функция session_gc(). Теперь можно чистить старые сессии прямо из скриптов.

    • Добавлена функция session_create_id(), которая позволяет сгенерировать валидный автоматический id сесии без запуска новой сесии, который можно будет использовать в session_id() для старта сессии со сгенерированным ранее ID.

    • Ускорили генерацию ID сессии в 2+ раз, убрав хеширование и используя новую функцию из 7.0 php_random_bytes()

      Скорость до: Requests per second: 899.36 [#/sec]
      Скорость после: Requests per second: 2278.59 [#/sec]
      

    • Убрали неконсистентное поведение над переменной $this

      
      function foo($this) { // Fatal error: Cannot use $this as parameter
      }
      static $this; // Fatal error: Cannot use $this as static variable
      global $this; // Fatal error: Cannot use $this as global variable
      try {
        ...
      } catch (Exception $this) { // Fatal error: Cannot re-assign $this
      }
      foreach ($a as $this) { // Fatal error: Cannot re-assign $this
      }
      unset($this); // Fatal error: Cannot unset $this
      $a = "this";
      $$a = 42; // throw new Error("Cannot re-assign $this")
      function foo() {
          var_dump($this); // throws "Using $this when not in object context"
                           // php-7.0 emitted "Undefined variable: this" and printed NULL
      }
      foo();
      // и другие кейсы

    • Расширение mcrypt помечено как устаревшее и все mcrypt_* функции будут выкидывать E_DEPRECATED.

    • В curl расширение добавлена поддержка для HTTP/2 Server Push, так же были добавлены новый функции curl_multi_errno(), curl_share_errno(), curl_share_strerror().

    • Опция 'e' для функций mb_ereg_replace() и mb_eregi_replace() обьявлена устаревшей.

    На этом мы пожалуй и остановимся, хотя там еще полно мелких изменений в основном в расширениях. А нам для холивара вполне хватит и этого списка. )

    Итог


    Лично моё мнение про данный минорный релиз: все очень органично вписалось, именно этого и не хватало в большинстве своем в новом PHP 7.0 и данные изменения лишь подчеркивают и усиливают особенности 7.х ветки.
    Рекомендую дождаться 7.1.1 и можно обновляться без страха, что-то сломать (если вы конечно уже перешли на 7.0).

    Данная статья не претендует на полное описание ВСЕХ изменений и я мог пропустить что-то важное, рекомендую все равно ознакомиться с первоисточниками:
    » https://wiki.php.net/rfc#php_71
    » https://github.com/php/php-src/blob/php-7.1.0RC1/UPGRADING

    P.S. Примеры можно испытать самому в онлайн песочнице — 3v4l.org/#version=7.1.0RC1

    Only registered users can participate in poll. Log in, please.

    Какую версию PHP вы преимущественно используете в своих проектах

    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 58

      –1
      Что-то не совсем понял, как использовать void в параметрах функции.

      То есть?
      $x = 5;
      
      function foo(void $x) : int {
         return $x; 
      }
      
      

      Вернет 5? Или данный код некорректен?
        +2
        Так же void нельзя использовать как тип к параметру.
          +2
          Так же void нельзя использовать как тип к параметру.

          Данный код некорректен.
            +1
            А, извиняюсь, неправильно прочитал.
          +1
          > Добавлен новый псевдо-тип: «iterable»

          Продолжаем потихонечку-потихонечнку двигаться вперёд.
          В 8.1, наконец введут псевод-тип для объединения array и ArrayAccess
            0
            А что в PHP есть встроенные классы, которые реализуют только интерфейс ArrayAccess?
            Насколько я помню (но могу и ошибаться), все кто реализует ArrayAccess так или иначе используют и Traversable интерфейс в конечном итоге. Например, тот же ArrayObject — он будет принят через «iterable» тип.
            Другой вопрос самописные классы — но в них нет проблем добавить еще один дополнительный интерфейс Iterator или IteratorAggregate и все так же будет работать…
              +2
              Но «возможность итерировать» и «хранилище с доступом по ключу», это разные интерфейсы.
                0
                Верно! Тогда почему от хранилища с доступом по ключу ждут возможность итерации (iterable)? )
                foreach для ArrayAccess никогда работал — https://3v4l.org/8H8vR
                  0
                  Совершенно верно, никогда не работал и никто не ждёт.

                  Есть два интерфейса — перебор элементов и доступ к конкретному элементу по ключу. Они не взаимозаменяемые.

                  Нативный array «реализует» их оба.
                  И для итерирования, наконец, его слили с объектами с нужным интерфейсом.
                  А для доступа по ключу, опять забыли.
                    0
                    Вот теперь понял.
                    Да действительно, для примитивного типа array и ArrayAccess придется создавать свой псевдотип (например «hashable»?) и оно никак не будет пересекается с «iterable».
                    Пойти что-ли предложить им «hashable» RFC? ))
              +1

              Тогда в php 9.2 можно ожидать наконец введения типов, как в некоторых других языках? =)


              type likeArray = array|ArrayAccess;
              
              function a(likeArray $a) { ... }
              0

              ну вот зачем отдавать преимущество {} перед [] для доступа к строке? ничего оно путать не будет, в других языках ведь как-то не путаются. а вот разные скобки задолбаешься ставить.


              UPD: А не, они еще не решили


              Скрытый текст

              On the opposite side, it was also suggested that array access and string offsets are so closely-related concepts that we should recommend using '[]' in both cases and disable the alternate '{}' syntax for string offsets !


              So, as the subject is controversial and very tangential to the subject of this RFC, it will be left for a future RFC.

                +2
                Изменение работы isset() в 7.0.6 резко охладило мой пыл обновляться. То что разработчики могут без лишнего шума в минорной версии могут решить всё сломать не греет душу. Я в целом за то чтобы убирать грязь из движка, но вот так вот, в минорных версиях, без настроек, без этапа депрекации – это опасно. Я ж не могу за весь composer.json отвечать.
                  0
                  Ну проколы бывают у всех. Это хотели сломать еще в 7.0.0 — что было бы естественным.
                  Обьяснение
                  It is unfortunate that this change had to happen in a patch release, rather than in PHP 7.0.0. It's my fault that I did not notice during the pre-release cycle that this previously relatively harmless bug completely breaks the null-coalesce operator in PHP 7. However, that's how things went, and at this point a fix was critical.

                  For reference, the way to fix any issues with this change is to make sure your __isset() or offsetExists() functions behave correctly. If this change causes issues with your code, it indicates that you already have a broken __isset/offsetExists implementation, but it's brokenness did not previously surface (one bug canceling another...)

                  А вообще согласен, даже patch версии нельзя бездумно или автоматически обновлять, хотя бы не почитав changelog. )
                    +4
                    А можете пожалуйста сказать, как именно изменили работу?
                      0
                      На хабре был пост: https://habrahabr.ru/post/283302/

                      Из него не совсем ясны последствия, но хотя бы понятно что у себя проверять.
                    +1
                    и что рекомендуется использовать вместо mcrypt?
                    –2
                    Кстати, это не значит что $x = someNethod(); не вернет ничего. Как и прежде в $x будет значение NULL

                    У авторов php шмаль явно лучше чем у меня.
                      +1
                      Можно предположить, что это сделано для обратной совместимости.
                      Код, который имеет такое поведение уже написан и просто так ломать его не принесет успеха новой версии языка.

                      Хотя с другой стороны, было бы не плохо кидать какой-то warning для такого кода, чтобы фиксили активнее.
                        +2
                        Простите, какая обратная совместимость? Речь о функции с возвращаемым типом void, который только-только вводится. В старых проектах таких ситуаций в принципе быть не может. Логично выкидывать предупреждение, если кто-то пытается присвоить значение функции с типом void.
                          +1
                          Может быть, если решили обновить зависимости, которые используются в текущем «старом» коде.
                            0
                            Можете пояснить?
                              0
                              Если вы пишете генератор кода, то проще считать, что все функции что-то возвращают.
                              Я писал, например, мне проще.
                              Рефлексия же не давала никакой информации.
                              Теперь эта информация есть, можно её использовать.
                              Но для обратной совместимости лучше пока оставить, потом в депрекейтед и потом выпилить.
                            0
                            PHP-программисты пишут всё с нуля и переписывают проект только целиком? Если использовать библиотеку, которая обновится и функция станет возвращать void, то это как раз тот случай.
                              0
                              Если использовать библиотеку, которая обновится и функция станет возвращать void,
                              то это как раз тот случай, когда лучше показать даже не ворнинг, а ошибку. Ведь если вызывающий код использовал значение, которое возвращала функция, то он никак не ожидает настолько кардинальной смены логики работы этой самой функции. Прикинуться валенком и продолжать работать — это худшее что может сделать интерпретатор в такой ситуации.
                                0
                                Так оно возвращало NULL и возвращает NULL, как понял.
                                  0

                                  Именно так. Смысл void только в том, чтобы помечать методы (функции) у которых де-факто отсутствует возвращаемое значение. Можно было конечно не изобретать новый псевдотип, а использовать null:


                                  function a(): null {}

                                  Но с другой стороны такая конструкция позволяет писать:


                                  function a(): ?int {
                                      return random_int(0, 1) ?: null;
                                  }
                                  
                                  function b(): null {
                                    return a();
                                  }

                                  Что говорит о том, что ошибка может возникнуть в 50% случаях. А на void можно ругаться ещё на этапе парсинга тела метода\функции (скорее всего так и будет, я пока не пробовал войд на практике, не в курсе). Там не должно быть ничего кроме return; или же он (ретурн) просто должен отсутствовать, что избавляет от подобных проблем.

                                    0
                                    Зачем записывать в переменную значение возвращаемое функцией, если оно всегда было NULL? А если оно не всегда возвращало NULL, а теперь возвращает void, то логика поменялась, а вызывающий код получил мину замедленного действия в виде отсутствия явной ошибки.
                                      0
                                      Функции могут динамически подставляться
                                        0
                                        С разными типами возврата? Ну, право слово, PHP не обязательно использовать для извращений.
                                          0
                                          Фреймворк роутинга, который маппит HttpMethod + PATH [+MimeType] на функцию обработки.
                                          Функция возвращает Объект, этот объект потом превращается в контент (к примеру в json или xml).

                                          Функция может вернуть int, string, number, Object, null.

                                          Пока не было типов функция могла ничего не возвращать, а просто записать что-то в хедеры и/или установить статус.
                                            0
                                            И? Вы не считаете такую архитектуру извращением?
                                            Пока весь остальной мир идёт по пути унификации обработки веб-запросов (см. WSGI, Rack, Clack, Plug, WAI, etc.), Вы предлагаете из роутера передавать управление к разнородным функциям, которые хз что возвращают?
                                            Ну, ok… ¯\_(ツ)_/¯
                                              0
                                              Посмотрел на WSGI и Rack (остальных не нашел), выглядит действительно не плохо! Но, как мне показалось, это то как на пхп писали еще лет 10 назад. Обработчик запроса, который устанавливает код ответа, хедеры и контент, и все это в одном месте. Для этого в пхп и фреймворки не нужны.

                                              Описанный мною подход — это крайне упрощенный JAX-RS.
                                              На выходе получается крайне простой и самодокументированный код, который не требует пояснений, который не содержит смеси бизнес-логики и формирования конента.

                                              ps: вот пример из мира PHP, чтобы не было притензий, что я с монстроузорной java лезу тут: https://laravel.com/docs/5.3/routing
                                                0
                                                остальных не нашел
                                                держите: Clack, Plug, WAI.

                                                Но, как мне показалось, это то как на пхп писали еще лет 10 назад.
                                                Нет, я 10 лет назад активно писал на PHP, и могу точно сказать, что ничего общего. Возможно, Вы не до конца поняли суть идеи…
                                                Во-первых эти библиотеки не являются фреймворками, наоборот фреймворки (именно во множественном числе, т.е. это своеобразная спецификация, которую уважающий себя фреймворк обязан поддерживать) строятся поверх них.
                                                Во-вторых, благодаря унификации обработчиков из их можно составлять цепочки произвольной длины, начиная с middlewares и заканчивая внутренними механизмами фреймворков. Кроме того, однажды написанную middleware можно опубликовать и люди смогут использовать её практически с любым веб-фреймворком в рамках данного ЯП, потому что никто из создателей фреймворков не стремится изобрести велосипед.

                                                https://laravel.com/docs/5.3/routing
                                                Прочитал… И какое-то смешанное ощущение, то ли документашка очень куцая, то ли роутинг в Laravel находится пока ещё в зачаточном состоянии. Во всяком случае описано мало возможностей и самое главное непонятно в чём профит от возможности возвращать разнородные данные из routing callbacks и как эти данные преобразуются в HTTP-ответ?
                                                  +1
                                                  Спасибо за ссылки. Впечатление, что все эти библиотеки просто были списаны с одного примера и портированы на разные языки.

                                                  Но это уже пошел оффтоп. Моя позиция была в том, что такой подход используется в довольно популярных фреймворках и решение по $x = f(), где function f():void, вполне могут быть обоснованы обратной совместимостью.
                                                  Так же, я считаю, что в этом случае должна быть какая-то опция, чтобы можно было контролировать уровень ошибки для такого кода: игнорить, ворнинг, эррор, со значением «ворнинг» по-умолчанию.
                                                    0
                                                    Так же, я считаю, что в этом случае должна быть какая-то опция, чтобы можно было контролировать уровень ошибки для такого кода: игнорить, ворнинг, эррор, со значением «ворнинг» по-умолчанию.
                                                    Вот с таким подходом я полностью согласен.
                          0
                          Молодцы ребята, работают. Спасибо и за это!
                            –2
                            В наследнике можно делать «строже» возвращаемый тип (то есть запрещать nullable), а параметр наоборот расширять до nullable, НО не наоборот!

                            Вот как вот с этим работать?
                              0
                              Если работать через интерфейс, то более строгая имплементация ничего не поменяет. При этом, более строгая имплементация, сама по себе, запрещает коду сделать что-то не так.

                              Эта фича в простом коде не будет сильно использоваться, но дает гибкость для построения абстракции (при разработке фреймворков и библиотек).
                                0
                                Да я про то, что в одном месте можно расширять до nullable, в другом нельзя. И всё это нужно запоминать, логики лично я в этом не вижу.
                                  +1
                                  Да, это кажется странным на первый взгляд, но на самом деле все довольно просто.

                                  Интерфейс метода описывает максимальное допустимое множество значений, которые может обработать.
                                  Имплементация может расширить это множество, скажем обрабатывать не только int, но еще и long, — это не сломает интерфейс int это подмножество множества long. А вот вместо int принимать short мы уже не сможем, т.к. множество short меньше множества int.
                                  — а если работать через интерфейс, то сам интерфейс не позволит передать long, даже если в имплементации аргумент типа long.

                                  Примерно такой же подход при возврате значения, мы можем Уменьшать множество ответов, но не можем его расширять. Уменьшать мы можем только, если меньшее множество ответов является подмножеством большего.
                                  К примеру long в интерфейсе мы сможем заменить на int в имплементации, но вот заменить на bool — не сможем, bool — не является подмножеством множества long. (под bool подразумевается множество {true, false}, а не {1,0})

                                  ps: примеры long, int, bool приведены как ограниченные множества, чтобы проще было понять идею, в реальности такие манипуляции могут не пройти.
                                    0
                                    Спасибо, теперь понятно, легко запомнить!
                              +1
                              У меня тут такой вопрос назрел: почему нельзя было сделать конструкцию
                              void Test() { ... }

                              как во многих языках программирования это реализовано. Зачем они сделали:
                              function someNethod(): void { ... }

                              ?
                              Уж извините за такой вопрос, но он мне покоя не дает.
                                0
                                Подозреваю что это нужно чтобы не сломать старый код в которым такие функции(без типа результата) возвращают значение.
                                  +3
                                  Ответ почему типы решили объявлять в конце функции, а не в начале есть тут.
                                  В целом думаю ориентир был на Hack, где это уже было реализовано именно так (типа зачем плодить другие варианты).
                                    +2
                                    Эх. А ведь частенько руки сами набирают что-то типа protected int getNumber() {}. Вообще не очень понятно, почему бы от function не отказаться. Парисить чуть сложнее разве что.
                                    0
                                    К примеру, чтобы легко было найти поиском «function Test» в десятке мегабайт кода.
                                      +1
                                      Легко нахожу «function Test» в десятке мегабайт кода с помощью IDE.
                                      –2
                                      Потому что это PHP, он не такой как все.
                                        0

                                        1) Js + FlowType
                                        2) TypeScript
                                        3) Haxe
                                        4) ActionScript
                                        5) ...


                                        Ну да, уникальный в своём роде в этом случае.

                                          –1
                                          Поэтому его все «любят»
                                          +1
                                          Потому что обратная совместимость.
                                          Потому что родитель был Perl, а не Си.
                                          Потому что типизация пока по желанию.
                                            +1
                                            Потому что такой вариант синтаксиса не менее популярен. Более того, он гораздо удобнее читается (при чтении слева направо).
                                            И между «сделать, как в C» и «сделать удобно» выбрали второй вариант, и я их поддерживаю.
                                            0
                                            Запрет на $this вне класса — сломается 1й Yii, там он в шаблонах использовался. Значит будем на 7.0.Х пробовать переезжать.
                                              0
                                              та он и во втором тоже используется
                                                +2
                                                По факту в Yii все шаблоны исполняются внутри класса View, так что ничего не должно сломаться.
                                                  +1
                                                  с чего взяли, что шаблоны YII1 вне класса работают? они инклудятся внутри метода

                                                Only users with full accounts can post comments. Log in, please.