PHP Fart Time
1.72K subscribers
75 photos
3 videos
2 files
162 links
Привет, фартаны!

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

Авторы контента: @roxblnfk и @butschster
Download Telegram
Рассматриваем Storybook в контексте обновления фронтовой части нового Buggregator.
Поверхностное рассмотрение демонстрационного проекта Ticket Booking, в котором интегрировано всё сразу: #Spiral, #Zipkin, #Birddog, #OpenTelemetry, #Grafana, #RoadRunner, #Centrifugo и #Temporalio.

https://youtu.be/Zk9E3ZBDtb8

Вуху, у нас есть чат! Теперь наши высеры можно комментировать! :)
Please open Telegram to view this post
VIEW IN TELEGRAM
PHP Fart Time
https://youtu.be/IGRI4I_nnQM Репка с бечами https://github.com/php-fart/benchmarks-serializers
Хотел, было, добавить детализации в тексте поста, но при работе с цифрами бенчей возникли вопросы.
Как этот инструмент считает avg?
Оказывается, при расчёте среднего значения исключаются 10% максимальных и 10% минимальных значений. Not bad.
#Hint
А я напомню, что атрибуты можно использовать и в PHP 7.4 с помощью пакета spiral/attributes:^2.7

https://t.me/isPHPdying/143
#Article #Типизация #php

#️⃣ Типизация PHP

Наверное буду кэпом, если скажу, что следование строгим типам и избежание неявных преобразований уменьшает магичность кода, что ведёт к стабильности и надёжности.
Поэтому в коде Spiral, Cycle и других наших продуктов мы используем строгую типизацию, где это возможно.
Вроде тема понятная, но... это же PHP. А значит без нюансов не обойтись 💩

⭕️ declare(strict_types=1);

Прям из доки: по умолчанию, PHP будет преобразовывать значения неправильного типа в ожидаемые. ...
Можно включить режим строгой типизации на уровне файла.
В этом режиме, тип значения должен строго соответствовать объявленному, иначе будет выброшено исключение TypeError.
Единственным исключением из этого правила является передача значения типа int туда, где ожидается float.

⚠️ На вызовы из внутренних функций, действие strict_types не распространяется.

Обратите внимание на предупреждение. Многие core-функции не следуют строгости типов.
Например, array_map() и array_filter() сделают неявное приведение типов.

print_r(array_map(fn(int $a, int $b) => $a + $b, [1, '10', 3], [4, 5, '1e2']));
---
Array (
[0] => 5
[1] => 15
[2] => 103
)


А вот call_user_func() будет ругаться на несоответствие типов.

Рефлексия тоже не следует строгости. Поэтому вместо newInstanceArgs/newInstance в фабрике контейнера у нас $instance = new $class(...$arguments);.
Оно, может, чуть медленнее, но зато надёжнее.

Теперь к костылям.

⭕️ Типизация переменных

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

function makeInt(int &$i): void
{
static $list = [];
$list[] = $obj = new class() {
public int $i;
};
$obj->i = &$i;
}

$int = 1;
makeInt($int);

$int = 42; // 42
$int = 'foo'; // Fatal error: Uncaught TypeError: Cannot assign string...


Не делайте так.

⭕️ PHP 8.2

Типы null, false и true теперь можно использовать автономно.
Зачем это надо? Для вариантности. Например, при расширении метода возвращаемое значение с bool можно сузить до true или false, а nullable (?Foo) — до null. Таких кейсов в библиотеках не мало.

Завезли DNF (Disjunctive Normal Form).
Вот такого мутанта теперь можно будет встретить в коде: (Countable&Traversable)|array

ℹ️
Что интересно, nullable-сахар (?Foo) был добавлен в PHP 7.1 ещё до Union Types.
ℹ️ Всегда явно указывайте тип nullable параметров (?Foo $foo = null) а не полагайтесь только на значение null по умолчанию (Foo $foo = null).
ℹ️ Тип never был добавлен в PHP 8.1. Но он вряд ли вам пригодится, если вы гоняете на RoadRunner.
ℹ️ Тип callable существует только в сигнатурах функций и методов. Его нельзя указать для свойств, а значит и в Promoted properties не засунуть. А всё потому, что в разных контекстах callable может быть разным.
Как же принять callable и записать в свойство? Например так:

// A class declaration
private \Closure $callback;

public function __construct(callable $callback)
{
$this->callback = $callback(...);
}


Может у вас есть какие-то мысли, нюансы или лайфхаки вокруг типов PHP? Поделитесь в комментариях
#ВредныеСоветы
Не используйте FINAL!

Есть хорошие программисты, которые топят за FINAL, а есть успешные люди.
https://samwho.dev/load-balancing/
Наглядно и очень интересно.

В связи с тем, что таких нагрузок вы всё-равно не достигните, в конце статьи всё-же можно поиграться на симуляторе.
#МыслиВслух
https://t.me/samdark_blog/103

Примерный перевод последнего абзаца:

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

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


Крутой доклад от @alexndrnovikov
Наш всратый доклад
Крошка Джун к Мидлу пришёл, и сказала кроха — что такое "хорошо", а что такое "плохо"?

Предлагаю нагенерить идеи Хорошо/Плохо для повышения квалификации PHP-комьюнити
Уважаймые подписчики! Вы верно чли первое правило клуба - не рассказывать о клубе. Но теперь ничего не поменялось и мы встали перед выбором. Готов ли наш канал выйти в массы?
Anonymous Poll
72%
Контент - говно, но вы держитесь. Запускай!
28%
Контент - говно, но PHP-комьюнити не заслуживает даже этого. Остаёмся закрытым элитным клубом.
В последнее время люди из моего окружения начали активно пользоваться Obsidian для ведения заметок и агрегирования информации. После восторженных отзывов уже и я не мог пройти мимо. Не может же быть всё так замечательно.

Оказывается, может!
Отличный markdown-редактор, теги, ссылки как в wiki, удобный и быстрый интерфейс с тёмной темой, даже плагины есть. Markdown рендерится красиво - блоки кода подсвечиваются, mermaid поддерживается, горячие клавиши работают, всё максимально юзабельно.

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

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

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

Обсудить Obsidian-flow го в комменты.
#Article #Типизация #php

#️⃣ Variadic параметр

Вроде тут и сказать нечего. Ну поставил три точки в параметре и всё.
Ан нет. Приколов хватает. Погнали 

⭕️ Что известно

Variadic параметр, он же "списки аргументов переменной длины", пользователем с помощью добавления (сюрприз!) многоточия. Примерно столько вы можете прочитать про variadic в документации. А ещё про то, что в него можно распаковывать итерируемые значения другим многоточием.

function toArray(...$items): array { return $items; }
$a = ['foo', 'bar'];
toArray(...$a);


Variadic является опциональным параметром. Всегда. Т.е. вы можете ничего в него не передавать и ему с того норм.

> Кстати, многие путают понятия "аргумент" и "параметр". Параметр - то, что в определении функции, аргумент - значение, которое передаётся в функцию.

Зачем он нужен, если и так можно передать сколько угодно аргументов, а потом вынуть их с помощью func_get_arg(), как делали ещё наши предки? Кроме того, мы можем в конце списка параметров сунуть массив и даже распаковка не понадобится при вызове функции. function foo(Foo $a, array $myVariadic = []) {}.
А затем, что в variadic умеет в типизацию! (про типы см. предыдущий пост).

function foo(Foo $a, Bar ...$variadic) {}


Теперь только объекты Bar попадут в массив $variadic. Ну это и так все знали.

⭕️ Приколы с распаковкой

Распаковывая iterable в variadic, ключи могут быть разные. Если вы распаковываете список (ключи типа int), то их порядок будет сброшен. Т.е. распаковка массива [3 => 'a', 2 => 'b', 1 => 'c'] приведёт к ['a', 'b', 'c'] в вариадике.
Ассоциативный массив останется ассоциативным массивом с теми же ключами.
Но не всегда можно смешивать целочисленные ключи со строковыми. При распаковке аргументов из массива, как и при передаче именованных+позиционных аргументов, позиционные аргументы должны идти перед именованными. Причём сортируется это по параметрам 💥

⭕️ Именованные аргументы (PHP 8.0)

Поиграем в игру. Есть сигнатура bar(int $a = 1, int $b = 2, int ...$c). Что попадёт в $c?

(если нажать на один скрытый элемент — откроются все)
bar(a: 1, c: 3) - `["c" => 3]`
bar(c: [1, 2, 3]) - `Fatal Error`
bar(foo: 3) - `["foo" => 3]`
bar(1, 2, a: 3) - `Fatal Error`
bar(c: 3, a: 1, b: 2) - `["c" => 3]`
bar(foo-bar: 3) - `Syntax Error`
bar(1, 2, 3, 4, foo: 5) - `[3, 4, "foo" => 5]`
bar(b: 2, 3, 4, foo: 5) - `Fatal Error`
Сколько промахов?
Как итог: распаковка аргументов из массива даёт возможность передать любой сроковой ключ, именованные аргументы — нет.

⭕️ Хрень какая-то. Где оно надо то вообще?

- Когда нужна типизация на списке аргументов, при этом не нужно сохранять ключи. При этом сигнатура точно не будет дополняться. Например, в yiisoft/injector в конструктор можно было бы передавать переменное число ContainerInterface, а не один и только один (@samdark, я смотрю на тебя). Или вот пример, как заставить передать минимум один аргумент нужного типа: function setEncoders(Encoder $encoder, Encoder ...$encoders) {}.

- В атрибутах, которые конфижат непонятно что. В атрибуте Column компонента cycle/orm можно передать любые именованные аргументы сверх тех, что предопределены заранее (спасибо, variadic). Например, определяем #[Column(type: 'bigint', unsigned: true). Здесь unsigned попадёт в variadic и, если у вас MySQL, столбец будет unsigned.

⭕️ Аннотации

Артефакты прошлого ещё долго будут встречаться в коде даже современном. Да, это про аннотации. Там variadic'и не поддерживаются. До недавнего времени они вообще фейлили парсер doctrine/annotations, однако там решили ограничиться просто фиксом "чтоб не падало". Поэтому (и не только) не пользуйтесь аннотациями, если есть возможность пользоваться атрибутами.

⭕️ Поддержка IDE

Её нет. Пока нет известного мне способа рассказать IDE или Psalm'у, какие ключи можно передать в variadic. Можно описать тип только одного (каждого) передаваемого элемента. Если вам известно об этом больше - го в комменты.
#Article

Привет, привет всем любителям PHP! 🎉 Хочу поделиться свежей статьей под названием "Как раскрыть сверхспособности высокопроизводительных очередей для PHP-приложений и не сойти с ума!" 🚀

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

И вот однажды один человек подумал, а почему бы не использовать в этом деле Golang? 🔥 Go умеет делать кучу дел одновременно (горутины), управляет ресурсами как настоящий профи, работает быстро как молния и еще и сокетами управляет на уровне близком к железу. Просто магия!

Итак, в моей статье я рассказываю о супер-мега-крутых очередях на RoadRunner (о плагине "Jobs"). 💪 Там PHP и Go нашли свою любовь и объединились в команду. Теперь PHP-разработчики могут наслаждаться всеми плюшками обоих языков и создавать высокопроизводительниые шедевры!

Но это еще не все, фартаны! Также, я раскрываю стратегии использования очередей. Мы будем погружаться в мир загадочных штуковин, как "Фанатик с запоздалыми задачами", "Король бесконечных повторений" и "Независимый ковбой с ретрайами". Это как сказка, только в мире программирования!

Так что, прямо сейчас отправляйтесь по ссылочке https://butschster.medium.com/unleashing-the-power-of-high-performance-queue-services-for-php-applications-dcc5c1426511! 😄

#PHP + #Go = Unstoppable! 💪

Жду ваших комментариев и обсуждений! 🙌

P.s. Мы как-то побенчили джобы разных реализаций. Оказалось, что очереди в отделении почты разгребаются быстрее, чем в Laravel.
#МыслиВслух
Мы с Павлом как-то готовили доклад. Начали делать его примерно за 2 часа до выступления. Наверное поэтому получилось так всрато, но сносно. Там я говорил о том, что экосистема Spiral акцентируется на объединении разных миров разработки, а скорость - просто приятный бонус: gRPC имплементируется на любом популярном языке, у Temporal есть SDK на разных языках, кроме того, RoadRunner хорошо объединяет go и PHP.

Так вот.
Сегодня я обратил внимание на такую вещь, что объединение миров работает и в другую сторону — не на расширение стека, а на сужение.

Вы когда-нибудь решали задачу утилизации компетенций?
Нафига нам питонист, если задачу можно сделать в одном PHP стеке? Но питонист уже есть и мы не можем его заменить. Нужно его эффективно утилизировать. Берём Temporal и пусть питонист питонирует. Его труды идеально встроятся в наши Workflow!
Добавлю только, что без sudo не удалится. Не благодарите.
Этот пост напомнил об одной интересной картинке: https://proxify.io/worlds/php.
Поставил бы там что-то позитивное мужицкое, но можно только сердечко.

А для вас, фартаны, ивент: ставьте здесь сердечко, если вы тоже фанатеете от Laravel и Тейлора.