Как стать автором
Обновить

Комментарии 51

Что-то относительно мало ссылок, или мне так кажется?
В среднем в дайджестах бывает 50-70 ссылок, сейчас ближе к 50
Сейчас идёт голосование за интересное RFC — сделать последовательными индексы в массивах, формируемых функциями array_*
https://wiki.php.net/rfc/negative_array_index

Вкратце — скорее всего, не попадёт в PHP 7.2, но возможно будет в PHP 8
Вышла бета версия yii2 плагина для IDEA/PhpStorm.
Скачать можно из закладки Beta на https://plugins.jetbrains.com/plugin/9388-yii2-support
или по этой ссылке .

Из нового:
Автокомплит для правил валидации
Автотип для Yii::createObject

Прошу помочь с бета тестированием. Баги пишите в гит хаб: https://github.com/nvlad/yii2support
Прошел PHP-FWdays в Киеве. Обещают поделиться видео через одну/две недели. Скорей всего к следующему дайджесту появятся
Кто-то может новичку PHP объяснить смысл https://wiki.php.net/rfc/parameter-no-type-variance

В наследнике появляется возможность забить на тип аргумента в родителе (то есть мы расширяем). В комментах к пуллреквесту срач насчет нарушает ли контрвариация аргумента LSP или нет (вроде как нет). Но у меня вопрос — зачем? Даем пользователям библиотек продолжать использовать свои бестиповые наследники?
Я не могу себе придумать практическое применение этого вброса, который почти наверняка будет вести к нарушению LSP и OCP. Хочу схватиться за голову и бегать…
Как раз таки этот «вброс» ведет к частично более полному соблюдению LSP, в этом и суть.

Если кратко, то LSP состоит в том, что множество допустимых входных параметров вы можете только расширять, а множество возможных выходных параметров вы можете только сужать.

Сброс тайп-хинта сигнатуры позволит вам реализовать прослойки для управления обратной совместимостью, при этом сигнатуры вы все еще можете определять через phpdoc
Откровенно говоря, Ваше краткое определение LSP тоже заставляет хвататься за голову и…
А я не говорил, что это определение. Это одно из следствий со стороны обсуджаемого вопроса.

Если вы хотите строго по определению, то пожалуйста. Представьте, что у вас есть тип 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 об этом написано и даже приведено несколько реальных примеров.

Суть предложения в том, что если у предка указан тайпхинт, то потомок может уже не писать его, он будет взят из предка
По крайней мере я так это понял
В комментах указано
// This RFC proposes allowing the type to be widened to be untyped aka any
// type can be passed as the parameter.
// Any type restrictions can be done via user code in the method body.


То есть ограничения снимаются и дело не просто в отсутствии варнинга.
Огромное спасибо!
всегда с удовольствием читаю. спасибо.
Спасибо! Всегда читаю этот дайджест.
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?
Выше про object typehint вопрос.
Подскажите, что в RFC значит Accepted — Pending Implementation?
Одобрен, но ожидает реализации в коде.
То есть object typehinting скорее всего не ждать в 7.2? И вообще не факт, что оно дойдет до реализации в таком виде?
Видимо да. 7.2 уже в альфе, вряд ли там будет что-то новое.

Надеюсь это будет


(params) => expr
тоже подумал, что не плохо было бы сделать как в js, но этот вариант не просто так запихнули на предпоследнюю позицию
//пример
$param = 5;
[
	($param) => $param*2
]

//может восприниматься парсером так:
[$param => $param*2] //[5 => 10]

//или так
[
	function($param) {return $param*2}
]

скорее всего выберут fn

такой случай не часто встретишь. можно сделать что бы в этом случае парислся как массив, хочешь однозначности в массиве? — оберни в скрбки


[($param => $param*2)]
это понятно, но магии в php итак хватает, думаю разработчики не пойдут на такой шаг, к тому же это может поломать старые проекты
в общем поживём увидим

а в вашем примере благодаря скобкам что получится массив или функция?

Думаю должно быть очевидно что [func]

понятно, я неправильно прочёл фразу «хочешь однозначности в массиве? — оберни в скрбки», думал что вы подразумеваете массив, хотя там должна быть функция
скорее всего выберут fn

function fn() {
    // bad ass
}

[fn($x) => $x ** 2]

то есть все те же проблемы и еще большая обратная несовместимость. С другой стороны....


[
    ($x => $x**2)
]

уже будет нам говорить что это массив выражений. Скобки неплохой вариант устранения двусмысленности с точки зрения синтаксиса. Вот только парсеру это не помогает особо и этот вариант все равно остается сложным. Ну мол что бы было кошерно надо как-то по первой лексеме понять что у нас тут лямбда.


Потому скорее уж примут function ($x) => $x ** 2.

теперь понятно для чего они добавили второй и третий варианты

вообщем будем ждать голосования
Потому скорее уж примут

Почему не (params) ==> expr? Оператор ==> еще свободен, да и набирать не сильно сложнее чем =>.

еще свободен

  1. потому что проблема не в двусмысленности, ее устраняют скобки. Идея в том что бы поменьше операторов добавлять, хотя с другой стороны идея так же что бы одни и те же операторы сохраняли свой смысл вне зависимости от контекста чего не происходит с =>.
  2. потому что профита с точки зрения реализации парсера это не добавляет.
  3. потому что => лучше чем ==> или ~>.
  1. Новый оператор как раз в стиле PHP
  2. Отследить контекст ему проще?
  3. Хз, тильда непривычна, [](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 имеет свои преимущества.

которые не имеют смысла в этом контексте.


за это время все уже привыкли к стандартному синтаксису

примерно так же про синтаксис массивов говорили.

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

И в чем же эта разница?


примерно так же про синтаксис массивов говорили.

А вот его как раз реализовали правильно :)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий