Пользователь
0,0
рейтинг
8 ноября 2013 в 17:16

Разработка → Функции в PHP 5.6 — что нового?


Слева направо: Rasmus, Build 5.4, Version 5.5, Relise 5.6

Сегодня хочу поделиться своим видением того, как будет выглядеть работа с функциями уже в ближайшем мажорном релизе PHP — 5.6. Для этого я изучил рабочие предложения и нашёл там немало вкусняшек:

  • Новый синтаксис для функций с переменным числом аргументов и радостный отход в историю мороки с func_get_args():
    function fn($reqParam, $optParam = null, ...$params) { }
    

  • Опускаем указание значений для необязательных аргументов:
    function create_query($where, $order_by, $join_type = '', $execute = false, $report_errors = false) { }
    create_query('deleted=0', 'name', default, default, /*report_errors*/ true);
    

  • Импорт функций из пространства имён:
    use function foo\bar\baz;
    baz();
    

  • Исключения вместо набивших оскомину фатальных ошибок:
    <?php
    function call_method($obj) {
        $obj->method();
    }
    
    call_method(null); // oops!
    
    try {
        call_method(null); // oops!
    } catch (EngineException $e) {
        echo "Cool Exception: {$e->getMessage()}\n";
    }
    

  • Добавление модификатора deprecated:
    deprecated function myOldFunction() { }
    

  • Вызов методов и доступ к свойствам создаваемого объекта:
    new foo()->xyz;
    new baz()->bar(); 
    

Большинство из приведенных предложений пока находятся на стадии обсуждения. Но среди них уже есть утверждённые и даже реализованные.

Также искушённого читателя ждёт эксклюзив: изучая чужие умные мысли, я и сам решился написать собственный RFC. Сейчас вы не увидите его в списке предложений, так как на данный момент он находится на самом начальном этапе — на рассылке internals@lists.php.net.

А начну обзор с RFC, который уже реализован и гарантированно попадает в релиз 5.6.

Синтаксис для функций с переменным числом аргументов

Реализовано в PHP 5.6, Принято 36 голосами против 1

И сразу в бой: рассмотрим код, который показывает как переменный аргумент ...$params будет заполняться в зависимости от количества переданных аргументов:
function fn($reqParam, $optParam = null, ...$params) {
    var_dump($reqParam, $optParam, $params);
}
 
fn(1);             // 1, null, []
fn(1, 2);          // 1, 2, []
fn(1, 2, 3);       // 1, 2, [3]
fn(1, 2, 3, 4);    // 1, 2, [3, 4]
fn(1, 2, 3, 4, 5); // 1, 2, [3, 4, 5]

$params будет пустым массивом, если число переданных аргументов меньше, чем число объявленных. Все последующие аргументы будут добавлены в массив $params (с сохранением порядка). Индексы в массиве $params заполняются от 0 и по возрастанию.

На данный момент функции с переменным числом аргументов реализуются при помощи функции func_get_args(). Следующий пример показывает, как сейчас реализуется функция с переменным числом аргументов для подготовки и выполнения запроса MySQL:
class MySQL implements DB {
    protected $pdo;
    public function query($query) {
        $stmt = $this->pdo->prepare($query);
        $stmt->execute(array_slice(func_get_args(), 1));
        return $stmt;
    }
    // ...
}
 
$userData = $db->query('SELECT * FROM users WHERE id = ?', $userID)->fetch();

Проблемы старого подхода и как их решить.
Во-первых, глядя на синтаксис функции public function query($query) невозможно понять, что это, собственно говоря, функция с переменным числом аргументов. Кажется, что это функция выполняется только с обычным запросом и не поддерживает дополнительных аргументов.

Во-вторых, так как func_get_args() возвращает все аргументы, переданные в функцию, то вам сначала необходимо удалить параметр $query используя array_slice(func_get_args(), 1).

Данное RFC предлагает решить эти проблемы добавлением специального синтаксиса для функций с переменным числом аргументов:
class MySQL implements DB {
    public function query($query, ...$params) {
        $stmt = $this->pdo->prepare($query);
        $stmt->execute($params);
        return $stmt;
    }
    // ...
}
 
$userData = $db->query('SELECT * FROM users WHERE id = ?', $userID)->fetch();

Синтаксис ...$params сигнализирует о том, что это функция с переменным числом аргументов, и что все аргументы после $query должны быть занесены в массив $params. Используя новый синтаксис, мы решаем обе вышеперечисленные проблемы.

Возможности нового синтаксиса

  • function fn($arg, ...$args): собирает все переменные аргументы в массив $args
  • function fn($arg, &...$args): собирает по ссылке
  • function fn($arg, array ...$args): гарантирует, что все переменные аргументы будут массивами (возможно указать любой другой тип)

Преимущества

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



Переопределение списка аргументов — эксклюзив!

Обсуждается на internals@lists.php.net

И так, на данные момент моё предложение уже существенно отличается от первоначального и сводится к следующему: предоставить возможность изменять список аргументов метода (их количество и/или тип) при наследовании классов:
class Figure
{
    public function calcPerimeter(array $angles)
    {
        return array_sum($angles);
    }
}

class Square extends Figure
{
    public function calcPerimeter($angle)
    {
        return 4 * $angle;
    }
}

class Rectangle extends Figure
{
    public function calcPerimeter($height, $width)
    {
        return 2 * ($height + $width);
    }
}

Теперь можно использовать обе реализации расчёта периметра:
$square = new Square();
var_dump($square->calcPerimeter(array(1, 1, 1, 1))); // 4
var_dump($square->calcPerimeter(1)); // 4

Большая наглядность и естественность второго вызова очевидна. Конечно, что-то подобное можно реализовать заморочившись с func_get_args(). Но предложенный подход даёт полную ясность того, что конкретно реализовывает метод, делает код более чистым, избавляя от каскада if-else (по количеству и типу аргументов). По-умному это называется ситуативным полиморфизмом, который уже давно и успешно используется в C++, Java/Scala, Delphi и многих других ЯП. Я уверен, что возможность изменять набор аргументов метода при наследовании — это очень полезно. Проблем с обратной совместимостью возникнуть не должно.

Опускаем указание значений для необязательных аргументов

На обсуждении

Так как в PHP нет поддержки именованных параметров, довольно часто функции содержат много необязательных параметров:
function create_query($where, $order_by, $join_type='', $execute = false, $report_errors = true) {...}

Если мы всегда используем дефолтные значение, то проблем не возникает. Но что, если нам надо поменять только параметр $report_errors, а остальные оставить без изменений? Для этого нам придётся найти определение функции и скопировать все остальные дефолтные значения в вызов. А это уже довольно скучно, потенциально глючно и может поломаться, если часть дефолтных значений изменится.

Предложение заключается в том, чтобы разрешить опускать указание значений для дефолтных аргументов в вызове, сохраняя, таким образом, их значение по умолчанию:
create_query("deleted=0", "name", default, default, /*report_errors*/ true);

В коде выше, $join_type и $execute будут иметь дефолтное значение. Естественно, таким образом мы можем опускать только необязательные параметры. В случае обязательных параметров будет генерироваться такая же ошибка, как и сейчас, когда в вызов функции передано недостаточно аргументов.

Проблемы

Проблема возникнет с поддержкой внутренних функций, использующих ручной вызов ZEND_NUM_ARGS(). Автор предложения просмотрел все функции в стандартном дистрибутиве, однако расширения PECL, которые не используют using zend_parse_parameters или делают это странным образом с zval-type без их корректной инициализации или проверки выходных результатов, могут требовать фиксов. Другими словами, они могут поломаться, если передать default с нулевым указателем на ссылку. Это не выглядит большой проблемой с точки зрения безопасности, но в любом случае не особо приятно.

Импорт функций из пространства имён

Принято 16 голосами против 4, Предложено включить в PHP 5.6

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

Функцию можно вызвать без указания полного имени, только если вызов находится в том же пространстве имён, что и сама функция:
namespace foo\bar {
    function baz() {
        return 'foo.bar.baz';
    }
}
 
namespace foo\bar {
    function qux() {
        return baz();
    }
}
 
namespace {
    var_dump(foo\bar\qux());
}

Можно избежать указания полного имени, если импортировать пространство имён, в котором определена функция. Однако его алиас всё равно должен быть указан при вызове функции:
namespace foo\bar {
    function baz() {
        return 'foo.bar.baz';
    }
}
 
namespace {
    use foo\bar as b;
    var_dump(b\baz());
}

Невозможно импортировать функцию напрямую. Пока что PHP не поддерживает это.

Детальная суть предложения
Суть предложения в том, чтобы добавить новую комбинацию ключевых слов, которая позволит импортировать функции в пространстве имён. Это должно намного облегчить работу с такими функциями и избежать реализации функций в глобальном пространстве имён.

Использование одного и того же оператора use и для пространства имён классов, и для функций, скорее всего, приведёт к конфликтам и оверхеду.

Вместо изобретения нового оператора, можно просто использовать комбинацию use и function:
namespace foo\bar {
    function baz() {
        return 'foo.bar.baz';
    }
    function qux() {
        return baz();
    }
}
 
namespace {
    use function foo\bar\baz, foo\bar\qux;
    var_dump(baz());
    var_dump(qux());
}

Причём, такой подход можно было бы использовать не только для функций, но и для констант:
namespace foo\bar {
    const baz = 42;
}
 
namespace {
    use const foo\bar\baz;
    var_dump(baz);
}

