Комментарии 51
https://wiki.php.net/rfc/negative_array_index
Вкратце — скорее всего, не попадёт в PHP 7.2, но возможно будет в PHP 8
Скачать можно из закладки Beta на https://plugins.jetbrains.com/plugin/9388-yii2-support
или по этой ссылке .
Из нового:
Автокомплит для правил валидации
Автотип для Yii::createObject
Прошу помочь с бета тестированием. Баги пишите в гит хаб: https://github.com/nvlad/yii2support
В наследнике появляется возможность забить на тип аргумента в родителе (то есть мы расширяем). В комментах к пуллреквесту срач насчет нарушает ли контрвариация аргумента LSP или нет (вроде как нет). Но у меня вопрос — зачем? Даем пользователям библиотек продолжать использовать свои бестиповые наследники?
Если кратко, то LSP состоит в том, что множество допустимых входных параметров вы можете только расширять, а множество возможных выходных параметров вы можете только сужать.
Сброс тайп-хинта сигнатуры позволит вам реализовать прослойки для управления обратной совместимостью, при этом сигнатуры вы все еще можете определять через phpdoc
Если вы хотите строго по определению, то пожалуйста. Представьте, что у вас есть тип T с методом T::f(A $a). И есть тип S extends T с методом, который отличается только отсутствием тайпхинта S::f($a).
Если сам код методов идентичен, то если свойство q(T x) верно, то и свойство q(S y) тоже будет верным
Таким образом исключение тайпхинта не нарушает LSP, а текущее поведение (фатал парсера) — нарушает. Что подтверждает мое утверждение
ведет к частично более полному соблюдению LSP
Во-вторых, Вы на основе чего программируете? Реализации? Не ведет это «к частично более полному соблюдению LSP». Если сигнатура гласила Razor::shave(Beard $beard), то, для возможности побрить что-то еще, необходимо не глушить сигнатуру в дочернем классе, а пересматривать решение на уровне интерфейса. Почему не, к примеру, Razor::shave(ShaveableInterface $hairySurface)?
Вы не подумайте, я на Вас бочку не качу)
Просто не в состоянии своё недоумение выразить в полной мере касательно «parameter-no-type-variance». Только и просится фраза «Зачем?!».
Только и просится фраза «Зачем?!»
Все началось с какого-то обсуждения в internals где предлагали что-то пофиксить но для того чтобы не ломать обратную совместимость пришлось ваять этот RFC. Все как обычно.
то если у Razor есть наследники (положим, это библиотека), то изменить сигнатуру указанным образом невозможно, это тут же нарушает LSP для наследников.
Если же сделать нового «правильного» наследника, с нужной сигнатурой, то текущая версия PHP кидается ворнингами (т.к. пока мы живем с инвариантами)
https://externals.io/thread/514
https://wiki.php.net/rfc/return_types#variance_and_signature_validation
Так что это полумера, но это единственное что позволяет перейти от одного интерфейса к другому с сохранением обратной совместимости и без особых костылей. Хотя если вы знаете короткий путь, то готов посмотреть
Да легко оно представляется, особенно когда есть куча старого кода, который надо поддерживать и рефакторить, более того, в самом rfc об этом написано и даже приведено несколько реальных примеров.
По крайней мере я так это понял
6 файлов, которые являются валидным PHP — GIF, PDF, JPG, которые можно выполнить как PHP.
Примажусь по случаю Как запустить *.jpg как *.php или как предотвратить исполнение загруженных юзером файлов
В примере есть код:
class WidgetFactory {
function create() {
return new Widget();
}
}
class CustomWidgetFactory extends WidgetFactory {
function create() {
$object = new Widget();
return true; //This is an error that cannot be statically analyzed.
}
}
Что мешает указать у метода create (): Widget?
Ну помешает вернуть true спецификатор: object, но что делать с остальными объектами, которые несовместимы с Widget?
Думаю скоро смержат в master
Надеюсь это будет
(params) => expr
//пример
$param = 5;
[
($param) => $param*2
]
//может восприниматься парсером так:
[$param => $param*2] //[5 => 10]
//или так
[
function($param) {return $param*2}
]
скорее всего выберут fn
такой случай не часто встретишь. можно сделать что бы в этом случае парислся как массив, хочешь однозначности в массиве? — оберни в скрбки
[($param => $param*2)]
скорее всего выберут fn
function fn() {
// bad ass
}
[fn($x) => $x ** 2]
то есть все те же проблемы и еще большая обратная несовместимость. С другой стороны....
[
($x => $x**2)
]
уже будет нам говорить что это массив выражений. Скобки неплохой вариант устранения двусмысленности с точки зрения синтаксиса. Вот только парсеру это не помогает особо и этот вариант все равно остается сложным. Ну мол что бы было кошерно надо как-то по первой лексеме понять что у нас тут лямбда.
Потому скорее уж примут function ($x) => $x ** 2
.
вообщем будем ждать голосования
Пока страждущие могут пользоваться фолдингом в IDE:
https://plugins.jetbrains.com/plugin/8477-php-lambda-folding
Потому скорее уж примут
Почему не (params) ==> expr
? Оператор ==>
еще свободен, да и набирать не сильно сложнее чем =>
.
еще свободен
- потому что проблема не в двусмысленности, ее устраняют скобки. Идея в том что бы поменьше операторов добавлять, хотя с другой стороны идея так же что бы одни и те же операторы сохраняли свой смысл вне зависимости от контекста чего не происходит с
=>
. - потому что профита с точки зрения реализации парсера это не добавляет.
- потому что
=>
лучше чем==>
или~>
.
- Новый оператор как раз в стиле PHP
- Отследить контекст ему проще?
- Хз, тильда непривычна,
[](params)
как-то странно выглядит, аfunction ($x) =>
совсем не короткий и оттого бессмысленный вариант. ИМХО, выберут между=>
и==>
.
2 нет. PHP юзает LR(1) парсер, то есть "не двусмысленно" это когда он может понять что он парсит смотря максимум на одну лексему вперед. Так что "просто" это когда у нас есть кейворд в самом начале выражения. Типа fn
или function
. Тогда парсер запросто все обработает.
В случае с массивом — скобочка будет для него сигналом что он парсит выражение, а не конструкцию в контексте массивов или генераторов, так что тоже все вроде бы ок. Но вот внутри выражения ламбда или нет — это он может догадаться распарсив список аргументов и это надо будет уже делать хитрости.
3 Между этими вариантами нет смысла что либо выбирать на самом деле. fn удобно и хороший компромис но вводит новое ключевое слово (обратная совместимость). function — длинно, хотя по факту не то что бы сильно:
$items = array_map(function ($row) => $this->hydrator->hydrate($row), $rows);
$total = array_reduce($items, function ($sum, $item) => $sum + $item->price());
// vs
$items = array_map($row => $this->hydrator->hydrate($row), $rows);
$total = array_reduce($items, ($sum, $item) => $sum + $item->price());
Вот именно что длинно, по сути только return
выбросили, это явно не то чего всем хочется.
$items = array_map($row => $this->hydrator->hydrate($row), $rows);
$items = array_map($row ~> $this->hydrator->hydrate($row), $rows);
$items = array_map($row ==> $this->hydrator->hydrate($row), $rows);
$items = array_map(function ($row) => $this->hydrator->hydrate($row), $rows);
$items = array_map(function ($row) { return $this->hydrator->hydrate($row); }, $rows);
$items = array_map(function ($row) {
return $this->hydrator->hydrate($row);
}, $rows);
это явно не то чего всем хочется.
ну тут как говорится, "хоти в одну руку, а..." Увы приходится идти на компромиссы в пользу простоты сопровождения парсера и отсутствия нарушений обратной совместимости :(
Имхо, добавлять кривой сахар смысла совсем нет, поэтому или действительно короткий синтаксис (лучше похожий на что есть в других языках) или ничего.
Представьте что вас просят добавить фичу, и вы можете реализовать фичу двумя способами:
- удобный пользователю, то что они хотят, но это усложнит реализацию на порядок и вам придется ее поддерживать годами (дорого)
- чуть менее удобный пользователю, зато намного более простой с точки зрения реализации, не требующий кардинальных изменений. (дешево)
Да, второй вариант всем не понраву, но он решает проблемы какого-то процента пользователей. Либо же не делать ничего. Как бы вы поступили?
Лично на мой взгляд, в php достаточно фич из разряда makeSomethingLikeFooButInAnotherWay. Если можно удержаться от «двусмысленности», то лучше так и поступить.
Выбрал бы первый вариант (==>
отношу к нему же) — кривая фича вообще никому не нужна (их тут и так слишком много), если это что-то ломает — есть следующая мажорная версия, а если это слишком сложно — не стал бы делать.
Выбрал бы первый вариант
то есть "то что они хотят, но это усложнит реализацию на порядок и вам придется ее поддерживать годами (дорого)".
а если это слишком сложно — не стал бы делать.
Это я к тому что при обсуждении RFC люди примерно так и думают. Либо сделать нормально, что технически невозможно на данный момент, либо не делать ничего.
Но все еще есть процент людей которым фича нужна даже с "лишним" кейвордом в начале.
То есть проблема — люди думают только о себе. Тем кто не видит смысла — фича не обязательная. С другой стороны убрать кейворд и сделать его опциональным в будущем не составляет особо проблемы.
то есть
Да, однако вы упускаете что поддерживать надо всё, поэтому, в данном случае, нежелание сделать нормально сразу это обычная лень.
Но все еще есть процент людей которым фича нужна даже с "лишним" кейвордом в начале.
Она была нужна давным давно, сейчас смысла в ней не очень много на самом деле. Но вообще дело не в лишнем function
, а в том что эта запись совсем не короткая, глядишь там еще и use
придется писать, а то сложно же по другому сделать...
нежелание сделать нормально сразу это обычная лень.
вам надо сделать в парсере гиганский кастыль который сможет чекать на N лексем вперед. Я не считаю что это "сделать нормально".
сейчас смысла в ней не очень много на самом деле.
аргументируйте. Есть альтернативы?
глядишь там еще и use придется писать
Почитайте RFC. В частности:
importing used variables from the outer scope implicitly
а то сложно же по другому сделать...
это как раз таки сделать не сложно. Сложно с парсером без кейворда в начале выражения.
аргументируйте. Есть альтернативы?
Что именно аргументировать? Анонимные функции есть давным-давно, короткий синтаксис всего лишь сахар, который первый раз был предложен пару лет назад (там кстати даже pr был...), за это время все уже привыкли к стандартному синтаксису + явный use
имеет свои преимущества.
Есть большая разница между "анонимными функциями" и "функциональными выражениями". В JS мире эту разницу тоже не сильно понимают потому пихают arrow functions бездумно.
явный use имеет свои преимущества.
которые не имеют смысла в этом контексте.
за это время все уже привыкли к стандартному синтаксису
примерно так же про синтаксис массивов говорили.
PHP-Дайджест № 110 – свежие новости, материалы и инструменты (28 мая – 11 июня 2017)