Фокус внимания давно переместился с 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?
Язык на многих произвел плохое впечатление, но за последние годы он сильно улучшился. Благодаря релизу PHP7 язык модернизировался, в его основе появилось множество приятных особенностей, повысились скорость работы и удобство пользования.
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 по сравнению с PHP5.6, все последующие релизы вносили улучшения, и эта тенденция продолжается. Проведенные Phoronix бенчмарки демонстрируют, что последняя версия PHP8 в три с лишним раза быстрее PHP5.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 при работе с более старыми версиями, я рекомендую дать этому языку еще один шанс. Возможно, он вам все равно не понравится, но я считаю, что многие изменят свое мнение, беспристрастно взглянув на новую версию.
P. S. А еще хотел напомнить, что на нашей платформе каждую неделю проходят полтора-два десятка бесплатных мероприятий, связанных с IT и программированием. Не все они так же хардкорны, как доклады на конференциях Олега Бунина и JUG.ru, хотя попадаются темы и для продвинутых. Например, летом мы делали расшифровку доклада сообщества JUGNsk из новосибирской Точки кипения Project Panama: как сделать Java ближе к железу. И это был классный рассказ.