Так же как и для классов, должна быть возможность делать алиасы для импортируемых функций и констант:
namespace {
    use function foo\bar as foo_bar;
    use const foo\BAZ as FOO_BAZ;
    var_dump(foo_bar());
    var_dump(FOO_BAZ);
}


Основные вопросы и ответы

Почему бы просто не импортировать пространство имён?

Действительно, вы можете импортировать пространство имён. Это не критично для классов и, подавно, для функций. Но есть один случай, когда импорт функций может ощутимо улучшить читаемость кода. Это будет очень полезно при использовании небольших библиотечек, которые представляют собой просто несколько функций. Можно было бы помещать их в пространство имён, например, по имени автора: igorw\compose(). Это бы помогло избежать конфликтов. И пользователь такой функции, которому нет дела до того как зовут её автора, мог бы просто писать compose(). Вместо этого пользователь вынужден изобретать новый бессмысленный алиас просто для того, чтобы использовать функцию.

Возврат в глобальное пространство имён

По умолчанию PHP будет искать функции в локальном пространстве имён, а затем будет возвращаться в глобальное. Для функций, которые были импортированы оператором use, возврата в глобальное пространство имён быть недолжно.
namespace foo\bar {
    function strlen($str) {
        return 4;
    }
}
 
namespace {
    use function foo\bar\strlen;
    use function foo\bar\non_existent;
    var_dump(strlen('x'));
    var_dump(non_existent());
}

Вызов strlen() теперь однозначен. non_existent() более не ищется в глобальном пространстве имён.

Зачем нужен оператор use function, почему не просто use?

В PHP функции и классы хранятся в отдельных пространствах имён. Функция foo\bar и класс foo\bar могут сосуществовать, потому что из контекста можно понять, что мы используем (класс или функцию):
namespace foo {
    function bar() {}
    class bar {}
}
 
namespace {
    foo\bar(); // function call
    new foo\bar(); // class instantiation
    foo\bar::baz(); // static method call on class
}

Если оператор use будет поддерживать импорт функций, то это повлечёт проблемы с обратной совместимостью.

Пример:
namespace {
    function bar() {}
}
 
namespace foo {
    function bar() {}
}
 
namespace {
    use foo\bar;
    bar();
}

Поведение изменилось после того, как поменялся use. В зависимости от версии PHP, будут вызваны разные функции.


Исключения вместо фатальных ошибок

На обсуждении, Предложено для PHP 5.6

Это RFC предлагает разрешить использование исключений вместо фатальных ошибок.

Для наглядности предложения, рассмотрим следующий кусок кода:
<?php
function call_method($obj) {
    $obj->method();
}
call_method(null); // oops!

Сейчас этот код приведёт к фатальной ошибке:
Fatal error: Call to a member function method() on a non-object in /path/file.php on line 4

Данный RFC заменяет фатальную ошибку на EngineException. Если исключение не будет обработано, мы всё равно получим фатальную ошибку:
Fatal error: Uncaught exception 'EngineException' with message 'Call to a member function method() on a non-object' in /path/file.php:4

Stack trace:
#0 /path/file.php(7): call_method(NULL)
#1 {main}
  thrown in /path/file.php on line 4

Конечно, его не проблема и обработать:
try {
    call_method(null); // oops!
} catch (EngineException $e) {
    echo "Exception: {$e->getMessage()}\n";
}
 
// Exception: Call to a member function method() on a non-object

Потенциальные проблемы
Совместимость с E_RECOVERABLE_ERROR

Сейчас можно игнорировать восстанавливаемые фатальные ошибки, используя кастомный обработчик ошибок. Заменив их на исключения, мы потеряем такую возможность, ломая, таким образом обратную совместимость.

Я никогда не видел применения этой возможности на практике (не считая грязных хаков). В большинстве случаев, кастомный обработчик событий выкидывает ErrorException, то есть эмилирует предложенное поведение, лишь с другим типом исключения.

Catch-all блоки в уже существующем коде

Так как EngineException расширяет Exception, он будет отлавливаться блоками catch с типом Exception. Это может привести к незапланированному отлову исключений. Решением этой проблемы могло бы быть введение BaseException, который был бы родителем Exception. От BaseException можно было бы наследовать только те исключения, которые нежелательно отлавливать. Такой подход используется в Python (BaseException) и Java (Throwable).


Добавление модификатора deprecated

На обсуждении

Данный RFC предлагает добавить модификатор deprecated для методов и функций, которые присваивают функциям флаг ZEND_ACC_DEPRECATED, таким образом, при вызове выкидывая исключение E_DEPRECATED.

Зачем это нужно?

Помечать используемые функции и методы как устаревшие — это обычная практика для больших PHP фреймворков при релизе новых версий. Позже эти функции убираются окончательно. Нативные функции требуют только флага ZEND_ACC_DEPRECATED для того, чтобы Zend при их вызове автоматически сгенерировал ошибку E_DEPRECATED. Тем не менее, пользовательские функции могут быть отмечены как устаревшие только добавлением тега @deprecated (в комментарии документации) или генерацией ошибки E_USER_DEPRECATED. Но почему обычный разработчик должен генерировать ошибку вручную, в то время как нативная функция требует только флага?

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

Ошибка E_USER_DEPRECATED может быть скорее использована для пометки как устаревшей целой библиотеки или способа вызова функций.

Так же, метод ReflectionFunction::isDeprecated() на данный момент бесполезен для пользовательских функций. И этот RFC решает указанную проблему.

deprecated function myFunction() {
    // ...
}
myFunction();

Deprecated: Function myFunction() is deprecated in ... on line 5

class MyClass {
    public deprecated static function myMethod() {
        // ...
    }
}
MyClass::myMethod();

Deprecated: Function MyClass::myMethod() is deprecated in ... on line 7


Вызов методов и доступ к свойствам создаваемого объекта

На обсуждении

Цель этого RFC — предоставить поддержку вызова методов и доступа к свойствам созданного объекта одной строкой. Мы можем использовать один из двух нижеприведенных синтаксисов.

Синтаксис 1 (без скобок)

  • new foo->bar()
  • new $foo()->bar
  • new $bar->y()->x

class foo {
	public $x = 'testing';
 
	public function bar() {
		return "foo";
	}
	public function baz() {
		return new self;
	}
	static function xyz() {
	}
}
 
var_dump(new foo()->bar());               // string(3) "foo"
var_dump(new foo()->baz()->x);            // string(7) "testing"
var_dump(new foo()->baz()->baz()->bar()); // string(3) "foo"
var_dump(new foo()->xyz());               // NULL
new foo()->www();                         // Fatal error: Call to undefined method foo::www()

Синтаксис 2 (со скобками)

  • (new foo())->bar()
  • (new $foo())->bar
  • (new $bar->y)->x
  • (new foo)[0]

class foo {
	public $x = 1;
}
 
class bar {
	public $y = 'foo';
}
 
$x = 'bar';
 
$bar = new bar;
 
var_dump((new bar)->y);     // foo
var_dump((new $x)->y);      // foo
var_dump((new $bar->y)->x); // 1


Эпилог


Ну, вот и всё. Список изменений получился довольно внушительный, а ведь он затрагивается только работу с функциями! Лично мне планируемые нововведения очень нравятся, хочется их попробовать уже сейчас :)

Буду рад обсудить все эти новшества и, конечно же, пуститься в горячую дискуссию вокруг моего RFC. А, возможно, кто-нибудь ещё и свой предложит :)

До встречи в комментариях!
Олег Полудненко @uaoleg
карма
53,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (203)

  • +6
    Отлично! Релизы не перестают радовать удобными нововведениями ) Спасибо.
  • 0
    Вызов методов и доступ к свойствам создаваемого объекта — без скобок не понятно, вызывается ли метод свежесозданного объекта или же создаётся объект класса, имя которого возвращает вызванный метод (какая-нибудь хитрая фабрика). Хотя, если без знака доллара, то можно и без скобок, но со скобками надёжнее.
    • +1
      Согласен, мне со скобочками однозначно больше нравится.
      • +3
        Но синтаксис со скобками уже занят с версии 5.4…
        php.net/manual/en/migration54.new-features.php
      • +1
        Забавно — смотрю я на список этих нововведений и не покидает мысль, что PHP всё больше и больше превращается в Python. :)

        Что, в общем-то, неплохо. Многого оттуда не хватает в PHP.
        • +11
          Забавно, что программист на Java, Ruby, JS скажет то же самое. Да и вообще любой программист, использующий в основном N язык будет говорить, что, мол, с их любимого языка N всё слизывают =)

          Можно даже в случайном порядке перебрать. Переменное число аргументов — с руби слизали. Вызов методов и свойств у создаваемого объекта — с JS, deprecated с Java, предложенный RFC автором — вообще с C++. Куда катится этот мир? =)
          • –2
            Мне переменное число аргументов напоминает опять же java, любителем которой не являюсь.
            Там:
            foo(Runnable ...bar)
            Тут:
            foo(callable ...$bar)

            Так себе смотрится. Жаль, что вариант с * не приняли.
            • 0
              Сделано точно так же, как в Ecma6, у Java сделано иначе
    • 0
      Согласен, лучше бы сделали у всех объектов метод new, как в некоторых языках
      Foo::new()->bar;
      Bar::new()->foo();
      • 0
        Ну ведь в этих некоторых языках и способ создания объектов другой, и в них все является объектами, т.е. это сложнее заимствовать, да и лишь сахарок :)
    • –1
      Вызов методов и доступ к свойствам создаваемого объекта — без скобок не понятно, вызывается ли метод свежесозданного объекта или же создаётся объект класса, имя которого возвращает вызванный метод (какая-нибудь хитрая фабрика)
      Штоа? Какая ещё хитрая фабрика? В PHP new bar() вернёт экземпляр класса bar, по-другому это не работает.
      • –7
        Забавно, но действительно не работает конструкция, хотя по логике php должна бы.
        function bar() { return 'foo'; }
        new bar();
        • +11
          С чего должна-то она работать?
          • 0
            class foo {}
            function bar()
            {
                return 'foo';
            }
            $fooClass = bar();
            $foo = new $fooClass;
            

            по логике ничем не отличается от
            class foo {}
            function bar()
            {
                return 'foo';
            }
            $fooClass = new bar();
            


            Первое работает, второе — нет. Работать должна как раз по логике, т.к. логика здесь от наличия промежуточной переменной, содержащей возврат bar(), никак не меняется.

            Правильнее было бы разрешить следующее:
            class foo {}
            function bar()
            {
                return 'foo';
            }
            $fooClass = new bar()();
            
            • 0
              new в рамках PHP не полноценный оператор, он может принимать только переменную или константную строку без кавычек.
              • +1
                Да, но мы говорим про логику.

                В PHP с логикой далеко не всегда окей.

                Смотрим, например, на созданный мной когда-то баг (к счастью переоткрыли, хотя изначально перевели в «не баг»): bugs.php.net/bug.php?id=62814
                • 0
                  Тогда уже по логике надо запретить создавать объект по строке из переменной, т.к. new не оператор. Иначе если пойти дальше и такая магия должна работать:

                  $x = ('cos')(20)
                  $prop = $obj -> ('property name' . $i); // почему заюзали { .... } вместо ( ) не очень понятно, т.к. -> похож на бинарный оператор.
                  ...
                  и т.д. и т.п.
                  
            • +1
              … и запретить следующее:
              class foo {}
              $foo = new foo;
              

              оставив только один вариант инстанциирования:
              class foo {}
              $foo = new foo();
              
            • 0
              … даже еще более магически, через константу =):

              class foo {}
              
              define('bar', 'foo');
              
              $fooClass = new bar();
              
            • +1
              Скажете тоже. «new» в ПХП — конструкция, у конструкций всегда ограниченный синтаксис. Вас же не удивляет (надеюсь), что вот такое не работает:
              $a = 'new';
              $b = $a bar();
              
        • 0
          будет работать, правда в JS, но ведь будет)
  • 0
    ...$params
    

    как-то странно выглядит
    • +3
      В lua и java очень похожий синтаксис.

      public void myMethod(String... arguments){
           // 
      }
      
    • +5
      Многоточие с параметром во многих языках используется. Это стандарт синтаксиса, можно сказать.
  • +2
    произвольное число параметров может иметь только один тип? или есть возможность указать несколько?
    • 0
      Можно указывать тип для каждого парметра, как и сейчас. Только сейчас нельзя изменить параметр (например, массив на число).
  • +7
    Переменное число аргументов смотрится ужасно, меня ещё в ruby это пугало, когда приходится считать аргументы, чтобы узнать какие переданы.
    depricated это логирование, зачем в конструкцию языка запихнули не понятно.
    Про неоднозначность new foo()->bar уже писали выше.

    Из полезного только неймспейсы и ещё пилить нужно, хотелось бы синтаксис use Foo\*, чтобы импортировать все классы из неймспейса с синтаксисом типа use для трейтов.

    Ну и бородатая хотелка — полный тайпхинтинг в php стиле, с приведением. function foo(int $id, string $default = '') {}
    • 0
      «Смотрятся ужасно» — это не аргумент, а вкусовщина. Сегодня смотрится ужасно, завтра вы уже привыкли и работаете. Depricated нужно чтобы встроенные возможности языка могли использовать не только встроенные функции, но и все остальные — warning, reflection и прочее. Неоднозначности в «new foo()->bar» не больше, чем в «$a || $b && $c». Всего лишь надо знать приоритет операций.
      • 0
        Аргумент был во второй части предложения.
        function($a, $b = 0, $c =0, $d)
        foo(1, 2) $a = 1, $b = 0, $c =0, $d = 2;
        foo(1, 2, 3) $a = 1, $b = 2, $c =0, $d = 3;
        foo(1, 2, 3, 4) $a = 1, $b = 2, $c =3, $d = 4;

        deprecated — trigger_error. В том же php функции то добавлялись, то удалялись с деприкейтид, для этого нужно менять внутреннюю реализацию функции, а не интерфейс.

        $a || $b && $c в нормальной команде этот код не пройдёт код ревью пока скобки не расставят. Другое дело, что оказалось что с функцией вариант не работает и это не добавит двойственности.
        • –1
          Вы про это?
          меня ещё в ruby это пугало, когда приходится считать аргументы, чтобы узнать какие переданы.

          Ну так в PHP это уже есть, просто синтаксис иной, станет удобнее, если этот примут.

          trigger_error должен помереть.

          Хотите сказать, что «$a || $b && $c» слишком сложен для современных программистов, чтобы тут ещё и скобки ставить?
        • –2
          $a || $b && $c в нормальной команде этот код не пройдёт код ревью пока скобки не расставят


          Вот это, наверное, просто так писали:
          www.php.net/manual/en/language.operators.precedence.php

          Если для таких очевидных вещей скобки ставить, ну я не знаю…

          Такой вот код тоже ревью не пройдёт?
          if($error_type&E_PARSE)
            return 'This is parse error';


          Попросят заменить на
          
          if($error_type==E_PARSE)
              return 'This is parse error';

          ? А лучше, наверное вот так:
          
          if(((($error_type===E_PARSE))))
              return ((((string)'This is parse error'))); //Я не уверен, что это строка, пожалуй стоит проверять ещё и при каждом использовании функции
          

          чтобы наверняка.

          Ну и что это за скобочная паранойя?

          Простите за сарказм.
          • +2
            Ваш код не пройдёт даже в CI phpcs, это реальность
            NotAllowed, Priority: High
            Inline control structures are not allowed

            Я программирую не один, так что свою гениальность могу засунуть в жопу, главное, чтобы код был понятен всем и стандартизирован. Мне это не сложно, я бы даже, следуя фаулеру, отрефакторил двойное условие, вынеся его в отдельный метод с хорошим названием, сделав код человекочитабельнее.
            • –5
              главное, чтобы код был понятен всем

              Вы же не со школьниками в команде?
              P.S. пусть школьник не обижаются, есть и исключения.
              Я понимаю, что у PHP низкий порог вхождения, но это абсолютно не значит, что останавливаться в его изучении на пункте мануала «Цикл foreach()» и со словами «я всё знаю, я у мамы инженер» идти работать над каким-то проектом с такими же «специалистами» = это нормальное поведение.

              Смысл программировать на языке, если человек его не знает? Стандарты нужны для структурирования кода и облегчения командной разработки, без ущерба коду. Если стандарт заставляет вас навешивать лишние скобки, заменять побитовые операции (в том примере это вполне нормально и правильно), переписывать любой механизм, который содержит что-либо, не описанное в книге «Как выучить пых за 24 часа, стать крутым программистом и написать фэйсбук», то, лично моё мнение, такой стандарт нужно сдать в утиль.

              Лично я в самом первом блоке кода не вижу никакой гениальности, я вижу код без лишнего говна.
              • +1
                Из самого контрастного — работал на проекте одновременно с малышевым из php core team и студентами бгуир, так что — да, работаю и со школьниками, и с гуру, но сам не страдаю профессиональным снобизмом.

                Вот вы привели ссылку на приоритеты, покажите где на ней написано, что приоритет new выше чем у вызова функции?
                • 0
                  Вот вы привели ссылку на приоритеты, покажите где на ней написано, что приоритет new выше чем у вызова функции?

                  1. Прошу прощения, не совсем понял, что вы имеете ввиду. Если вам не очень сложно, приведите, пожалуйста, пример.
                  2. Оператор new находится выше всех в таблице приоритетов, этого вам недостаточно? Я думаю, не нужно быть гением, чтобы интерпретировать этот факт, как "new, при наличии каких-либо других операторов, в любом случае будет исполнен первым".
                  3. С каких пор вызов функции является оператором?
        • –2
          $a || $b && $c в нормальной команде этот код не пройдёт код ревью пока скобки не расставят.
          А почему просто не выгнать тех, кто может ошибаться в приоритетах выражения с 2 операторами?
          • +2
            И увеличить безработицу в стране? Не раскачивайте лодку :)
          • 0
            Тогда придётся начать с себя. Пишу на 3 яп, так что могу легко напутать приоритеты.
            Ну и тем более if (!$bar = foo()), этот код работает как if (! ($bar = foo()) ), хотя приоритет у "=" меньше чем у "!"
            • –1
              и тем более if (!$bar = foo()), этот код работает как if (! ($bar = foo()) )


              Код if (!$bar = foo()) работает как if (!$bar = foo()) забудьте о скобках. Вам самому глаза не режет?

              хотя приоритет у "=" меньше чем у "!"

              Давайте попробуем ещё раз.
              www.php.net/manual/ru/language.operators.precedence.php
              Специально для вас под табличкой примечание (напишу на русском):

              Замечание:

              Несмотря на то, что оператор = имеет низший приоритет, чем большинство остальных операторов, PHP все равно позволяет использовать следующую конструкцию: if (!$a = foo()), которая присваивает переменной $a результат выполнения функции foo().

              Не читайте выборочно мануал. Вот из-за такого подхода, многие php-шные говнокодеры до сих пор не знают, что если не объявлять массив, а просто присвоить необъявленной переменной элемент, то она автоматически станет массивом $a=[2];.
              Хотя в больших проектах лучше всё-таки обнулять.

              Вы там выше о стандартах говорите. Какие к чёрту стандарты, подучите базовые вещи.
              • 0
                Так я о чём и говорю, даже стандартный приоритет имеет исключение, этот момент описан в документации в части note.
                Там же в Example #2 показана случаи неопределённости конструкций, поведение которых не гарантировано.
                Это к тому, что приоритеты не такие однозначные.

                А про массив для необъявленных — ты действительно считаешь что нормальный программист столкнётся с таким кодом, я лично думал что будет нотис и мне не стыдно. Считаю что именно говнокодеры пишут такой код в не зависимости от размера проекта.
                • –2
                  я лично думал что будет нотис и мне не стыдно

                  Знаете, что плохо? Не то что, программист чего-то не знает. Все мы люди и всё в голове удерживать просто невозможно. Но если программист сталкивается с странным, на его взгляд поведением, и забивает болт, вместо того, чтобы разобраться как и почему такое происходит, предпочитая порасставлять скобки где, только можно, то это очень печально. Значит человеку это неинтересно, значит человек мыслит по шаблону «да ничё страшного не будет, подумаешь пятьсот лишних знаков и действий-пустышек, которые не несут ни какой смысловой нагрузки, серваку то похер». Как выше, справедливо отметили, обленились нынешние программисты. Я, конечно не застал то время (вернее застал, но в нежном возрасте), когда писалась Windows 3.1, когда ребята сидели ночами возле Dial-up и думали над каждой деталью программы, потому что ресурсы были крайне ограниченны и мощности не позволяли, но когда читаешь статьи о тех временах, чувствуешь себя говном.
                  • 0
                    Я ставлю скобки не потому что не знаю приоритетов (или не могу их посмотреть в мануале :), а потому что не хочу других заставлять лезть в мануал, чтобы вспомнить у чего выше приоритет: у or или xor.
                    • +1
                      я не понимаю, в PHP, что — тысяча операторов? В чём состоит сложность? В нежелании запомнить, в лени, в чём?
                      • 0
                        Какой результат будет у следующего выражения?
                        php -r "print true ? 1 : true ? 2 : true ? 3 : true ? 4 : 5;"
                        • –1
                          1
                          • +2
                            Надеюсь, что после того как вы запустите этот код, у вас не останется сомнений в нужности скобочек :) (если что, в документации оно отражено)
                            • 0
                              Документация: us1.php.net/manual/ru/function.print.php

                              И?
                              • 0
                                Вы всё-таки запустите :) (а потом почитайте про уникальный тернарный оператор в PHP)
                                • 0
                                  Запустил, var_dump() выдаёт (int) 1. Что я делаю не так?
                                  • 0
                                    Что именно вы запускаете? (уже ведь намекнул про уникальный тернарный оператор)
                                    • 0
                                      Вы определитесь, что вы у меня спрашиваете
                                      — результат print true? 1: true? 2: true? 3: true? 4: 5;
                                      — результат true? 1: true? 2: true? 3: true? 4: 5;
                                      ?

                                      Про ассоциативность я знаю, не переживайте, а вот знаете ли вы, как сработает выражение
                                      print true? 1: true? 2: true? 3: true? 4: 5; я сильно сомневаюсь
                                      • 0
                                        Ессно про «true? 1: true? 2: true? 3: true? 4: 5;», разве не очевидно было?
                                        • 0
                                          Какой результат будет у следующего выражения?
                                          php -r «print true? 1: true? 2: true? 3: true? 4: 5;»


                                          Мой ответ: результатом будет вывод текста в консоль. Теперь я надеюсь всё в порядке.

                                          Естественно, неочевидно. Касаемо тернарного оператора — ассоциативность правая, так что нет ничего неожиданного в выводе «4» на экран. И по--моему правая ассоциативность — это одна из тех штук в php, которую сразу замечаешь при изучении тернарного оператора
                                          • 0
                                            И что же будет выведено в консоль?
                                            • 0
                                              4 будет выведено
                                              • –1
                                                И вас это не удивляет? (что они курили? :()
                                                • 0
                                                  Я учился программированию на паскале, и знаете, когда я сел за пых, для меня было такое облегчение, что нигде нету THEN, NOT, BEGIN, END, разных неудобных какашек, что такой пустяк, как странная логика тернарного оператора не кажется чем-то плохим.

                                                  Кстати насчёт «что они курили» =) почитайте на досуге мою статью, а ещё лучше комментарии к ней. Поверьте, по сравнению с другими косяками, тернарный оператор — просто сама очевидность.
                                                • 0
                                                  И это (результат 4) нормальное поведение вложенных тернарных операторов в PHP, что отражено в документации и обсуждалось на хабре.
                                                  • 0
                                                    Как будто я не знаю (читайте ветку целиком)… Проблема только в том, что это «нормальное» поведение нормально только в PHP, поэтому вопрос «что они курили?» очень актуален.
                                                    • +2
                                                      Я вот про это поведение узнал только из документации. Всегда, во всех языках использую скобки в выражениях с более чем одним оператором.
                                                      Чтобы там не курили авторы, такой подход — отлично решение не стрелять себе в ногу, когда приходится практически ежедневно прыгать между 2-4 ЯП.
                                                      • 0
                                                        Я вот про это поведение узнал только из документации.

                                                        Как я понял в результате этой дискуссии — мануал читать не нужно (а ещё лучше — не думать). Просто создалось такое впечатление, судя по комментариям, вы уж извините конечно, но выглядит всё это как «да не парься, ставь скобки ВЕЗДЕ ВЕЗДЕ ВЕЗДЕ! И ПОБОЛЬШЕ!»

                                                        Знание нескольких ЯП — это не повод писать на них абы-как. Я может и танцевать умею, и петь, и быть композитором великим, но только вопрос в качестве, а не в количестве скиллов =)
                                                        • +2
                                                          Скобки в сложных логических выражениях идут защитой от случайного некорректного учета приоритетов операторов. Знание приоритетов не гарантирует отсутствие случайной ошибки.
                                                          Из похожего — конструкция «if (42 == $foo)», защищающая от случайного присвоения в языках, где допустимо такое присвоение.

                                                          А еще мне просто удобнее визуально смотреть на выражение со скобками, особенно если оно вылезло за пределы одной строки.
                                                          • –1
                                                            Знание приоритетов не гарантирует отсутствие случайной ошибки

                                                            С тем же успехом можно и в скобках запутаться
                                                            • +1
                                                              Я еще со времен паскаля в школе взял за практику закрывать все парные элементы сразу при открытии. То, что сейчас IDE пытаются за нас делать. Отличный способ не запутаться с любыми парными элементами.
                                                              Но если сложность выражения такова, что там куча скобок (и это не языки вроде lisp), то стоит задуматься уже о вынесении частей выражения в переменные.
                                                            • 0
                                                              Нормальные IDE помогают разобраться с многоуровневыми вложениями скобок.
                                                              • –1
                                                                нормальные программисты разбираются в коде и без всяких IDE
                                                                • 0
                                                                  Зачем игнорировать помощь, которую IDE оказывают без всяких дополнительных действий? Да даже не IDE, а простые редакторы хоть самую малость заточенные именно под код?
                                                                • +2
                                                                  нормальные программисты разбираются в коде и без всяких IDE

                                                                  … и пишут программы на перфокартах. Да!
                                                                  • 0
                                                                    Не пишут, а пробивают вручную прямо из головы. Без всяких перфораторов.
                      • +1
                        Не тысяча, но за полсотни. Ну и да, можно сказать, что и в лени, вернее в экономии ресурсов. Плюс следует учесть, что зачастую люди пишут не только на PHP, а и на других языках, где приоритеты могут быть другими, что сильно осложняет запоминание.
                        • –1
                          и порождает, в частности, говнокод
                          • 0
                            Я не считаю наличие излишних скобок (хоть круглых, хоть фигурных) говнокодом. У вас может быть другое мнение. Оба имеют право на жизнь.
                            • 0
                              нет, наличие лишних скобок — не говнокод, говнокод — это путаница в головах, она к нему и приводит.
                              • +2
                                Так скобки и призваны удалить путаницу.
            • +1
              В каком из ЯП проритет || выше или равен приоритету &&?
              Предполагая, что вы пишете на PHP, Ruby и JS, скажу, что с приоритетом && и || в этих языках все одинаково.
    • +4
      Ну и бородатая хотелка — полный тайпхинтинг в php стиле, с приведением. function foo(int $id, string $default = '') {}

      Не надо с привидением! Смысл тайп хинтинга именно в строгом контроле типов.
      • 0
        :) из-за этого и не договорились, хотя даже была реализация.
        • 0
          Жаль :(
  • +3
    Переопределение списка аргументов… даёт полную ясность того, что конкретно реализовывает метод, делает код более чистым, избавляя от каскада if-else

    и полностью ломает ключевую концепцию ООП — полиморфизм
    • +1
      Это называется ситуативным полиморфизмом, который успешно используется в C++, Java/Scala, Delphi, etc.
      • +7
        В Java то что вы описали, называется перегрузкой методов и к наследованию не имеет отношения. Вашу идею нужно развить, чтобы в одном классе можно было определять несколько методов с одним и тем же названием, но с разным количеством аргументов. Вот тогда это имеет смысл.
        • 0
          В изначальном варианте моё предложение содержало вашу идею. Но, в ходе дискуссии на рассылке выяснилось, что это может сильно поломать обратную совместимость (из-за функции func_get_ars()):
             class B {
                function foo() { func_get_ars(); }
                function foo($bar = null) { func_get_ars(); }
             }
             $o = new B;
             $o->foo(1, 2); // Unpredictable call
          
          • +2
            Почему же оно будет ломать совместимость, если на данный момент невозможно объявлять 2 метода с одинаковым названием? В вашем примере можно выдать ошибку, что нет подходящего метода, т.к. используется несколько методов с одинаковым названием.
            • 0
              Хм, пожалуй вы правы. В приведенном коде, проблема скорее не в BC, а в том, что неясно какая реализация должна отработать.
              • 0
                Я думаю никакая, можно было бы выдавать Fatal error, раз уж вводят переменное число аргументов, то есть смысл отказываться от магии func_get_ars().
                • 0
                  Отказаться от func_get_ars() было бы просто чудесно. Но вот это уже точно сломает BC :)
                  • +1
                    В содружестве с ...$params BC break тоже будет?
                    И если честно — пускай уже ломают наконец обратную совместимость, ради таких вот фич, старые движки и так выше 5.3 не поднялись, хочешь юзать 5.6 — учитывай нюансы, в противном случае бери старую версию
                    • 0
                      возникнет новая профессия — откатывать версию php после нерадивого админа
                  • 0
                    Ну, можно проводить поверку типа что если func_get_args() вызывается в методе, который имеет «брата» по названию в данном классе, то генерим ошибку.
              • +1
                Возможно, ввести модификатор? Не знаю, практикуется ли это среди других языков, но раз у нас^
                — динамичный php,
                — важна обратная совместимость,
                — мы пытаемся сделать кошерную перегрузку,

                то нужно ввести модификатор для перегруженных методов. Устанавливать какое-нибудь primary для «главного» метода, или точнее fallback-метода (и тогда назвать модификатор fallback? :)). И в случае, если вызов не совпадает с набором аргументов ни у одного из серии перегруженных методов, вызывать праймери так, как это делается сейчас. Если праймери нет, выбрасывать фатальную ошибку.
                • +1
                  Такое практикуется в других языках, например в delphi надо указывать override методу, чтобы его перегрузить и помоему в с++.
                  • 0
                    Отличная идея!
        • +2
          Перегрузку методов сложно сделать при наличии опциональных аргументов — интерптетатору и программисту сложно будет отличить вызов метода с опциональными аргументами от вызова перегруженного метода без аргументов.

          class foo {
              public static function bar($optional = false){ 
                  return $optional;
              }
          
              // как бы перегруженный метод, в том же классе или наследнике 
              public static function bar(){ 
                  return true; 
              }
          }
          var_dump(foo::bar()); // ??? какой метод должен вызваться ???
          
          • 0
            Да, это хорошее замечание, спасибо.
          • +3
            Выдавать Fatal error что объявлено 2 метода, которые по сигнатуре одинаковы. И проблема решена.
            • +3
              Ну сейчас так и сделано: Fatal error: Cannot redeclare foo::bar() ;-)
              • 0
                )) осталось только добавить подсчёт обязательных параметров и сравнение их типов…
                • +1
                  Олег, тут на самом деле очень большая проблема с производительностью возникает. Придется для каждого метода отдельные хештаблицы держать с сигнатурами для каждой перегрузки. Это увеличет время вызова метода и потребляемую память одновременно, что вообще рассматривается как очень плохо. В языках, которые вы приводите, нужные перегрузки, скорее всего (не уверен насчет джавы), резолвятся на уровне компиляции, поэтому рантайм остается при нормальных скоростях.
                  Хотя, в принципе, насчет таблицы для каждого метода, — наверное можно было бы и в общую таблицу всех сувать, но надо тогда там сразу использовать имена с хешированными до строки сигнатурами. Ну тогда будет сложно резолвить метод, у которого есть опциональные аргументы, если он при этом вызван с опущением каких-то из них… В общем, все это довольно сложно, и уже из-за пинка по производительности я бы не хотел такого.
                  • 0
                    Ну и самое главное — непонятно кто это реализует
                    • 0
                      Вот здесь можно посмотреть пример кода к последней версии моего RFC. Основное изменение — это добавление модификаторов dynamic и override. Я полагаю, они должны решить проблему как обратной совместимости, так и падения производительности. Но вот с реализацией — это да, я пока не знаю, как найти человека, который бы за это взялся.
      • +6
        Пощеголяли умным термином? А почитать, что он означает, никак?

        Для минусующих: ситуативный (или ad-hoc) полиморфизм — перегрузка функций, т.е. объединение под одним именем нескольких существенно различных реализаций, принимающих различные (по типу, количеству) аргументы.

        В чудесном предложении автора реализации метода в подклассе ломает интерфейс
        • –3
          Т.е. вы полагаете, что перегрузить метод можно только в том же классе, а в наследнике нельзя? Моё предложение не ломает интерфейс, смотрите пример из поста:
          var_dump($square->calcPerimeter(array(1, 1, 1, 1))); // 4
          var_dump($square->calcPerimeter(1)); // 4
          

          Как видите, работают оба варианта.
          • +4
            Вот вам пример контрпример:

            class Figure {
              function calcArea(array $sides) { /* realisation */ }
            }
            
            class Square extends Figure {
              function calcArea(int $side) { /* realisation */ }
            }
            
            
            /* У меня есть функция, использующая ваш код */
            function area(Figure $f, $sides) {
              return $f->calcArea($sides);
            }
            
            $square = new Square();
            area($square, [1, 1, 1, 1]);
            


            Моя функция полагается на интерфейс, заданный классом Figure, и соответствующим образом вызывает метод. Будет вызван метод Figure::calcArea(), но позвольте, откуда, вообще говоря, базовый класс знает, как устроен подсчет в данном случае площади в дочернем?

            • –2
              Вроде ваш пример не отличается от моего. Базовый конечно не знает про реализацию методов в дочернем классе. Наоборот, если аргументы в методе дочернего класса не совпадают с параметрами вызова, то вызов передаётся в родительский класс.

              Я видел ваш комментарий в соседней ветке, про то, что должна быть возможность перегружать метод в одном классе. И мне этот подход тоже нравится. Нравится настолько, что я его вкюлчил в изначальный вариант RFC. Вы и dim_s высказали много интересны мыслей. Мне надо некоторое время на подумать, как это всё увязать. Спасибо за интересную дискуссию!
              • 0
                Я поменял периметр на площадь для наглядности, ибо площадь только по сторонам не посчитаешь, надо знать больше о геометрии фигуры, а о ней может знать только дочерний класс
                • 0
                  В этом случае Figure::calcArea() должен содержать больше аргументов, а не только $sides, либо этот метод должен быть абстрактынм. Иначе получается, что он нерабочий.
                  • +1
                    Ну тогда базовый класс должен стать очень умным и уметь все делать за своих наследников, даже еще не написанных.

                    Нет, в вашем примере с периметром не должен — стороны определяют периметр.
                    Только зачем городить огород, когда можно было сделать так:
                    abstract class Figure {
                      function __construct($sides) { $this->sides = $sides; }
                      function calcPerimeter() { return array_sum($this->sides); }
                      abstract function calcArea();
                    }
                    
                    class Square {
                      function __construct($side) { /* irrelevant */ }
                      function calcArea() { return $this->sides[0] * $this->sides[0]; }
                    }
                    
                    class Polygon {
                      function __construct($sides, $angles) { /* irrelevant */ }
                      function calcArea() { /* большая формула, не помню, какая */}
                    }
                    


                    очень ООПшно
                    • +1
                      Или так:

                      interface calculated {
                          public function calcArea();
                      }
                      
                      abstract class Figure implements  calculated {
                        function __construct($sides) { $this->sides = $sides; }
                        function calcPerimeter() { return array_sum($this->sides); }
                      }
                      
                      class Square {
                        function __construct($side) { /* irrelevant */ }
                        function calcArea() { return $this->sides[0] * $this->sides[0]; }
                      }
                      
                      class Polygon {
                        function __construct($sides, $angles) { /* irrelevant */ }
                        function calcArea() { /* большая формула, не помню, какая */ }
                      }
                      


                      Но я бы не отказался от
                      class Calculator {
                        function __construct($name) { /* irrelevant */ }
                        function calculate(array $prices) { /* calculation */ }
                        function calculate(PriceCollection $collection) { /* calculation */ }
                      }
                      

        • 0
          Не ломает, т.к. Figure это не интерфейс, а класс.
          • +4
            Отвечу тут.

            Ок, не ломает, я не так выразился, потому что не совсем так понял идею.

            Класс/не класс — важно то, что родительский класс определяет интерфейс для дочерних.
            Когда дочерний класс реализует (переопределяет) метод из этого интерфейса, я ожидаю, что именно переопределенный метод и будет вызван в случае: $figure->calcPerimeter(/* args */).
            Ан нет, будет вызван базовый метод. Дочерний класс, получается, создает свой метод, который можно вызвать только если знать как (какие именно у него аргументы). Только называется этот метод почему-то так же, как интерфейсный
            • +2
              Да тут я согласен конечно, в статически типизированных языках такая проблема в этом случае отпадает. Но однако, вы же можете вызвать любой метод у объекта, не зная его класса. Это же динамическая типизация.

              Когда дочерний класс реализует (переопределяет) метод из этого интерфейса, я ожидаю, что именно переопределенный метод и будет вызван в случае: $figure->calcPerimeter(/* args */).


              Если сделать figure интерфейсом или абстрактным классом с абстрактным методом, тогда будет то чего вы ожидаете, надо будет определить в классе 2 метода с одним названием. Поэтому здесь нужна перегрузка методов, а не то что предложено в статье.
              • 0
                надо будет определить в классе 2 метода с одним названием

                Именно! Перегрузка если и должна быть, то в пределах одного класса. Дочерние, если делают метод с тем же именем и другими параметрами, обязаны реализовать и метод с сигнатурой родительского.
                • +3
                  Не обязаны — просто при вызове с соотв. количеством аргументов должен автоматически вызываться родительский.
      • 0
        Это называется непониманием базовых принципов ООП и SOLID, а именно — LSP (принцип подстановки Барбары Лисков), который гласит, что объекты классов-наследников, расширяющих базовый класс, могут использоваться вместо экземпляров базового класса без каких-либо изменений желательных свойств этой программы.

        Картинка прилагается:
        image
  • +4
    class foo {
        public $x = 1;
    }
     
    class bar {
        public $y = 'foo';
    }
     
    $x = 'bar';
    
    
    $bar = new bar;
     
    var_dump((new bar)->y);     // foo
    var_dump((new $x)->y);      // foo
    var_dump((new $bar->y)->x); // 1
    
    


    Это уже давно работает (5.4+).
  • +10
    В PHP, как всегда, все сделали по-своему, причем абсолютно непостижимым образом

    • Троеточие перед именем переменной — выглядит ужасно. Наверняка хотели сделать «как в Java, но не совсем».
    • new foo()->xyz; — не вижу ничего поразительного. В нормально написанной грамматике не должно быть разницы, какое выражение использовать перед обращением к полю — вызов функции, литерал или создание нового объекта. Да и вообще, странная практика — создать объект и тут же потерять ссылку на него.
    • Использование ключевого слова default при вызове — уж лучше тогда добавить именованные аргументы, потому что это — неудобный костыль.


    Извлечение функций из пространств имен и модификатор deprecated — возможно. Единственная же реально полезная и правильная штука — это исключения вместо Fatal Error. Даже как-то странно, что это ввели только сейчас.
    • +1
      Троеточие перед именем переменной — выглядит ужасно. Наверняка хотели сделать «как в Java, но не совсем».

      Как в EcmaScript 6
    • +1
      В PHP ничего ещё не сделал, что вы разоряетесь-то? Что, блин, такое «выглядит ужасно»? Вот по-моему слово «троеточие» выглядит ужасно, потому что такого слова нет. Многоточие перед именем переменной — синтаксис, как синтаксис, ничего удивительного. Ничем не лучше и не хуже решётки перед именем переменной, собачки, скобочек или ещё каких-то значков. Но у многоточия хоть логика есть — это понимаемый многими программистами символ «тут ещё аргументы идут», так сделано в Си, Луа, Гоу и многих других языках.

      В new foo()->xyz конечно ничего поразительного нет, просто PHP надовит порядок в синтаксисе, радоваться надо. Создать и потерять ссылку на объект — тут ничего странно нет, например, у нас богатый объект работы с датами, а всё что нам хочется — получить нашу дату в другом формате. Делаем: new Datetime('1977-09-13')->format("%d/%m%Y"), как-то так. Неужели не сталкивались с чем-то похожим?

      Ну и использование default — это, конечно, костыль. Неясно зачем было делать ключевое слово, если можно было просто запятые ставить для пропуска, как это уже сделано в конструкции list. Впрочем, такой явный синтаксис даст, думаю, меньше ошибок. А именованные аргументы — это чудесно, после Пайтона мне их в ПХП не хватает. Но это не значит, что default лишит нас именованных аргументов.
      • 0
        «Выглядит ужасно» — субъективное мнение. Я согласен, что использование многоточия очевидно с точки зрения семантики, но оно хорошо смотрится в после идентификатора, а не перед ним. Например, String... params в Java. Можно было бы сделать $args... — было бы сильно лучше.

        Наведение порядка в синтаксисе — это хорошо, но я сильно сомневаюсь, что это так. Больше похоже на то, что для некоторых вещей просто добавляются дополнительные правила в грамматику. Когда я последний раз в нее заглядывал, там были отдельные правила наподобие return variable и return expr_without_variable. Почему переменная не является частным случаем выражения — тайна, покрытая мраком.

        Что же касается default — то зачем сначала делать костыль, чтобы потом сделать как следует? Это же не срочная фича, без которой народ изнемогает, а если сделать сейчас так — то потом придется поддерживать оба варианта.
        • +1
          Я согласен, что использование многоточия очевидно с точки зрения семантики, но оно хорошо смотрится в после идентификатора, а не перед ним. Например, String… params в Java. Можно было бы сделать $args… — было бы сильно лучше.

          Опять вкусовщина. По мне как угодно хорошо смотрится, вам кажется, что лучше после параметра. Какая разница? Вы привыкните через неделю и перестанете внимание обращать. Вы путаете хорошее с привычным. Вы привыкли как в Джаве, вот вам и кажется, что так красивее.
          Это же не срочная фича, без которой народ изнемогает, а если сделать сейчас так — то потом придется поддерживать оба варианта.

          Может и изнемогает. Вы же опрос не проводили, так зачем же утверждать то, чего не знаете?
          • 0
            Вы привыкли как в Джаве, вот вам и кажется, что так красивее.

            Зачем утверждать то, чего не знаете? :) Я ни разу в жизни не писал на Java. Привычнее мне все-таки params из C#, однако вариант с многоточием из Java мне все равно кажется более грамотным, хотя бы потому что очень часто хочется объявить функцию с аргументом params — а нельзя, ключевое слово.

            Вы привыкните через неделю и перестанете внимание обращать.

            Честно пытался, но привыкнуть можно к чему-то постоянному. В PHP же именно постоянства-то и не хватает: что синтаксис, что стандартная библиотека постоянно подкидывают неожиданные (и как правило неприятные) сюрпризы. Хаотическое развитие с одной стороны и необходимость обратной совместимости с другой — вот и имеем то, что имеем.
        • 0
          Когда я последний раз в нее заглядывал, там были отдельные правила наподобие return variable и return expr_without_variable. Почему переменная не является частным случаем выражения — тайна, покрытая мраком.

          Так, по-моему, подобными нововведениями и стремятся избавиться от этого. То есть будут добавляться все больше новых правил, пока в один прекрасный момент не выкинут их все, не ломая обратной совместимости.
          • 0
            Это было бы бессмысленно. Добавлять новые правила по одному, чтобы потом заменить их все на одно общее — можно же сразу заменить только существующие на одно общее и получить абсолютно тот же результат сразу же.
            • 0
              Слишком много изменений, возможно ломающих BC, в одно релизе получится.
              • 0
                Так и надо. Выпустили бы два релиза: один со всеми плюшками и без заботы о мифической BC (вспоминаю про php 5.3 и preg_quote и понимаю что её нет) и второй без них, но с длительным временем жизни (фиксы ошибок и уязвимостей)
                • +1
                  Вы считаете, что лучше революции, другие считают, что лучше эволюции. Оба мнения имеют право на жизнь.
  • 0
    Я правильно понимаю, что new foo()->xyz это просто замена созданию собственного текучего интерфейса? Или за этим кроется что-то еще?

    Переопределение списка аргументов понравилось, но из-за контекста переменного числа аргументов не сразу понял, что вызывается метод из Figure. Что будет, если передадим 2 аргумента в calcPerimeter? При этом смена класса судя по всему не происходит и вот это, как мне кажется, сильно может запутать. Возможно просто пример не совсем удачный.

    P.S. Ну и не особо по теме вопрос — где можно посмотреть какая версия php используется сейчас большинством? Подразумеваю, что 5.3 какой-нибудь, т.к. до сих пор вижу на некоторых хостингах 5.2, что практически сводит на нет весь прогресс PHP…
    • 0
      Вообще-то если мы создали объект, на стеке должна лежать ссылка на него, а если на стеке объект, то мы должны иметь доступ к этому объекту. Так что это скорее ограничение или недальновидность синтаксического анализатора PHP. Тоже самое было с func()[...] и т.п.
      • 0
        Спасибо, но я, видимо, не настолько суров...) это ответ на какой вопрос из первых двух?)
        Скорее всего на первый…

        Если на второй, то уже нашел похожий на мой вопрос этот комментарий и ваш ответ)
        • 0
          Да на первый, чтобы понять это нужно хоть немного знать теории из асм-а или байткода (который похож на асм код). PHP компилирует исходный код в байткод, в котором буквально следующая последовательность команд: положить 1 на стек, положит 2 на стек, сложить последние 2 числа из стека и поместить результат на стек. Все в таком разжеванном виде. Для new + доступ к полю почти тоже самое: создать объект положив его на стек, положить на стек имя свойства, взять значение свойства используя 2 последних элемента из стека.

          Поэтому я считаю что даже такое должно работать:

          function(){
             return array('x' => new MyObject());
          }()['x']->method();
          
          • 0
            ну некоторые базовые вещи (которые вы написали) я понимаю и пример с функцией понятен, но скорее всего я не так вопрос задал, попробую немного перефразировать.

            в php 5.6 будет возможно такое, даже не возвращая $this в каждой функции?:

            class foo {
                public $x = 5;
             
                public function bar() {
                    $this->x = 10;
                }
                public function baz() {
                    return $this->x;
                }
            
            }
             
            var_dump(new foo()->bar()->baz());               // int(10)
            
            • 0
              Не возвращая $this в каждой функции, это сделать невозможно. Каждый следующий метод в цепочке вызывается на том объекте, который был возвращен из предыдущего. Как только вы перестанете возвращать $this, контекст потеряется.
              • 0
                так ведь и это мне понятно :)
                просто мне почему-то показалось, что в php 5.6 решили сделать возврат $this по-умолчанию там, где возврата нет вообще. поэтому и спросил, так ли это.

                Первый пример из rfc про Without brackets как раз и отвечает на мой вопрос, что нет, return $this никуда не убрали

                пример из rfc
                <?php
                 
                class foo {
                	public $x = 1;
                 
                	public function getX() {
                		return $this->x;
                	}
                	public function setX($val) {
                		$this->x = $val;
                		return $this;
                	}
                }
                 
                $X = new foo->setX(10)->getX();
                var_dump($X); // int(10)
                 
                ?> 
                
                • +1
                  К счастью.
  • 0
    Синтаксис 2 (со скобками)

    (new foo())->bar()
    (new $foo())->bar
    (new $bar->y)->x
    (new foo)[0]


    Вот чего действительно не хватало, обращения с объектами — +5 к динамике)
    • 0
      А зачем так много вариантов?

      Например, зачем варианты 2 и 3 одновременно?
  • 0
    Совместимость с E_RECOVERABLE_ERROR

    Сейчас можно игнорировать восстанавливаемые фатальные ошибки, используя кастомный обработчик ошибок. Заменив их на исключения, мы потеряем такую возможность, ломая, таким образом обратную совместимость.

    Имхо все нововведения имеющие проблемы с обратной совместимостью надо вносить все же не в минорные версии, а мажорные.

    Это сильно упрощает жизнь разработчикам и админам.
    • +1
      А в чем сложность для старых проектов сохранять определенную версию php?
      • 0
        Просто было бы хорошо, если бы все придерживались единых правил: semver.org/
        • +3
          В тоже время у PHP сложилась традиция — первая циферка означает кардинальную смену, боюсь что даже подхода к программированию на этом языке. Вторая — расширения синтаксиса, всякие плюшки и прочее. Третья — версия билда, патчфиксы всякие и прочее.

          Исходя из всего этого — вторую циферку можно считать вполне себе мажорной, а первую — вообще как будто новый язык вышел.
    • +1
      Фига себе минорные версии, выпускаемые раз в 1-4 года.
    • 0
      В данном случае минорные версии это 5.x.xx, а мажорные 5.x. 6 (если когда-нибудь она выйдет) будет наверное означать глобальную потерю обратной совместимости и/или полную замену движка.
      • +1
        6-ая юникод же :)
        • 0
          Вот поэтому и «если когда-нибудь она выйдет». В том числе ведь юникод будет означать и глобальную потерю своместимости.
          • 0
            Разве что [] для строк перестанет работать (его кто-то вообще использует?), вместо остальных функций все равно давно используются mb_*
            • 0
              Не все так просто. Банальная strlen начнет возвращать другие результаты, а это очень часто используемая функция для определения количества байт (sic!) в строке.
              • 0
                Пожалуй… Можно вынести новые функции в пространство имен std (это же все равно рано или поздно сделают?), а старые оставить как есть (с такой же логикой), через пару версий объявить устаревшими и еще через 2-3-… версии выпилить.
                • +1
                  Мне более логичным кажется перевод большинства функций в методы классов и/или в разные (многоуровневые) нэймспэйсы. Типа $string->lenght(), String::lenght($string) или \Std\String\lenght($string) или какие-то их комбинации.
                  • 0
                    ИМХО, «перевод большинства функций в методы классов» никогда скорее всего не будет :(
                  • +1
                    Я вот как-то развлекался, вынеся работу со строками (и частично с массивами) в отдельный namespace через C расширение: Str\len('foo'); Str\endsWith('UnifiedPHP', 'PHP'); Arr\filter(Arr\range(20), function($i){...}); и т.п.

                    Может, использование подобных костылей и есть удел желающих получить подобный синтаксис.
                    • 0
                      Развлекался я тоже подобным образом, правда путем создания классов, пытаясь реализовать что-то вроде «Всё объект».
                      • 0
                        Да я лишь хотел последовательные и понятные имена, порядок аргументов и недостающие «парные» функции.
                        «Все объект» тоже интересно, вопрос проседания по скорости(
                        • 0
                          Собственно начал копать в сторону расширений, когда частично реализовал на самом PHP, порадовался, а потом решил бенчмарк сделать. Но забросил это дело потом так как не смог разобраться как реализовать перегрузку операторов для некоторых классов без патчиния самого php, а то $str1->concat($str2) менее удобно было чем $str1 . $str2.
  • +4
    Исключения вместо фатальных ошибок — как я долго этого ждал. Ура!
  • +5
    Как же я хочу, что бы взяли наконец PHP, выкинули нафиг весь мусор, взяли всё самое лучшее, стандартизировали имена\пути и прочее по PSR и выложили в виде новой, мажорной версией PHP, а не пичкали всё новым и новым.
    • +2
      Простите за нескромный вопрос — зачем вы ждете такого именно от PHP? На нем свет клином не сошелся. Есть же Python, Ruby, Node.JS, ASP.NET в конце концов.
      • +3
        Эм мне перечислять все плюсы, начиная от бедных дотнетчиков, пускающих горючие слёзы от того, что новая версия ИЕ присылает им флоаты, вместо интеджеров в input type=«image» до бедных рубистов, которые постоянно переживают, что воркеры опять начнут кушать 99% процессора и по гигабайту памяти на десяток пользователей?

        Перечисление всех «за» и «против» пыха займёт много строек и буковок, и даже не взирая дичайшую свалку функций и безумие в типах я считаю его самым лучшим, что есть на данный момент под серверсайд, может из-за того, что я его лучше знаю, может из-за Java-like синтаксиса без строгой типизации — не важно. Важно, что топик про PHP 5.6 и разговор следует вести именно о нём, разве не так?
      • 0
        мне например совсем не нравится синтаксис в руби и питоне, нода только развивается и это вообще совершенно другой мир и пока другие задачи6 asp.net — я так понимаю это майкрософт, а значит не открыто, скорее всего запустится только на винде — спасибо, не нужно.
        • 0
          Вы очень давно последний раз смотрели в сторону asp.net. Исходный код фрейиворка открыт, есть стабильная кроссплатформенная реализация средств разработки и рантайма (Mono) — в ней все отлично работает. У нас в компании сайт на asp.net на никсовом сервере даже шустрее крутится, чем под windows.
      • 0
        Другие подходы. В чем-то лучше, в чем-то хуже, но, главное, другие.
  • –1
    Опускаем указание значений для необязательных аргументов:
    function create_query($where, $order_by, $join_type = '', $execute = false, $report_errors = false) { }
    create_query('deleted=0', 'name', default, default, /*report_errors*/ true);

    Не надо делать функции, содержащие более трех аргументов, и не прийдется придумывать костыли, решающие связанные с этим проблемы.
    • +1
      Я тоже не понимаю смысла этого, если уже ввели укороченный синтаксис множественных аргументов и в предложениях висит RFC с именованными аргументами.

      Плюс к этому — безумия добавляет указание «default» в качестве ключевого слова, следовательно:
      1) Надо знать, что аргумент имеет дефолтное значение и проще указать именно его (пустую строку, null или другое), а не писать default
      2) Почему именно «default», не проще ли просто запятыми пропускать?
      create_query('deleted=0', 'name',,, true);
      
      • 0
        Имхо, пропуск запятыми невозможно прочитать. Взгляните бегло на эту строчку с create_query и скажите, сколько времени вам понадобится чтобы определить, в какой по счету параметр передано значение true?
        • +2
          Невозможно прочитать с ходу код на Руби. По сравнению с ним — это просто небольшая причуда.
        • 0
          Имхо, если после каждой запятой ставить пробел, как это делается в естественных языках, то читабельность такого выражения станет куда лучше.
          • 0
            Я бы предложил "_", но это наверное из Python, где он используется для распаковки неиспользуемых позиций.
      • +1
        null не катит. Потому как разработчику прийдется как сейчас писать:
        if($a === null) {$a = true}
        if($b === null) {$b = self::BLA_BLA}
        

        default самое нормальное, особенно если IDE будет подсвечивать это дело
        • 0
          Во многих стандартах кода как раз требуют ставить единственно-возможным дефолтом — null. Это позволяет обрабатывать дефолты для объектов в том же стиле, что и для остальных типов данных. Та же ситуация с более сложной логикой определения дефолтов.

          Ну и плюс, не совсем понимаю, зачем логику выбора дефолтов выносить в сигнатуру функции/метода.

          Короче, лично я уже давно перешёл на инкапсулированные дефолты внутри метода/функции и на null-значения для необязательных параметров в сигнатуре.
  • +1
    Было бы здорово, если б в 5.6 запилили как в Java возможность определения одноименных методов класса с разным набором типизированных аргументов. Но очевидно пока такое в чистом виде реализовать нельзя без статической типизации. Но хотя бы с разным количеством аргументов вариант был бы кстати.
    • 0
      Почему нельзя? Достаточно в случаях без указания типа ввести какой нибудь псевдотип «any» и проблемы уже нет.
      • 0
        Даже этого делать не нужно, отсутствие типа у аргумента и так подразумевает любой тип any.
  • +2
    Оторвать руки у любителей писать такое:
    function foo($var, ...$params)
    {
        ...
    }
    


    И заставить использовать унифицированное, понятное и не требующее особой поддержки ЯП:
    function foo($var, array $params = array())
    {
        ...
    }
    


    Всё равно в итоге массив получаете. Нафига вам ещё какой-то сахар для того, что надо выпилить к чертям из языка и всё.
    • 0
      function foo($var, array $params = array())
      {
          ...
      }
      


      function foo($var, array $params = [])
      {
          ...
      }
      

      fixed и уже не столь унифицированное

      Но в любом случае предложенный синтаксис лаконичней, просто небольшой сахарок, не ломающий BC
    • 0
      Да, но тогда перед вызовом foo() массив $params приедтся собирать вручную. С новым синтаксисом будет удобнее.
      • +1
        Ну, «собирать» громко сказано. Вместо foo(1, 2, 3, 4, 5) будет foo(1, [2, 3, 4, 5]), но, да, чуть удобнее будет сновым.
    • 0
      Там вон ниже уже привели второй RFC из этой же темы wiki.php.net/rfc/argument_unpacking очень приятно в некоторых местах отказаться от call_user_func_array. Поэтому в паре достаточно неплохая функциональность.
  • 0
    function fn($reqParam, $optParam = null, ...$params) { }


    Не очень-то практично: с появлением [короткого] синтаксиса массивов нет почти никакой разницы с fn($reqParam, $optParam = null, array $params = []).

    Куда уместнее было бы аналогичным образом избавиться от call_user_func_array. Скажем, так:

    function fn($param1, $param2, $param3) { }
    
    $args = [1, 2, 3];
    fn(...$args);
    
    

    Или даже так

    $more_args = [2, 3];
    fn(1, ...$args);
    


    Это намного чаще нужно — в фабриках, DI и т.п.
    • +1
      Буду краток: wiki.php.net/rfc/argument_unpacking =)
      • 0
        О! Надеюсь, это войдет в релиз.
      • 0
        Это одна и моих самых больших хотелок в PHP. Особенно, если именованные параметры поддерживать будет.
  • +2
    То, что дело дошло до перевода фаталов в исключения — это очень хорошо. Если это примут, писать и обслуживать приложения станет проще и удобнее. Жалко, что до этого добрались так поздно.

    Вообще, в PHP есть только несколько серьезных концептуальных проблем. Вот фаталы — одна из них. Может их по-тихоньку выпилят и язык обретет новую жизнь. По сути главное, что надо еще сделать, — это полностью переписать все стандартные функции, классы и все, что с ними идет, но объектный и единый стиль, избавиться от хаоса именований и подходов. Т.е. привести всю внутрянку в нормальный вид.

    Это что касается самого языка. А что касается среды исполнения, то тут надежды на HHVM. Если Facebook не забъет на этот проект и сообщество его подхватит, это станет новая дефолтовая среда для исполнения PHP, на порядок лучше старой интерпретации.

    Если каким-то чудом срастется это все, то у PHP однозначно начнется новая жизнь.
    • 0
      Фатальные ошибки это не концептуальная проблема, а ваше нежелание принять и начать использовать подход отличный от исключений. Так же не нужно забывать что PHP сочетает в себе ООП и функциональное программирование (в котором исключениям в их текущем виде нет места), поэтому никто не станет просто так их выпиливать.
      • +2
        1. Мое нежелание тут не причем. Подход должен быть единым, а не половина ошибок через исключения, вторая — через фаталы. Ничего нормального в этом нет при любом раскладе вне зависимости от моего и вашего понимания этого вопроса. Подчеркиваю — в этом нет даже нормальности, не говоря о том, что это может быть хорошо. Такой подход был актуален до появления исключений.

        2. Я не против сочетания ООП-подхода и процедурного, если для ООП все написано как положено, в объектном стиле. Т.е. полное дублирование (естественно через обертки) всего коробочного функционала — для работы в процедурном стиле, и ООП. А то, что сейчас все перемешано — это одна из серьезнейших проблем языка.
        • 0
          Сейчас ничего не мешает перевести большую часть ошибок в исключения и те кому это нужно уже давно так и сделали, насколько нужны исключения вместо оставшихся? Вот, например, что делать если вылезла E_CORE_ERROR?
        • 0
          А то, что сейчас все перемешано — это одна из серьезнейших проблем языка.

          Проблема только в том, что это гораздо удобнее чем чисто ООП подход когда приходится создавать или объекты ради объектов или статичные классы с набором функций (которые по сути ничем не отличаются от обычных функций).
          • 0
            А вы точно не путаете функциональное программирование с процедурным?

            Одна из проблем PHP в том, что практически любой код невозможно написать без использования «процедурно-ориентированной» стандартной библиотеки. И когда в теле метода приходится использовать процедурный подход (от strlen() до resource переменных) то это вызывает диссонанс и желание перейти на ЯП, где «всё объект».
            • 0
              Да, вы правы.

              Но вот как раз strlen и прочее удобнее чем объекты:
              srtlen($var); // тип может быть почти любой
              
              ((string) $var)->length(); // на фиг, на фиг ...
              


              В Java так и есть «всё есть объект», но лямбды всё равно добавили — не от хорошей жизни наверное?
              • 0
                Я редко использую неявные приведения типов, предпочитая их явным, поэтому ((string) $var)->length() для меня выглядит предпочтительней :)

                Но лямбды всё равно же объект.
            • 0
              Согласен, но с небольшой оговоркой. Вот как раз про strlen. Я, лично, не сторонник перевода базовых типов в объекты. Т.е. я не хочу, чтобы все строки внезапно стали объектами. И тем более не хочу раздвоения, когда есть и string, и String. Это никому не нужно. Но все методы для работы со строками привести к виду String::length() — вот это то, чего я хочу. Более того, это даже сделать можно относительно не сложно. Надо только научиться писать расширения, потому что такие обертки на PHP будут тормозить приложение.
              • +1
                Это никому не нужно.

                Не говорите за всех :)
                Но все методы для работы со строками привести к виду String::length() — вот это то, чего я хочу.

                Не вижу особого смысла. Почему не к виду \String\length()?
                • 0
                  Не говорите за всех :)


                  Даже, если будет по вашему, но оно будет работать не медленнее, чем сейчас, я не против. Я против вариантов с приведением типов (даже автоматическим), или варианта, когда вся память будет засрана строками-объектами.

                  Не вижу особого смысла. Почему не к виду \String\length()?


                  Потому что это по прежнему процедурный стиль. Например, можно засунуть свою функцию в \String. Я против этого, будет тоже самое, что с глобальными массивами. С другой стороны можно сделать ProjectString extends String, чтобы расширить функционал, но сохранить целостность. Для нэймспейсов так не сделаешь.
      • 0
        Я тоже рад, что фаталы можно будет переводить в исключения. И уж «начать использовать подход отличный от исключений» точно не про меня, поскольку я начинал писать ещё на PHP3, где исключений не было вообще.

        И за 10+ лет я не видел ни одного проекта на PHP на котором бы использовалось чистое ФП, без императивных возможностей. Ну и главное — если вы не используете исключения в своем проекте, то так же будете получать фатальные ошибки и можете их обрабатывать привычным для вас способом. Это лучший компромисс чем «заставлять» оопщиков и процедурщиков на большую часть стандартных функций писать обертки, отлавливающие ошибки и переводящие их в исключения.
        • 0
          Насколько часто в ваших проектах возникают фатальные ошибки?
          • 0
            По 10 раз на дню.
            • 0
              А какая их часть не может быть переведена в исключения сейчас?

              ЗЫ: как то сомнительно что в нормальных проектах десяток фатальных ошибок в день это нормально.
              • 0
                Собственно большая часть переведена, но костылями типа проверки существования метода перед его вызовом. Проблема в том, что на одном логическом действии может возникнуть куча ошибок, которые по бизнес-логике фатальными не являются, но по логике PHP являются, и приходится для атомарной по бизнес-логике попытке что-то сделать городить кучу проверок для каждого возможного типа фатальных ошибок, а результатом этих проверок является выбрасывание одного типа исключения.
          • 0
            В реальных проектах возникают. Только это не важно. Важен подход.
      • 0
        Функциональщина в php чисто номинальная, для написания небольших кусков в ФП-стиле вполне подойдет, но не более. Без restarts смысла в плане обработки ошибок немного. Проще с исключениями по аналогии с handler-case в лиспе.
  • 0
    Давно ждал такого
    function create_query($where, $order_by, $join_type = '', $execute = false, $report_errors = false) { }
    
    create_query('deleted=0', 'name', default, default, /*report_errors*/ true);
    


    Но еще бы
    
    class B {
        public function n ($a, $b = 456) {
            return $a . $b;
        }
    }
    
    class A extends B {
        public function m ($a = 123, $b = default) {
            return parent::n($a, $b);
        }
    }
    
    $a = new A();
    
    echo $a->m(); // 123456
    
    echo $a->m(000); // 000456
    
    echo $a->m(321, 321); // 321321
    
    echo $a->m(default, 321); // 123321
    
    
  • 0
    Переопределение списка аргументов

    Может кто-то подсказать где найти обсуждение или rfc сейчас этой фичи?
    • 0
      До RFC дело не дошло, всё осталось на уровне обсуждения на рассылке internals@lists.php.net
      Если интересно, могу форварднуть
      • 0
        Да, я пытался найти историю этой рассылки, но письма только до сентября 2015 смог найти. Почту в приват написал.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.