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

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

Если уж говорить о перспективах, так как об апи не было ничего сказано, то оное в jphp почти что идеально в той перспективе, в которой следует двигать оригинал. Яб точно не отказался увидеть это в будущей версии пыха.
Return Types долго ждал, понравилось как было сделано в первой версии RFC, которую забраковали, исправили это поведение так:
interface A {
    static function make(): A;
}
class B implements A {
    static function make(): B { // must exactly match parent; this will error
        return new B();
    }
}

Вот из-за этого поведения, return_types не будет использоваться активно. К примеру в Hack можно указать тип возвращаемого значения как 'this', то в текущей реализации в PHP этого сделать будет нельзя. В итоге люди все равно будут дальше использовать обычный phpDoc: @ return $this для этих целей, и IDE будет работать правильно.

Если бы хотя бы добавили Генерики, было бы намного проще:
class AbstractRepository<T> 
{
    public function find($id): ?T
    {
        ...
    }
    ....
}


Так было бы намного удобнее это сделать (к примеру так сделано в Hack);
Немного объяснений:
У вас есть ваша любимая ORM'ка (к примеру Doctrine), у которой есть AbstractRepository, который используется как репозиторий по умолчанию, и также вы от него можете насследоваться. У этого AbstractRepository есть метод find, который возвращает нам объект Entity. Представим, что все Entity реализуют интерфейс EntityInterface, тогда наш AbstractRepository будет иметь вид:
class AbstractRepository 
{
    public function find($id): EntityInterface
    {
        ...
    }
    ....
}

Вроде все правильно, find действительно возвращает EntityInterface, но если мы будем использовать его для определенной Entity, к примеру User, мы не сможем при наследовании переопределить тип возвращаемого значения как User, то-есть такой код приведет к Fatal Error:
class UserRepository extends AbstractRepository 
{
    public function find($id): User
    {
        ...
    }
    ....
}

То-есть нет сужения/расширения классов, возьмем к примеру Java:
public interface A {
    public A create();
}
...
public class HelloWorld implements A
{
     public static void main(String []args){
        HelloWorld a = new HelloWorld();
        a.create();
     }
     
     public HelloWorld create() {
         return this;
     }
}

Такой код является валидным, так как он не противоречит условию.
В вашем примере есть еще одна проблема — make всегда должен возвращать B. То есть тот же пример с find у абстрактного репозитория с
nullable types в draft-е лежит уже, без него смысла лепить это дело на методы типа find сами понимаете мало. В целом же пример с абстрактным репозиториями я лично считаю надуманным.
Имхо — подобный драфт не совсем практичный, намного удобнее было бы унифицировать аргументы для получения нескольких значений, например вот таким образом:
public function some(SplFixedArray|null $any) 
{
}

Это позволит не только определять аргумент, как nullable, но и указывать несколько типов аргументов. Хотя вариант с перегрузкой был бы всё же красивее…
ну во первых подобный синтаксис есть и в java и в c# и используется оно по прямому назначению, разрешает использование null как значение. ваш вариант кроме того что выглядит ужасно, так ещё и убивает весь смысл тайпхинтинга. Если ваши методы/функции работают с разными типами то и тайпхинтинг вам не нужен.
Так реализовано в TypeScript — по-моему это лучший вариант при наличии типизации в аргументах, но отсутствия перегрузки. Хотя с другой стороны может вы и правы и вполне достаточно хинтинга в автодоках для подсветки и разруливания типов в иде.
не имеет смысла при крайней нестрогой типизации php, имхо…
Я бы сказал не «крайне нестрогой», а «опциональной». Т.к. при желании можно писать почти так же, как на джаве (используя строгие spl-типы, например).
Кстати на счёт «крайней нестрогости». Вот такое будет работать везде:
Пример (Чур в обморок не падать)
<?php
$i = int(23.0);
$f = float("asdasdasd");
 
class Test
{
    public static function printInt(int $i)
    {
        echo $i . "\n";
    }
 
    public static function printFloat(float $i)
    {
        echo $i . "\n";
    }
}
 
 
Test::printInt($i); // 23
Test::printFloat($f); // 0.0

А вот реализация
<?php
abstract class number
{
    protected $value;
    public function __construct($val)
    {
        $this->value = $val;
    }
 
    public function __toString() { return (string)$this->value; }
}
 
class int extends number
{
    public function __construct($v) { parent::__construct((int)$v); }
}
class float extends number
{
    public function __construct($v) { parent::__construct((float)$v); }
}
 
function int($v) { return new int($v); }
 
function float($v) { return new float($v); }

Все бы было круто, если бы

echo $i + $f;


или
if ($f)
{
	echo $f;
}


после этого работало) А так бесполезно…
Скорее эту примут, чем драфт 3-х летней давности.
По-моему эти rfc несколько разной направленности.

По моей ссылке позволяет нормально приводить объекты к другим типам, как следствие:
1) позволяет обходить такие проверки, как is_array при реализации объекта с интерфейсами ArrayAccess и проч.
2) позволяет выполнять математические операции, какое-нибудь сложение специфичных объектов, например векторов (Vector2), хотя с этим придётся помучаться, т.к. получение слагаемых вроде бы не предусмотрено
3) и уже в последний момент для подобной откровенной издёвки над языком, как я привёл выше, в качестве реализации строгой типизации

По вашей же ссылке — вполне очевидный рфц, добавляющий типы для скаляров (за исключением массива, т.к. он уже есть) и предназначенный только для этого. Т.е. перспектива очевидна и «унитарна», если так можно выразиться.
По моей ссылке, вменяемый свежий RFC решающий конкретные проблемы. Возможность же каста объектов в скаляры штука весьма неудобная и создает почву для говнокода. Все эти эмуляции перегрузки операторов вообще не нужны ни разу. Эмулировать что-то таким способом тоже не очень то удобно и уж темболее я не хочу увидеть такой код (ваш пример с реализацией тайпхинтинга для скаляров на базе этой штуки) у себя в продакшене.
> В вашем примере есть еще одна проблема — make всегда должен возвращать B.

Это не проблема, особенно если вспомнить что type hinting в такой ситуации прекрасно умеет проверять цепочку наследования и выбрасывать E_RECOVERABLE_ERROR.
я про то что метод find может вернуть null, а в текущем варианте при использовании тайпхинтинга — не может. Потому пример предложенный на java в php пока реализовать не удастся.
Аббревиатура LSP вам о чем-нибудь говорит?
Постусловия не могут быть ослаблены в подклассе.

Вроде всё пучком. В приведённых примерах постусловие усиливается.
Если всегда в возвращаемом значении ожидается instanceof A, то все пучком, но тогда и нет смысла в таком переопределении.
Аббревиатура LSP вам о чем-нибудь говорит?

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

ИМХО, проблема скалярных типов не в возвращаемом значении, а в отсутствии методов

__toBool
__toInt
__toFloat

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

$a = new Bool;
if ($a)


Приговор «код, который я написал 10 лет назад, по-прежнему должен запускаться сегодня и должна быть возможность выполнить его через 10 лет»

Вроде за 10 лет была куча изменений, которые ломали обратную совместимость — хотя бы, выводили NOTICE или WARNING, что уже половину сайтов делало не работоспособными.

github.com/php/php-src/pull/998 — я расчитываю на то что в 7.0 это дело все же войдет.
Может вы знаете, есть какой-нибудь простой способ собрать php с этим делом?
Вариант Nikic, с преобразованием примитивов в полноценные объекты, мне больше нравится. Такм образом можно будет убрать бардак с именнами и аргументами стандартных функций в PHP, и как бонус заработает TypeHinting для «примитивов».
А еще это добавит изрядно оверхэда ибо вместо хранения одного жалкого int у нас в памяти будет жирная структура. А там и накладные расходы и т.д. Либо же надо изрядно переделывать парсер что бы тот трансформировал это добро в нормальные конструкции.

Имхо превращать все в объекты это не сильно практично. Ну и проблемы тайпхинтинга для содержимого массивов это никак не решает. Как по мне так уж лучше на Hack перейти за всем этим добром.
— int, string и т.д. как примитивы явно останутся, ибо совместимость.
— phpng уменьшит размеры структур.
— другой альтернативы исправить php api, я не вижу.
— type hinting заработает бонусом.

С массивами сложнее… в php вообще с колекциями плохо, даже в spl.

А к Hack я уже давно присматриваюсь. Останавливает только отсутствие поддержки нативных php расширений, а переписывать не хочется.
Можете первый пункт раскрыть? Если я правильно понимаю, в этом случае нужно править синтаксис языка, причем не слабо.

В интерналс сейчас идет обсуждение единого API для расширений под HHVM и PHP. Правда думаю долго еще ждать и не факт что что-то такое вообще будет. Я стараюсь реже использовать какие-то кастомные расширения как раз таки для того что бы код был максимально переносим.

другой альтернативы исправить php api, я не вижу.


Предлагаю всё же попробовать заглянуть на светлую сторону jphp ;) Ну например: github.com/jphp-compiler/jphp/blob/master/jphp-runtime/src/main/resources/JPHP-INF/sdk/php/lib/str.php
> не будет возможности вернуть скалярные значения, такие как string, int, bool и др.

Учитывая что они свободно конвертируются друг в друга это не особо печально.

> нельзя будет определить возврат нескольких типов.

Есть языки где это возможно?

> Некоторые люди также жаловались на объявления типа после закрывающей скобки списка аргументов, а не перед именем функции, но для меня это придирки. Популярные языки, такие как современный C++, используют “пост”-синтаксис, при этом сохраняется возможность поиска «function foo» без какой-либо необходимости прибегать к regex-модификациям.

Несколько странно видеть сравнение с с++, разве java/c# не ближе? «Поиск» вообще не актуален, IDE давным-давно решили данную проблему. ИМХО, префиксная запись гораздо читабельнее, особенно при большом количестве аргументов.

> Понятно, сломанная совместимость всегда огорчит некоторых людей

Тони похоже просто говнокодер, конструкторы совпадающие с именем класса во всех книгах/статьях не рекомендованы к использованию еще со времен перехода с 4.0 на 5.0, поэтому в нормальном коде эта проблема не может существовать в принципе. Буду рад если выпилят (большая часть остального тоже давным давным устарела).

> Как вы относитесь PHP7 в целом?

Раз уз добавляют указание возвращаемого типа, то пусть и properties сразу добавят (возня с магией уже порядком надоела) и перегрузку методов до кучи (вот это будет по настоящему круто).
> нельзя будет определить возврат нескольких типов.

Есть языки где это возможно?

Swift?

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}
А это разве не кортеж? (структура/массив)
возврат нескольких переменнных это другое.
>Учитывая что они свободно конвертируются друг в друга это не особо печально.

Какая вообще связь?

>Есть языки где это возможно?

В PHP есть возможность возвращать значение разных типов, но указать этого нельзя.
Оно не особо нужно из-за конвертации: сейчас по сути все равно что возвращает метод 0, false, null или еще что-то приводящееся к false. Если же вам это критично всегда можно явно привести тип. Да и опять же — скалярного type hinting все равно нету, добавлять так все вместе.
Ну, если мы идём по пути увеличения строгости, то уже должно быть важно, 0 или NULL.
в текущей RFC тайпхинтинга для скаляров всеравно нету ничего для проверки содержимого массивов… грусть печаль.
Есть языки где это возможно?

Typescript же!
Долго не мог понять это место «возвращаемыми могут быть лишь те типы, которые есть на данный момент» и почему это типов int и bool на данный момент нету.
ИМХО надо пояснение, что речь идет о типах, которые можно было использовать в type hinting аргументов ф-ий.
Еще есть интересный rfc про дефолтные конструкторы для объектов. Вещь далеко не критичная, но удобная например при написании юнит тестов. Увы проголосовали 50/50, но так как это изменение на уровне языка, то требуется 2/3+1 голос для принятия.
А можете пояснить, в чем удобство для написания юнит тестов?
В моей практике постоянно нужно следить существует или нет конструктор создаваемого объекта, чтобы его замокать. Но не удивлюсь, что в phpunit это уже давно решили какой-нибудь проверкой на существование конструктора (буду честен — не проверял).
Также есть удобство в написании конструкторов дочерних классов (это был кстати основной аргумент автора rfc), когда можно было бы всегда смело писать parent::__construct() независимо от того, есть он или нет.
Целиком и полностью за избавление от пережитков PHP4 — лучше переделать свое приложение, чем опять тащить кучу ненужного барахла в новую версию. Насчет типизации возвращаемых функцией значений. ИМХО зачем делать еще одну Java или Ruby? Или с этой фичей говнокод сразу станет конфеткой? Выбросить балласт — очень правильное решение. Наворачивать избыточный функционал — ИМХО нет.
Почему вы считаете что этот функционал избыточен? В любом случае право использовать тайпхинтинг или нет — ваше право.
Насчет типизации возвращаемых функцией значений. ИМХО зачем делать еще одну Java или Ruby?

Ruby? Вы уверены? Никогда не видел в Ruby type hinting, тем более возвращаемых значений.
Тони в «Не ломайте наш язык» прав в том смысле, что большинство core девелоперов не имеют достаточного опыта (и популярный Никита Попов — туда же). Тенденция в PHP — ломать работающее — не может не настораживать. Не вижу ничего плохого в том, что сам язык обратно совместим с собой же. По своему небольшому хостингу (~50 клиентов) могу сказать, что замены версий PHP и без намеренного слома очень болезненны (то, что задело — HTTP_xxx_VARS, ereg_xxx). После окончательного слома конструкторов может навернуться масса легаси софта (в т.ч. и покупного).

Еще «замечательно» то, что команда, ломая совместимость, абсолютно плюёт на разработчиков. Так, не припомню ни одного анализатора кода на выявление в коде отломанной функциональности. Стоило бы вменять в обязанности делать такие анализаторы тем, кто голосует за удаление — при принятии такого решения.

Обратная совместимость — это огромная сила. И все исторические примеры это только подтверждают (тот же Python 2/3 — который приходится держать обе версии, Windows 8). И где был бы сейчас C++, если бы не его совместимость с C? Думаю, там же, где и всякие PL/I, COBOL, etc — на свалке истории.
Может быть объясните, но я не понимаю зачем заставлять древний код работать под новым интерпретатором? А вообще советую посмотреть на C#, один из наиболее быстро и часто обновляющихся языков, и никто не ноет.
Объясняю — команда позиционирует его как замену текущей ветки 5.x. Соответственно поддерживать 5.х бросят, а сам интерпретатор _очень_ дырявый с точки зрения безопасности. Соответственно минимум хостинги встают перед дилеммой — обеспечивать безопасность или сохранять совместимость.

По своим клиентам — у меня есть код, написанный более 14 лет назад (для интерпретатора 4.0). И он до сих пор работает. Я не вижу ни единой причины, чтобы перетряхивать его бесплатно. С точки зрения клиентов доп.затраты на его обновления — аналогично, бессмысленны. Так что команда PHP такими жестами перекладывает свою работу на разработчиков.

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

Никто, собственно, не ноет, проблем нет уйти в новых разработках на что-то более стабильно относящееся к обратной совместимости. И с потерей «старой гвардии» язык рискует просто уйти в тень — как то потихоньку происходит с Perl (крайне неудачная история развития). С python слабо знаком — но подозреваю, популярность они себе сами подорвали выкрутасом с миграцией 2.х -> 3.x

Насчет C# — там действительно всё так же печально с обратной совместимостью? Насколько я могу видеть, .NET 2 вышла в 2005, конец поддержки Microsoft обещает на 2016 год. Немного расходится с поддержкой PHP, правда?
Статью попозже постараюсь почитать, но выход вы вовсе не там ищите — не нужно всех заставлять пользоваться старыми кривыми костылями, поддержка которых к тому же тормозит эволюционное развитие (приходится тратить время на обновление этого кода). Вместо этого, как вы сами сказали, нужна версия с длительной поддержкой в которой будут фиксы безопасности (или что-то совсем критичное). Поэтому просить стоит именно об этом, а не о мифической обратной совместимости.
В рамках текущей модели развития языка это (поддерживание старых фич) единственное, что можно сделать. Безусловно, если был бы вариант перейти на LTS — по меньшей мере виртуальные хостинги так бы и сделали.

И (сейчас меня заминусят) вот я чего чисто психологически не понимаю — вроде ж все не дети, а у многих (и в команде PHP, и здесь) кипит типичный юношеский максимализм в обсуждении «старое vs новое». Новая версия — значит всё резать! И (сугубое imho) комплексы неполноценности языка — когда в язык некритично тащат всё подряд.

В плане совместимости мне очень нравится здравый консерватизм FreeBSD, когда поверх базы создаются слои совместимости (и их можно как включить, так и выключить). В PHP почему-то старые возможности необратимо режутся. С расширением ereg например нехорошо получилось — вполне можно было его убрать из базы в PECL (как например сделали для dbase). Мой код например именно его использовал (т.к. в 2000-2001 в документации писалось, что preg тормознее).

Подытоживая, пока у текущей команды PHP такой настрой, как мне кажется, ни о какой LTS ветке речи быть не может. И статья Тони (отражающая мнение части PHP-пользователей) — глас вопиющего в пустыне. Сложность саппорта LTS выше, чем саппорта в текущем коде отдельных «устаревших фич».
Спасибо за информацию, не знал. Оно в комплекте Zend Server, цены только не радуют — shop.zend.com/en/production-solutions.html (хотят $185 в месяц за минимальный Small Business).
Либо 2200 в год либо намного больше на миграцию кода. Как по мне если речь идет о проекте, который использует код 10+ летней давности и переписывать его дорого, вполне приемлемая цена.

Можно постараться интегрировать возможности предоставляемые платформой и тогда будет не только LTS но еще и плюшки.
Я думаю, вопрос приемлемости цены — это не тот вопрос, который решает разработчик/сисадмин? Для небольшого хостинга например ценник неподъемный.
А причем тут небольшие хостинги? Это не их проблема. Это проблема разработчика/клиента, которому можно предоставить VPS а Zend Server пусть он покупает.

Я вообще вот честно слабо представляю себе системы написанные на PHP4, которые проблемно перевести на PHP5.6. Только в случаях использования каких-то специфичных экстеншенов.
Всё верно. Все фичи пятерки должны жить.
Но речь идет про функционал четверки. Если вы не хотите переносить код с четверки на семерку, то… не переносите. Пользуйтесь четверкой.
Не хотите пользоваться четверкой? Почему вы считаете что разработчики пхп должны поддерживать ДАВНО устаревший функционал? Вам сложно написать десять строчек кода, чтобы пройтись по своему коду в поисках устаревшего кода?
Очень логично было, что этот функционал был сохранен в 5.1. Логичен он был и в 5.2.
Но лично я был сильно удивлен сегодня, прочитав что он еще живой. Я думал, что он умер уже в 5.3.

