Язык php часто ругают, обычно необоснованно. Особенно удивляет, что javascript ругают меньше. Зачастую это делают люди, которые писали на нем 10+ лет назад, когда язык был действительно чертовски плох, да и разработчики в те времена не задумывались над качеством кода. Посмотрите хотя бы на код wordpress, который до сих пор вызывает шок.


Ругают необоснованно, но проблемы у языка, конечно же, есть, и они серьёзные. Разуметеся, если сравнить последние релизы php7 (с нормальным ООП и строгим тайпхинтингом) и php4, то разница будет колоссальная. Однако и в последних версиях языка не всё гладко, и до java/c# пока что очень далеко. Более того, берусь утверждать, что будущее php тоже довольно сомнительно (с точки зрения типов).


Другими словами, давайте рассмотрим предметно, что хорошо и что плохо в php с точки зрения типизации.


Тайп хинтинги


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


Немного отвлечемся и посмотрим кусок кода на javascript:


function filterUsersByAge(users, age) {
    // тут какой-то код
}

Что мы можем сказать об этой функции? Она берет каких-то пользователей и фильтрует их по возрасту. Но этого мало, потому что сразу возникают вопросы:


Что такое users? Массив? Или какой-то хитрый объект-коллекция?
Возраст задан как целое число или может быть дробным?
Может ли возраст быть null?
Возвращает ли эта фунция значение или же меняет переданный массив users?


Чтобы всё это понять, надо прочесть код функции, а также вызовы этой функции. Ошибки будет отловить сложно, потому что язык не будет ругаться ни на какие аргументы, а будет пытаться их как-то привести к нужному типу.


Как известно, программист тратит больше времени на чтение и понимание кода, чем на написание нового, поэтому отстутствие подсказок в коде является затармаживающим фактором.


Для сравнения код на последних версиях php:


function filterUsersByAge(array $users, ?int $age) : array {
   // ...
} 

Тут мы видим, что на входе массив пользователей, возраст может быть null, возвращается также массив. Гораздо яснее, не так ли? Если же в нужных местах указать declare(strict_types=1), то при попытке пихнуть дробное число в качестве возраста, мы получим ошибку.


Вроде всё супер, но есть нюансы.


Нет дженериков


Мы смотрим на эту php-функцию filterUsersByAge и сходу не понимаем, массив чего нам пришел. Что именно за array? В java можно было бы написать List<User>, и мы бы понимали, что к нам пришел список объектов User. Или Set<User>, и мы бы сразу видели, что это список без повторов, т.е. только разные объекты. (Вообще, array в php — это странноватая смесь массива и HashMap, но это тема для отдельной статьи)


Нет уточнений для типа callable.


Вот пример функции:


function reduce ( array $array, callable $callback )

Что за функция идет вторым аргументом? Что в ней должно быть?


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


В некоторых языках, например в TypeScript, можно прописать прямо в объявлении функции:


function fn(action: (a: string, b: number) => void)

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


Странности тайпхинтинга и типа возврата в связке с наследованием


<?php

interface Entity {}

class User implements Entity {}

abstract class Repository {
    abstract public function findById(): Entity;
}

class UserRepository extends Repository {
    function findById(): User {
        return new User();
    }
}

Здесь получаем ошибку, что findById не совместим с findById из абстрактного класса.


Такой же пример в java нормально компилируется:


interface Entity {}

class User implements Entity {};

abstract class Repository {
    abstract public Entity findById();
}

class UserRepository extends Repository {
    public User findById(){
        return new User();
    }
}

в TypeScript тоже можно:


interface Entity {}

class User implements Entity {}

abstract class Repository {
    public abstract findById(): Entity;
}

class UserRepository extends Repository {
    public findById(): User{
        return new User();
    }
}

На это дело время от времени появляются баг репорты, возможно будет исправлено когда-нибудь:



Фатальная проблема


Самая большая проблема в том, что php проверяет типы во время выполнения, а не во время компиляции. Потому что, не смотря на strict_types и type hintings, это ВНЕЗАПНО не строго типизированный язык


Отсюда следует два вывода:


1) Чем больше проверок в рантайме, тем больше тормозов. Поэтому слишком сложные проверки навряд ли вообще когда-нибудь появятся. Многослойные дженерики и callable с callable аргументами просто положат рантайм. Также будут тормозить рантайм введение типов для членов класса и в других местах.


2) Ошибки выявляются только во время запуска. Т.е. всегда будут ситуации, когда в какой-то хитрой ситуации пользователь сделает что-то не предусмотренное тестами, и всё повалится


Вместо выводов


Хотя (с точки зрения типов и ООП) на мой взгляд php на голову выше, чем javascript, и подходит для написания сложных программ, но при этом, конечно, не дотягивает до java/c#/typescript, и навряд ли когда-нибудь дотянется (см "Фатальная проблема"). Повторюсь, не дотянется именно с точки зрения системы типов, в остальных вещах возможны предпочтения в ту или иную сторону.


Поэтому в по-настоящему сложных приложениях надо обязательно всё обкладывать тестами. Также, возможно, что phpdoc добавит поддержку сложных callable с параметрами, и IDE научатся их понимать.

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


  1. AlexLeonov
    18.01.2018 13:01
    -1

    проблемы у языка, конечно же, есть, и они серьёзные

    до java/c# пока что очень далеко

    ВНЕЗАПНО не строго типизированный язык

    конечно, не дотягивает до java/c#/typescript


    Антон, так пишите на Java или C#, кто же вам запрещает-то?

    Статья — прекрасный образец самой настоящей демагогии.

    Берем язык А, в котором нет фичи b, поскольку она не нужна или реализована иначе.
    Берем язык B, в котором фича b в наличии
    Намеренно опускаем момент, что это принципиально разные языки и сравниваем килограмм с километром, делая вывод, что «А не дотягивает до B»

    Я никогда не понимал — как можно быть «руководителем отдела разработки» на языке, который тебе так не нравится? Расскажите, Антон, пожалуйста, как вы планерки проводите?

    Примерно так: «Парни, начинается новая неделя и нам всем снова предстоит писать код на этом ненавистном PHP, будь бы он неладен… Когда же это кончится уже?»


    1. varanio Автор
      18.01.2018 13:03
      -1

      Я же написал: «Повторюсь, не дотянется именно с точки зрения системы типов, в остальных вещах возможны предпочтения в ту или иную сторону.»


      1. AlexLeonov
        18.01.2018 13:05

        А нужно дотягиваться?
        Зачем вообще принципиально слаботипизированному языку с динамической «рантайм» системой типов дотягиваться до языков со статической типизацией?
        Кто такую цель поставил для PHP? Вы?


        1. varanio Автор
          18.01.2018 13:07
          -1

          Ну php же явно идет в эту сторону. Type hinting-и усложняются с каждой версией. strict_types и т.д. Но в то же время у этого процесса есть ограничения, потолок возможностей, что я и показал в этой статье. Просто это не всем очевидно.


          1. AlexLeonov
            18.01.2018 13:10

            Я не уверен, что вы верно понимаете, в какую сторону идет PHP. И более того — не уверен, что цель этого движения именно «строгая типизация» в вашем понимании.


            1. sam002
              18.01.2018 13:57

              Цель-то достаточно очевидная у нынешних владельцев zend — отжимать рынок у java/c#/typescript. Это предопределяет кучу стратегических решений по развитию языка. Так что не зарекайтесь от «строгой типизации».
              Вполне допустимо повторение ошибок, подобных php6. Тогда всё исходило из идеи что в java же utf-16, значит и в php надо.
              К большому сожалению само ядро php имеет относительно слабое комьюнити и ограниченные ресурсы. Плохая сторона — зависимость от zend с плохо продуманной стратегией, хорошая — очень тщательно выбираемые изменения не ломающие BC каждые пять лет и дающие максимальный профит тактически.


        1. varanio Автор
          18.01.2018 13:08

          Не надо так агриться на статью, я не хотел никого обижать )


          1. AlexLeonov
            18.01.2018 13:11

            Я бы не «агрился» так, если бы не очевидный вред от таких статей.

            Вы своё собственное несовпадение «идеального языка» и реального PHP почему-то считаете проблемой последнего. Да еще и называете «фатальным недостатком»

            Если бы не подобная тональность статьи — никаких отрицательных эмоций в вашу сторону не было бы.


            1. varanio Автор
              18.01.2018 13:21
              +1

              Какая тональность? В какой фразе? Система типов хуже, чем у java — ну извините, это медицинский факт, а не тональность.
              Кроме этого факта я ничего плохого про php не сказал. Более того, я на нем сам пишу.
              О проблемах надо говорить, а не замалчивать. Тогда возможно появятся какие-то решения. К примеру для javascript появился typescript. Чем не решение? И строгие типы, и возможность использоваь либы на ванильном Js


              1. AlexLeonov
                18.01.2018 13:32

                Можно я чуть-чуть «сагрюсь» еще? Ну совсем немножко?

                Система типов хуже, чем у java — ну извините, это медицинский факт, а не тональность.

                Вот здесь у вас фатальная ошибка и недостаток. У вас, а не в PHP. Ошибка в том, что вы пытаетесь личное субъективное выдать за объективное сравнение несравнимых величин. Пресловутые «килограмм» с «километром»

                Система типов в PHP не «хуже» или «лучше» — она другая. Она построена на иных принципах и решает иные задачи, нежели в Java.

                Не понимаете? А как вы тогда руководите разработкой?
                Впрочем, этот вопрос я вам уже задавал, ответа не последовало.


                1. varanio Автор
                  18.01.2018 13:35

                  Не могли бы вы мне объяснить, какие именно задачи решает система типов в php? Чтобы я мог лучше руководить разработкой? А может и вообще стёр вредную статью?


                  1. AlexLeonov
                    18.01.2018 13:40

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

                    Но если совсем коротко, то успешно решаемые задачи в PHP стоит свести к нескольким важнейшим пунктам:
                    — автоматический динамический кастинг скалярных типов
                    — реализация понятия «практической эквивалентности»
                    — стандартизация всех i/o хэндлеров в едином типе resource
                    — решение всех проблем, которые возникают в других языках с динамическими массивами
                    — реализация класс-ориентированного подхода
                    — контроль типов времени исполнения
                    — контроль типов времени компиляции

                    Постарался расположить по степени важности


                    1. varanio Автор
                      18.01.2018 14:36

                      — автоматический динамический кастинг скалярных типов

                      Да, когда-то целью php это было. Но ввели declare(strict_types=1). Это для чего?
                      По-моему чтобы избавиться от неявного, разве нет?

                      — реализация понятия «практической эквивалентности»

                      Не могли бы вы пояснить?

                      — решение всех проблем, которые возникают в других языках с динамическими массивами

                      Каких проблем?

                      — контроль типов времени компиляции

                      в php почти нет этого


                      1. AlexLeonov
                        18.01.2018 14:40

                        Да, когда-то целью php это было. Но ввели declare(strict_types=1). Это для чего?
                        По-моему чтобы избавиться от неявного, разве нет?

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

                        Причем тут ваши фантазии о «явном» и «неявном» — я не знаю.

                        И не надо, пожалуйста, рассказывать о «целях PHP». В вашем исполнении это звучит как минимум странно.


                        1. varanio Автор
                          18.01.2018 15:13

                          Причем тут ваши фантазии о «явном» и «неявном» — я не знаю.

                          Я про неявное приведение типов.

                          function myFunc(int $val) {
                             print $val;
                          }
                          
                          myFunc("1.99999999");


                          выдаст единицу. Молча, неявно преобразовав тип.

                          с decrlare(strict_types=1) придется явно написать

                          myFunc((int) "1.99999999");
                          


                          иначе будет выдана ошибка. Вот про это явное указание (int) я и говорил.

                          И не надо, пожалуйста, рассказывать о «целях PHP». В вашем исполнении это звучит как минимум странно.


                          Почему в моем исполнении странно? Может именно в вашем странно?
                          Я просто высказываю свое мнение, наблюдая за changelog ом языка.


                          1. AlexLeonov
                            18.01.2018 15:16

                            выдаст единицу. Молча, неявно преобразовав тип.


                            Как же «неявно», если вы сами написали «int»? Что тут неявного?


                            1. poxvuibr
                              19.01.2018 08:51
                              +1

                              Как же «неявно», если вы сами написали «int»? Что тут неявного?

                              Ну вот так, неявно. Если функция принимает int, ей передают строку и эта строка автоматом преобразуется в int — это назвается неявным преобразованием.


                              Явное преобразование — это когда программст, когда передаёт параметр сам пишет, что его надо преобразовать в int.


                              1. varanio Автор
                                19.01.2018 08:53

                                Вот да, достаточно просто погуглить по фразе «неявное преобразование типов»


                      1. AlexLeonov
                        18.01.2018 14:41

                        Практическая эквивалентность это
                        1 == '1' == true
                        0 == '0' == '' == false == []

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

                        На практике же такая эквивалентность необходима просто в силу того, что так устроен HTTP и CLI.


                        1. varanio Автор
                          18.01.2018 15:15

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


                          1. AlexLeonov
                            18.01.2018 15:19

                            Однако это сомнительный плюс, если честно.

                            Не пишите на PHP. Он вам не нравится, и, как результат — вы его не понимаете.


                            1. asm0dey
                              18.01.2018 16:53
                              +4

                              Последнее утверждение крайне спорно. Я 9 лет писал на джаве, я думаю что понимаю её глубже чем многие. Но я прям далеко не фанат. И как только появилась внятная альтернатива в лице котлина — с радостью перешёл на него. Не нравится ? не понимаю.


                              1. AlexLeonov
                                18.01.2018 17:58
                                -2

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

                                Изучение же, приводя к пониманию, затем убирает это странное «не нравится». Ну или человек уходит на другую платформу.


                                1. OlegOleg1980
                                  18.01.2018 21:20

                                  Позвольте вас дополнить.
                                  В целом обсуждение сводится к той ситуации, когда есть два напильника — плоский и круглый, и, автор, взяв в руки круглый напильник, рассказывает нам, как же плохо им выравнивать плоскую поверхность — то он соскальзывает, то канавки в поверхности делает, то вообще очень медленно точит! И, говорит, неплохо бы этому круглому напильнику грани сделать — тогда и с плоскими поверхностями намного удобнее будет работать! У автора то уже есть один удобный плоский напильник, тот то хорошо плоскости обрабатывает, значит надо к этому стремиться, сделать все напильники плоскими. Автор просто редко занимается округлыми поверхностями, но в те редкие моменты, когда это все же происходит, он тихим шепотом сыплет проклятия тому, кто ему подсунул эти неплоские поверхности, возможно даже изредка подумывая о круглом напильнике…


                                  1. varanio Автор
                                    18.01.2018 21:25
                                    +1

                                    Если уж на то пошло, то php (personal home page) изначально предназначался для простых сайтиков

                                    Но время шло, сайтики превращались в фейсбуки, и старый напильник перестал подходить

                                    Множество гигантских систем написны на php и страдают от недостатчной строгости язык

                                    Посмотрите современные фреймворки.


                                    1. OlegOleg1980
                                      18.01.2018 21:43

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


                                      1. varanio Автор
                                        19.01.2018 10:18

                                        Блин.
                                        Расскажите мне, какие аргументы приводить начальству, чтобы уговорить их потратить пару человеколет на то, чтобы переписать всё на другой язык?

                                        Напильники, фигильники. Многие компании в заложниках у тех технологий, на которых они построены. И зачастую это навсегда.

                                        Т.е. выбора-то нет на самом деле.


                                        1. VolCh
                                          19.01.2018 14:57

                                          Потратить на портирование пару человеко-лет ещё можно как-то убедить, но вот убедить, что на несколько месяцев развитие текущего проекта остановится точно нельзя.


                                      1. VolCh
                                        19.01.2018 14:56

                                        Аналогия с напильником не очень хорошая. Напильником сделал продукт и больше он от напильника не зависит. Следующий продукт можно делать другим напильником, более подходящим под него. Единственное препятствие — новый напильник очень дорогой и денег на него нет, тогда модернизируем старый.


                            1. varanio Автор
                              18.01.2018 17:11
                              +3

                              Чего я там не понимаю? На php пишу 100500 лет.

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


                              1. AlexLeonov
                                18.01.2018 18:41
                                -3

                                Не понимаете главного — зачем этот язык. От непонимания идет нежелание его изучать. От нежелания изучать — недостаток знания и понимания.

                                Замкнутый круг.

                                Попробуйте ответить на самый простой вопрос для самых-самых начинающих — а зачем вообще в PHP
                                empty('0') === true;
                                ?
                                Какой практический смысл в таком?

                                С точки зрения любого не-PHP программера ересь же. Непустая строка пустая?


                                1. Crandel
                                  18.01.2018 19:14

                                  Так в чем же цель php?


                                1. varanio Автор
                                  18.01.2018 20:47

                                  empty($x) — это фактически сокращенная запись ( isset($x) && $x == false)
                                  А '0' в php — это false

                                  Это не то, чтобы ересь, просто нейминг немного путает людей


                                  1. WebSpider
                                    18.01.2018 22:05

                                    empty($x) — это фактически сокращенная запись ( isset($x) && $x == false)

                                    Да ну? то есть для несуществующих переменных (isset($x) = false) empty должна вернуть false?


                                    1. varanio Автор
                                      18.01.2018 22:13

                                      Да, ошибся. Я имел в виду !isset($x) || $x == false


                                      1. AlexLeonov
                                        19.01.2018 11:06

                                        Вы не ответили на вопрос «зачем оно так»


                                        1. varanio Автор
                                          19.01.2018 17:46

                                          ну, чтобы меньше кода писать. Вместо двух условий одно


                        1. 0xd34df00d
                          18.01.2018 20:14
                          +2

                          1 == '1' == true

                          Idris> the Int $ cast "1"
                          1 : Int
                          


                          0 == '0' == '' == false == []

                          Но… Зачем? Как HTTP и CLI требуют этого?


                          1. varanio Автор
                            18.01.2018 21:01
                            +1

                            AlexLeonov намекает, что в http-протоколе есть только строки, других типов нет. И удобно брать строки из $_GET и тд и сразу начинать сравнивать и складывать с чем нибудь, не приводя вручную к типу

                            На самом дделе этот аргумент не совсем верен.


                            1. tehSLy
                              18.01.2018 21:06

                              Учитывая, что PHP работает далеко не только с $_GET, $_POST и иже с ними, не уверен в корректности этого аргумента как такового. Но, надо же привести что-то в защиту ?\_(?)_/?


                              1. varanio Автор
                                18.01.2018 21:17

                                В сложных приложениях все равно приходится тщательно валидировать и санитизировать входные данные.
                                Одна ручная операция по преобразованию типа роли бы не сыграла.

                                В сложных приложениях получение данных из GET и POST — вершина айсберга, причем самая простая. Дальше идет бизнес логика и т.д., где цена ошибки слишком высока, и хочется не надеяться слепо, что php как-то сам закастит данные по своим магическим правилам. Делать все явно — вот, что было бы хорошо. Понятный с одного взгляда неизменный тип переменной -это было бы супер. Но увы


                                1. tehSLy
                                  18.01.2018 21:31

                                  И я о том, но ведь «мы просто используем инструмент не по назначению», как тут многие выражаются(С удовольствие использовал бы подходящий инструмент, да вот поди объясни бизнесу, что у них кодовая база не на том написана). Я с Вами во всем солидарен. Времена, когда PHP заходил с его слабой динамической типизацией канули в лету, теперь скорее источник ошибок, нежели полезная фича.


                              1. VolCh
                                18.01.2018 22:37

                                mysql тоже строки возвращает как результаты выборки, независимо от типа в базе. Так что основная причина подобных приведения — именно упрощение разработки в среде, где почтм всё представлено в строках технически, но имеет семантику не только строк, но и чисел, булевых и т. д.


                              1. dekameron
                                19.01.2018 14:45

                                В защиту: для проверки с учётом типа есть ===


                            1. 0xd34df00d
                              18.01.2018 23:43

                              А вручную ничего не надо приводить. Ну вот как тут, в quick start-примере. quiet имеет тип Bool, enthusiasm — вообще Int, и вместе с тем никаких ручных приведений.


                      1. AlexLeonov
                        18.01.2018 14:48

                        Каких проблем?

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

                        Поверьте, не каждый язык это всё умеет.


                        1. varanio Автор
                          18.01.2018 15:16

                          Да, на уровне конструкции языка этого часто нет. Но обычно в этом случае есть в виде стандартной библиотеке.


                        1. JTG
                          19.01.2018 16:52

                          Это всё классно, но

                          $requiredParams = array_slice($params, 0, 9);
                          $baseUrl = Router::createLink('analys', 'index', $requiredParams);

                          Видите ошибку? А она есть.


                    1. 0xd34df00d
                      18.01.2018 20:08

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

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

                      А это хорошо?

                      решение всех проблем, которые возникают в других языках с динамическими массивами

                      Включая статические гарантии не выхода за границы? Или как проблемы-то решаются?


                      1. AlexLeonov
                        19.01.2018 12:25

                        Включая статические гарантии не выхода за границы? Или как проблемы-то решаются?


                        Покажите мне практический пример «выхода за границы» для массивов в PHP — и тогда обсудим вопрос про гарантии.

                        На самом же деле постановка вопроса не имеет смысла, поскольку «массивы» в PHP это не массивы с фиксированным размером элемента и смещением, а что-то вроде hashmap (тоже неверно, но ближе к истине)


                        1. 0xd34df00d
                          19.01.2018 20:40

                          Я сразу написал, что в PHP не особо разбираюсь. Собственно, именно поэтому мне и интересно, как он решает эти проблемы. Если через возврат нулевых-пустых-неопределенных значений, то это, в принципе, решение. Если через утверждение, что «на практике таких проблем не возникает», то это, в принципе, тоже решение, да.

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


                          1. AlexLeonov
                            19.01.2018 20:48

                            Запрос элемента с несуществующим ключом приведет к выбросу предупреждения (можно проигнорировать) и возврату null значения.
                            Но поскольку в языке есть явная конструкция проверки существования элемента — проблема не имеет смысла.


                            1. 0xd34df00d
                              19.01.2018 20:57

                              Хорошее решение, спасибо!


                              А ради интереса, есть языки, где нет проверки существования элемента в массиве или индекса в массиве?


                              1. VolCh
                                21.01.2018 01:15

                                C?


                                1. 0xd34df00d
                                  21.01.2018 22:28

                                  Ну, если не сохранять размер выделенного блока памяти, то да.


                1. hack3p
                  18.01.2018 13:47

                  Если PHP претендует на OOP с SOLID, тогда почему они немогут реализовать нормальное ковариантное наследование как в других языках. Вместо этого зачем-то делают костыли в виде нарушения принципа Лисков. Можно еще ознакомится с этим PR и отношением PHP сообщеситва к таким изменениям.


                  1. AlexLeonov
                    18.01.2018 13:50

                    Можно ссылочку на документацию, где указано, что цель развития PHP — соблюдение принципов SOLID?

                    И не кажется ли вам, что соблюдать эти принципы должен программист, как разумное существо, а не язык, как набор инструментов?

                    Это всё равно что сказать, что нож нарушает уголовный кодекс.


                  1. greatkir
                    18.01.2018 13:58
                    +2

                    Прошу прощения, но искренне не понимаю, где в вашем примере нарушение принцпа Лисков.

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

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


                    1. 0xd34df00d
                      18.01.2018 20:31
                      +1

                      Если бы речь шла о сужении типа, то да, типы в наследуемых классах не соответствовали бы базовому типу, и это было бы нарушением принципа Лисков

                      Нет. Наследование ковариантно по возвращаемым типам и контравариантно по принимаемым.


                      Ковариантность: если у вас в базовом классе Base есть метод, возвращающий некоторый BaseRet, то вы по факту говорите, что объект каждого класса Derived, унаследованного от Base, возвращает из этого метода BaseRet. Если вы в конкретном Derived возвращаете DerivedRet, унаследованный от BaseRet, то вы всё равно возвращаете BaseRet (потому что DerivedRet is-a BaseRet), и все действия, которые клиент вашего метода может сделать с возвращённым ему (по контракту базового класса) BaseRet, он может сделать и с возвращённым из конкретного метода DerivedRet.


                      Если вкратце: возвращаемые типы сужать можно, расширять нельзя.


                      Контравариантность, как подсказывает название, работает в обратную сторону: когда вы объявляете функцию, принимающую DerivedIn, вы говорите, что ваша функция умеет работать со всеми объектами, реализующими так или иначе интерфейс DerivedIn. Если вы теперь в наследнике объявите функцию, принимающую BaseIn, то унаследованный от него DerivedIn она уж точно принять сможет!


                      Если вкратце: принимаемые типы расширять можно, сужать нельзя.


                      1. sergyx
                        19.01.2018 15:45
                        +1

                        Ковариантность: если у вас в базовом классе Base есть метод, возвращающий некоторый BaseRet, то вы по факту говорите, что объект каждого класса Derived, унаследованного от Base, возвращает из этого метода BaseRet. Если вы в конкретном Derived возвращаете DerivedRet, унаследованный от BaseRet, то вы всё равно возвращаете BaseRet (потому что DerivedRet is-a BaseRet), и все действия, которые клиент вашего метода может сделать с возвращённым ему (по контракту базового класса) BaseRet, он может сделать и с возвращённым из конкретного метода DerivedRet.

                        Если вкратце: возвращаемые типы сужать можно, расширять нельзя.

                        Если под расширением типов вы подразумеваете
                        B extends A {...}
                        то разве из первого абзаца не следует прямо противоположное — что возвращаемые типы расширять можно?


                        1. 0xd34df00d
                          19.01.2018 20:51

                          Я имею ввиду теоретико-множественное расширение (где тип, упрощая, это множество принадлежащих ему значений). Множество объектов класса B, очевидно, является подмножеством (и чаще всего собственным) множества объектов класса A.


            1. varanio Автор
              18.01.2018 13:25
              +1

              Вы не представляете, как я радовался declare(strict_types=1). Как ребенок.
              Но потом я внезапно осознал, что в эту сторону большого развития не будет из-за того, что всё проверяется в рантайме. И опечалился.
              Собственно, об этом и статья.


              1. Gemorroj
                18.01.2018 13:37

                Когда будет JIT, вероятно, проблемы рантайма должны будут уменьшится.
                Даже opcache, по словам Дмитрия Стогова уже использует тайпхинтинг для оптимизаций.


              1. Adelf
                18.01.2018 13:47
                +1

                У меня такие же чувства. Но если честно, то первый комментарий абсолютно верен. Нам с вами надо писать на Яве и сишарпе :) там все в разы приятнее. Особенно с типами :)
                А так… я пока тоже пишу на PHP. Мне это приносит больше денег :)


      1. YaRobot
        18.01.2018 13:40

        Меня вполне устраивают типы.
        Есть конечно моменты которые стоит доработать, но их уже предложили и рассматривают.
        К примеру хотят добавить скалярный тип.
        Еще бы хотелось иметь возможность создавать собственный тип.
        (type Test = ...)


        1. AlexLeonov
          18.01.2018 13:41

          Ну да, соглашусь.
          Пожалуй не хватает только конструктора кастомных типов.
          Что-то вроде
          type iterable = array | \Iterator, но в своем коде


    1. VolCh
      18.01.2018 22:50

      Можно любить, признавая недостатки в тех или иных областях. Движения в сторону строгости типизации подтверждает, что слабая типизация создаёт проблемы в некоторых случаях типового по нынешним временам использования PHP, не только по мнению части сообщества, но и по мнению разработчиков самого языка. Пойдёт ли движение дальше в сторону ещё большей строгости, вряд ли кто сейчас скажет наверняка, но исключать, что PHP станет ещё ближе к Java/C# в плане строгости типизации, нельзя.


  1. KirEv
    18.01.2018 14:11

    странная статья, странные предъявы,

    сравнивать типы и ооп в рнр с java, etc… вы серьезно?

    … в рнр много вредных возможностей, например:

    $Obj = new \stdClass;
    $Obj->first = "First";
    $Obj->second = "Second";
    
    $a = "first";
    
    print($Obj->$a);
    
    


    эти вещи добавляют неочевидности, и несколько скриптов в сотни строк каждая из таких конструкций способны голову сломать…

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

    и всякое такое…

    это как автомобили сравнивать… что говно что не говно… говорю, любое авто хорошее, если им по назначению пользоваться и вовремя обслуживать, а не лезть паркетником в гавно\глину и жаловаться «джип с недостатками».


  1. CyberSoft
    18.01.2018 15:57

    1. Особенно удивляет, что javascript ругают меньше

      Откуда вы взяли про больше/меньше? Получается java/c# совсем не ругают?


      По моим ощущениям, ругают одну только джаву (чего только это стоит — как же её не ругать?), и ощущение складывается от того, что эта платформа моя основная сфера деятельности.


    2. релизы php7 (с нормальным ООП и строгим тайпхинтингом)

      Тут надо начать с "какое оно, нормальное ООП?", а вообще, чтобы понять, откуда взялось ООП в PHP, нужно ответить на вопрос для чего он создавался и как потом росла сложность проектов. Отсюда такое развитие



  1. tehSLy
    18.01.2018 20:07
    +3

    Не понимаю, почему все накинулись на автора, еще и с аргументами, аля «пишите на своих джаве, сях и прочем, если не нравится», это сродни «я художник, я так вижу». Но тут-то все-таки комьюнити не гуманитарное, думается мне.

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

    2 моих последних проекта на PHP, это мой основной рабочий язык, он неплохой, он очень простой, в этом его плюс и минус. И если это плюс на старте, то чем дальше в лес, тем больше понимаешь, какой же он в некоторых моментах уродливый и как же не хватает тех фич `b` из тех самых других языков. Я не говорю, что PHP плохой язык, упаси боже, у него действительно свои цели и своя ниша, в которой он чертовски неплох. Но давайте будем честны, как только он делает хоть шаг за границы возможного, он мгновенно теряет весь свой шик перед упомянутыми «тру-языками». #nohate


  1. 0xd34df00d
    18.01.2018 20:32

    Самая большая проблема в том, что php проверяет типы во время выполнения, а не во время компиляции. Потому что, не смотря на strict_types и type hintings, это ВНЕЗАПНО не строго типизированный язык

    Строгость типизации и статичность/динамичность типизации — это два разных измерения.


    1. Corpsee
      19.01.2018 04:43

      Он имел в виду статическую типизацию, по контексту. Их почему-то все путают, Python-у вон никто не мешает иметь динамическую строгую типизацию, а C статическую слабую)


      1. varanio Автор
        19.01.2018 08:54

        в php и не статическая, и не строгая


        1. Corpsee
          19.01.2018 16:59

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


          1. 0xd34df00d
            19.01.2018 20:57

            О чём я изначально и написал, да.


  1. cliff_5
    19.01.2018 10:44

    Что значит «js не подходит для сложных программ»? Масштабные 3D игры явно посложнее чем какая-нибудь cms. И нейросети на нём давно реализованны, есть библиотека. Ооп и типы этому никак мешать не могут, всё зависит лишь от программиста


    1. varanio Автор
      19.01.2018 10:47

      Ну не то, чтобы совсем не подходит, но на typescript гораздо легче писать сложные программы. Быстрее понимаешь код и допускаешь меньше тупых ошибок. Angular не зря его выбрал как дефолт


  1. Mabusius
    19.01.2018 11:55

    Поначалу тоже плевался от нестрогой типизации. А теперь вообще не представляю как без нее можно жить. Откуда я знаю что там в ответе от АПИ приходит? 0 как число? 0 строка? null? А что если один единственный метод этого апи писал другой автор и написал «пустой ответ» вообще как то по другому? В ПХП очень низкий порог вхождения, надо учитывать что тут говнокод прет просто со всех щелей и со строгой типизацией будет только хуже.


    1. tehSLy
      19.01.2018 12:48
      +1

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


      1. Mabusius
        19.01.2018 15:09

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


        1. tehSLy
          19.01.2018 15:56

          С того, например, что если бы типизация была статической, или хотя бы, строгой динамической, компилятор еще на этапе компиляции сказал бы,(ну или хотя бы понимал в рантайме) что тут приходит не то, что нужно, а не тихонечко кастовал величины к тайпхинтам. Эта вседозволенность как раз таки и приводит к говнокоду, просто потому, что так проще, а никто не запрещает. Вы точно работали на хоть сколько-нибудь крупных проектах в PHP? Без этого поддержка и разработка оных становится болью ниже спины, я не знаю, как тут можно спорить. Если в плюсах, джавах, шарпах и т.д. можно выстрелить себе в ногу в некоторых случаях, то это точно не относится к таким вещам, как типизация, которая как бы является фундаментальной вещью, ибо есть суть представления информации. У PHP в этом вопросе как будто читы на оружие, можешь отстрелить все что угодно, просто из-за того, что тебе вместо 0 — «0» вернулся, а вкупе с дизайном его API так это вообще стрелковая фиеста.


          1. Mabusius
            19.01.2018 17:29

            Я не говорил, что участвовал в чем то крупном :). ПХП это в первую очередь не для крупных проектов. Если у вас там потребность лезть аж в компилятор, будьте добры возмите чтото другое. А если не можете, то это не проблема ПХП уже. Как выше писали аналогию с напильником — вы взяли не тот инструмент, а теперь ругаете инструмент, что он плохо работает.


            1. tehSLy
              19.01.2018 17:35
              +1

              Ну вот как появится опыт разработки проектов покрупнее, я уверен, мнение о крутости слабой динамической типизации очень быстро рассеется. Я думаю, тут никто не говорит об кейсах аля «бложик на 200 строк».
              Выше также писали, что приходится работать с тем что есть, и что никто под нас, разработчиков подстраиваться не будет, просто потому что, нам видите ли неудобно так.


    1. michael_vostrikov
      19.01.2018 14:13

      Суть не в том, чтобы везде нестрогую заменить на строгую, а чтобы была возможность использовать то или другое.


      1. AlexLeonov
        19.01.2018 15:02

        Нет никакой «строгой типизации» в PHP. Есть контроль типов в рантайме.
        И да, у вас есть возможность его использовать либо не использовать. Что прекрасно, имхо.


        1. VolCh
          19.01.2018 15:06

          Контроль типов — это и есть типизация. А в рантайме она или в каком-то компайлтайме — разница между динамической и статической типизацией. Вот в python типизация строгая, но динамическая. Хотя в каких-то моментах она теперь менее строгая, чем в PHP.


        1. michael_vostrikov
          19.01.2018 15:26

          Сильная и слабая типизация
          PHP еще есть куда двигаться в сторону контроля типов, как его ни называй.


    1. VolCh
      19.01.2018 15:03

      А откуда вы знаете, что в API 0 (число) — это пустое значение, а не валидное полноценное? Банальный индекс элемента в коллекции, например. Собственно, даже в документации функций типа strpos постоянно выделяют предупреждения, что результат false надо проверять строго, что if (strpos($s1, $s2)) не означает "если подстрока найдена".


  1. JTG
    19.01.2018 18:06

    У самого основной хлеб — PHP, но частично согласен с автором.
    Как писали в PHP: фрактал плохого дизайна:

    PHP обширно черпает вдохновение из других языков, при этом ему удаётся быть непонятным для тех, кто эти языки знает.


  1. Sannis
    22.01.2018 18:49

    Чем больше проверок в рантайме, тем больше тормозов. Поэтому слишком сложные проверки навряд ли вообще когда-нибудь появятся. Многослойные дженерики и callable с callable аргументами просто положат рантайм. Также будут тормозить рантайм введение типов для членов класса и в других местах.

    Не нагнетайте, в PHP5 это работает даже быстрее, чем strlen($str), а в PHP7 вообще без разницы.