Актуален ли PHP в 2021 году?

Original author: Burak Karakan
  • Translation

Фокус внимания давно переместился с PHP на JavaScript и Python. Тем не менее у него выходят новые версии, а тесты производительности говорят о неплохом прогрессе. Насколько актуален PHP сегодня? Под катом — размышления разработчика, который продолжает отдавать ему предпочтение.

Краткая история PHP

PHP разработал Расмус Лердорф в 1994 году. Лердорф создал набор скриптов, которые отслеживали посещения его онлайн-резюме, и назвал их Personal Home Page Tools («инструменты личной домашней страницы»). Со временем название превратилось в PHP Tools. Он пополнял этот набор новыми инструментами, а потом решил переписать их: добавил взаимодействие с базами данных и многое другое. Так набор превратился во фреймворк.

Дальше эти инструменты продолжали эволюционировать в еще более сложные примитивы, а после публикации кода в open source в 1995 году число пользователей стало расти заметно быстрее. Если вас интересуют подробности этой истории, вы можете найти их на официальном сайте PHP.

Последняя версия языка сейчас — PHP 8.0.

А что не так с PHP?

Уже долгие годы этот язык — мишень для критики. Люди справедливо упрекают его за проблемы в работе, особенно старые версии. Лердорф разрабатывал PHP как язык шаблонизации, а не как полнофункциональный язык программирования. Поэтому у него есть ряд недостатков, которые сильно усложняют поддержку и разработку крупных приложений. 

Слабая типизация

Лично мне в этом языке не нравится слабая типизация, позволяющая сочетать разные типы и выполнять их неявные преобразования. Рассмотрим такой пример:

echo "1" + 3;
echo 1 + "3";
echo "1" + "3";

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

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

Отсутствие пространств имен

Поддержка пространств имен была добавлена в PHP в версии 5.3. В более старых проектах приходилось создавать собственные типы пространств имен, в основном при помощи добавления пространств имен к названиям классов и методов. Из-за этого приходилось использовать повсюду абсурдно длинные имена. 

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

В более поздних версиях языка таких проблем нет.

Противоречивые функции стандартной библиотеки

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

Вот некоторые примеры противоречивости наименований в строковых методах из документации:

  • strpos(string $haystack, string $needle, int $offset = 0): int|false: находит позицию первого вхождения подстроки в строке;

  • strsplit(string $string, int $length = 1): array : преобразует строку в массив;

  • explode(string $separator, string $string, int $limit = PHP_INT_MAX): array: разделяет строку по граничной строке.

Три разные функции: одна с префиксом str, вторая с префиксом str_, а третья без префикса. Аргумент $string является первым для str_split, но вторым для explode. Вы можете изучить все строковые методы в документации — этому паттерну следует множество функций, то есть среди них нет особого единообразия.

Суперглобальные переменные

Это больше относится к личным предпочтениям — я ненавижу использовать глобальные переменные, а следовательно, и суперглобальные. Когда находишь какие-то старые самодельные проекты, особенно высока вероятность встретиться с печально известными переменными типа $SERVER или $REQUEST. Не поймите меня неправильно: иногда они очень полезны и время от времени их нужно использовать. Однако для безопасного использования этих значений первым делом нужно инкапсулировать их в многократно используемые классы. Если этого не сделать, то взаимодействие со значениями или внесение изменений в крупный проект будет очень сложной задачей, ведь с этими значениями связано множество скрытых зависимостей.

И что хорошего в PHP?

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

Type hints

Это один из моих любимых способов модернизации старого кода на PHP: использование необязательных type hints, выполняющих преобразование типов, а также обеспечивающих документацию кода. Рассмотрим простую функцию:

function isValueSomething($value) {}

Если добавить type hints, код станет таким:

function isValueSomething(string $value): bool {}

Просто увидев сигнатуру функции, мы понимаем, что она ожидает строковое значение и вернет булев-результат. Можно добавить, что здесь полезно было бы применить правильное наименование, однако эти type hints гарантируют, что значения будут именно указанных типов и предоставляют IDE возможность автодополнения и статического анализа с предупреждениями и другими полезными вещами.

С версии 7.4 PHP позволяет задавать и типизированные свойства для классов:

class Person {
    public string $firstName;

    public string $lastName;

    public int $age;

    public ?string $job;
}

Это означает, что у объектов Person будут строковые имя и фамилия, возраст в integer и допускающая пустое значение строка для должности. Чем больше классов — тем полезнее эта возможность.

Улучшения синтаксиса

В поздних версиях PHP появилось много синтаксических улучшений:

  • стрелочные функции: fn ($x, $y) => $x + $y;

  • оператор объединения с неопределенным значением: $value = $array['key'] ?? 'default value';

  • присваивание с неопределенным значением: return $cache['key'] ??= computeSomeValue('key');

  • расширение массивов: $first = ['a', 'b']; $second = ['c', 'd']; $final= […$first, …$second];

  • именованные аргументы: array_fill(start_index: 0, num: 100, value: 50);

  • разделитель числовых литералов: 299_792_458

Помимо синтаксических он содержит возможности для комплексных улучшений.

Constructor promotion

Взгляните на класс Person:

class Person {
    private string $firstName;

    private string $lastName; 

    protected int $age;

    public ?string $job;

    public function __construct(
        string $firstName,
        string $lastName,
        int $age,
        ?string $job
    ){
        $this->firstName = $firstName;
        $this->lastName = $lastName;
        $this->age = $age;
        $this->job = $job;
    }
}

Вместо этого избыточно многословного кода PHP 8 поддерживает возможность написания такого кода:

class Person {
    public function __construct(
        private string $firstName,
        private string $lastName,
        protected int $age,
        public ?string $job
    ){}
}

Удобно, не так ли?

Nullsafe-оператор

Этот оператор существовал в некоторых других языках наподобие JavaScript, но PHP его не поддерживал. Взгляните на код, который я взял из документации PHP:

<?
if (is_null($repository)) {
    $result = null;
} else {
    $user = $repository->getUser(5);
    if (is_null($user)) {
        $result = null;
    } else {
        $result = $user->name;
    }
}

Именно так писали логику в старых версиях PHP для учета проверок на null. Новый nullsafe-оператор позволяет свести это к такому коду:

$result = $repository?->getUser(5)?->name;

Разве не великолепно?

Объединенные типы

Хоть для меня это и не самая любимая штука, она все равно ценна в случаях, когда уже есть несколько возможных типов без type hints. Объединения позволяют определять в качестве вариантов несколько типов значений. Благодаря объединениям становится работающим вот такой код:

function doSomething(int|string $value): bool|array {}

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

Производительность

У меня нет четких данных для сопоставления производительности с другими языками, но по сравнению с предыдущими версиями скорость работы кода PHP заметно выросла. В дополнение к рывку, сделанному PHP 7 по сравнению с PHP 5.6, все последующие релизы вносили улучшения, и эта тенденция продолжается. Проведенные Phoronix бенчмарки демонстрируют, что последняя версия PHP 8 в три с лишним раза быстрее PHP 5.6. В посте по ссылке выше есть подробные тесты, так что их стоит изучить.

В дополнение к этим бенчмаркам Kinsta также провела реальные испытания с WordPress. Вот результат для WordPress 5.3.

Точные цифры замеров таковы:

  • Результаты бенчмарка WordPress 5.3 с PHP 5.6: 97,71 запросов/с

  • Результаты бенчмарка WordPress 5.3 с PHP 7.0: 256,81 запросов/с

  • Результаты бенчмарка WordPress 5.3 с PHP 7.1: 256,99 запросов/с

  • Результаты бенчмарка WordPress 5.3 с PHP 7.2: 273,07 запросов/с

  • Результаты бенчмарка WordPress 5.3 с PHP 7.3: 305,59 запросов/с

  • Результаты бенчмарка WordPress 5.3 с PHP 7.4: 313,42 запросов/с

Пока в эти бенчмарки не включен PHP 8, однако видно, что даже версия 7.4 способна обрабатывать в три раза больше запросов по сравнению с 5.6, и это серьезное улучшение.

Вывод

В целом PHP за последние годы значительно улучшили, и с ним стало удобно работать. Я профессионально пишу на Golang, PHP и Python, но больше всего опыта у меня в PHP, поэтому я могу быть пристрастен. Однако, по моему мнению, PHP нашел идеальный баланс между гибкостью и поддерживаемостью. 

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

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

Leader-ID
Company

Comments 27

    0
    -
      0
      Насколько давно?)
      +4
      я думал что-то интересное будет, а статья просто для того, чтобы рекламу в постскриптуме разместить
        +2
        О да, на что только не идут люди ради рекламы бесплатных открытых мероприятий.
        0
        Копипасты с мануала php.net в основном(
          0

          da

            +1
            5.3 вышел аж в бородатом 2008 году, но отсутствие пространства имен… в огороде бузина, а в Киеве — дядька.

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

            В остальном, отличная реализация ООП, множество фреймворков и библиотек, нормальная производительность.
              0
              • отсутствие generic'ов.
                0
                В языке с динамической системой типов они не настолько критичны.
                  0

                  Да, но вот нормальный DI с отложенным внедрением зависимостей в конструкторе без generic'ов не построить. Приходится прикручивать прокси с кодогенерацией и вытекающими из этого "плюшками" (например, регенерация при изменениях в интерфейсах). В том же .Net это делается на уровне самого языка (Lazy<T>).

                    0
                    Не, я согласен, что фишка удобная. Но опять-таки на данный момент статический контроль «генерикообразных» структур возможен через Psalm. Имхо, отсутствие генериков — не самая главная беда PHP. На мой взгляд, куда больше вредит отсутствие нормальной многопоточности. Судя по всему, мы рискуем увидеть fibers уже в 8.1, а там и многопоточные рантаймы подтянутся под Amp/ReactPHP. В интересное время живем, хе-хе.
                      0

                      Через psalm не всем подходит. Но вообще, да, это не главная проблема. С другой стороны, многопоточность и асинхронность явно не те фичи, которые как-то заметно помогут большинству проектов на PHP.

                        0
                        Вполне помогут. Несмотря на то, что основной вал хайпа по микросервисам прошел, все равно многие серьезные проекты дрейфуют в сторону развертывания отдельных сервисов в k8s, и вот там без асинхронного рантайма приходится очень туго: банально невозможно реализовать health checks, работающие адекватно.

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

                        Ну и фреймворкам типа Symfony/Laravel/Laminas ничто не помешает подтянуться, выкатив скелет асинхронного сервиса.
                          0

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


                          Выкатить могут, но вот как донести разработчикам магазина ООО "Рога и копыта", что переход на новые принципы упростит их работу, ускорит деливери бизнес-фич? Особенно если это будет неправдой. ))

              +1
              Хм. Я так понимаю, автор скопипастил статью «Актуален ли PHP в 2011 году?»
                0
                Скорее «Актуален ли в 2009» — именно тогда были проблемы, что некоторые библиотеки еще не работали с новым PHP 5.3 и не было пространства имен.
                  0
                  Автор всего лишь перевел портянку с medium. А вот зачем — это уже вопрос.
                  –4
                  Фокус внимания давно переместился с PHP на JavaScript

                  В первом же предложении нечто странное… А ничего что это всетаки совсем разные вещи, PHP — сценарный язык программирования для СЕРВЕРНОЙ части, а JS объектно-ориентированный язык КЛИЕНТСКОГО исполнения? Или имелось ввиду Node.JS, но так тогда и надо было писать, а то по сути приводятся несравнимые вещи.
                    +8
                    Всегда считал, что NodeJS — это платформа, а язык-то java script, поэтому js и php вполне уместно сравнивать. Другое дело, что автор в качестве недостатка php приводит слабую типизацию, но при этом в js она не сильно лучше.
                      +1
                      Надо лишь понять где она лучше.
                      // PHP
                      '1' + '1' = 2
                      '1' - '1' = 0

                      // JavaScript
                      '1' + '1' = '11'
                      '1' - '1' = 0


                      Вам какой вариант больше нравится?
                        +3
                        Мне вообще нравится больше строгая типизация. Но если сравнивать эти 2, то PHPшный больше по душе, потому что в JS получается неоднозначно, т.к. знак "+" используется и для конкатенации строк, и для сложения чисел. В случае '1' — '1' происходит неявное преобразование типов, а при '1' + '1' — нет.
                      0

                      И JS, и PHP давно языки общего назначения.

                      0
                      Зачем впихывать в статью о состоянии PHP в 2021 году, проблему языка на момент 10-х годов?!
                        +1

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

                          +1

                          Слава богу, что фокус сместился с PHP. Меньше желающих будет поддерживать легаси на нем.

                            +1

                            Вы с какой стороны смотрите? Конкуренция уменьшится? ))

                              0

                              Да, все верно поняли )

                          Only users with full accounts can post comments. Log in, please.