И да, я чрезмерный консерватор. И да, у меня есть некоторый код, который после небольшого рефакторинга перешел из Бейсика в Паскаль, а потом в пхп4, и сейчас живет в пхп5.4., и да, я вот прямо сейчас испытываю небольшие трудности с переносом старого фреймворка с 5.1 на 5.4. (обидно, что это происходит в рамках плавного отказа от того фреймворка и переноса на другой). Но сохранять такие мелочи как конструктор с именем класса… Увольте.

ПостСкриптум: Еще хотелось бы услышать реальных примеров того как такой код вообще мог дожить до времен 5.4… В четверке классы были очень проблемными, и пользовались ими мало. После этого было много серьезных изменений которые требовали хоть какого-то рефакторинга. Нет, я сам разгильдяй, и очень часто игнорирую нотисы с депрекейтами. Но не до такой же степени…
ПостПостСкриптум: Если кого-то обидел, то простите, я случайно. Жена рожает, я немного нервный :) Так что резкость оборотов делите на два)
Речь не об этом. У меня есть большое купленное приложение на PHP 4, благополучно функционирует на 4.4.9 (внутри ВМ), меня это устраивает. Клиент (муниципальное учреждение) не может себе позволить купить апгрейд за 40т.р. и потратить неизвестный объем времени/денег на перенос данных.

Из встреченных примеров — сайт другого муниципального учреждения, сделанный в 2011 году (по гос. конкурсу за бешеные деньги), внутри объектный, конструкторы все «старые». По инспекции кода — база CMS писалась человеком в 2001-2002 году, сам автор успешно отчалил в штаты, веб-студия до тех пор (минимум до 11 года) использовала старые наработки (ну работает же — не трожь). Собственно, сайт (а он там не такой) будет держать виртуальный хостинг на 5.х еще много времени. Собственно, вот — плач Ярославны месячной давности, прямой результат политики команды PHP.

Речь собственно о стратегии (отсутствующей) развития языка. Когда базовая функциональность может внезапно быть объявленной устаревшей и выкинута. Речь о правилах и принципах, которые обязаны соблюдать даже лидеры проекта.

В любом проекте накапливается рутина, которую всё равно надо делать. Обеспечение обратной совместимости, поддержка кода — это да, ни разу не фан. Но это нужно делать, это нужно финансировать (временем разработчиков и/или деньгами). Иначе большой продукт не будет отличаться от студенческой поделки ничем.

Мне тоже очень нравятся новинки языка (не все), и здорово, что оно обновляется и расширяется. Но как системный администратор, я не могу рисковать сайтами клиентов — в том числе и из-за логов изменений языка. И из-за этого сайты, требующие 5.4 и выше — вынуждены покупать более дорогие виртуалки, хотя в остальном нужды в них нет.
Проблематика понятна — нет денег чтобы сделать как положено, поэтому пусть за них потратят деньги другие люди, или «в тендере выиграли люди которые использовали депрекейтет функционал даже когда он был уже депрекейтет — разработчики языка за них в ответе!».
Я их прекрасно понимаю. У самого есть такие ситуации/клиенты. Но!
Есть общепринятая практика — обратная совместимость сохраняется в рамках последней цифры, частично сохраняется в рамках средней цифры и не сохраняется в рамках первой.
Если бы эти конструкторы выкинули в 5.2, то я бы вас понял. А так… Давайте еще требовать совместимости с пхп3, ведь у кого-то еще может есть код времен пхп3?
Если ваш код под 4.0 работает на 5.4+ без правок, видимо, там вообще чистая процедурщина, иначе бы одни амперсанды в аргументах замучались удалять (именно по этой причине у меня, кстати, крутится 5.3 на сервере со старьем). А с процедурщиной вроде бы ничего и не ломают сильно: ереги просто выносятся в pecl-расширение, а уж HTTP_VARS вообще не проблема — добавить три строчки в auto_prepend_file да и всё.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации