Пых
8.36K subscribers
212 photos
12 videos
6 files
528 links
Блог @vudaltsov о разработке на PHP.

Хобот: @phpyhobot
YouTube: https://youtube.com/@phpyh
VK Видео: https://vkvideo.ru/@phpyh
Мемы: https://t.me/isPHPdying
Статистика: https://t.me/INOTAROBOT?start=st1219340804

Вакансии НЕ размещаются.
Download Telegram
Пыхап ищет спонсора!

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

Мы планируем провести третий московский Пыхап уже в апреле. Запланированы крутые доклады, Открытый микрофон и афтепати, не хватает только спонсора!

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

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

Про первый Пыхап: https://t.me/phpyh/557.
Итоги второго: https://t.me/phpyh/636.
👍31🔥143🦄1
Closure в константных выражениях в PHP 8.5

В 8.5 приняты два RFC:
PHP RFC: Support Closures in constant expressions,
PHP RFC: First Class Callables in constant expressions.

Они позволяют использовать анонимные функции и first class callable синтаксис в константных выражениях (значениях параметров по умолчанию, константах, константах класса и атрибутах).

Как всегда в PHP нельзя что-то добавить без "но". В данном случае исключение сделано для стрелочных функций, потому что они автоматически захватывают контекст, а константные выражения не могут содержать переменные.


final class Request
{
#[Validate(is_string(...))]
#[Validate(static function (string $locale): bool {
return preg_match('/^[a-z]{2}$/', $locale);
})]
public mixed $locale = 'ru';
}

final readonly class Checks
{
public const Closure IS_STRING = is_string(...);

public const Closure IS_LOCALE = static function (string $locale): bool {
return preg_match('/^[a-z]{2}$/', $locale);
};
}

final readonly class Worker
{
public function __construct(
private Closure $onFinish = static function (): void {}
) {}

// ...
}
👍48🔥1710👎2🥱1
PHP-линч #28 с Андреем Моховым / andi-lab/graphql-php

В среду в 18:30 вместе с Андреем Моховым отлинчуем его библиотеку для описания GraphQL API на базе webonyx/graphql-php с возможностью интеграции в SpiralFramework.

https://github.com/andrey-mokhov/graphql-php
https://github.com/andrey-mokhov/graphql-php-spiral

YouTube: https://youtu.be/DQPtYimff6M
VK Видео: https://vkvideo.ru/video-228746873_456239027
👍25🔥17
Есть тут такие, кто, как и я, не юзает чат-боты и счастливо живёт?
Anonymous Poll
54%
Да!
46%
Нет, ИИ — наше всё, а ты чёртов ретрогад.
PHP RFC: Marking return values as important (#[\NoDiscard])

За internals не успеть в последнее время! Вот уже на голосование вышел RFC от Tim Düsterhus и Volker Dusch. Они предлагают добавить в PHP атрибут #[NoDiscard] — им можно будет пометить функции и методы, возвращаемое значение которых не стоит игнорировать. Например, вот такой код будет кидать E_WARNING, если RFC примут:


$date = new DateTimeImmutable('2024-1-1');
$date->setDate(2025, 1, 1); // E_WARNING

echo $date->format('Y'); // 2024


Возвращаемое значение считается использованным, если оно участвует в выражении или присваивании. Чтобы избежать предупреждения и явно в коде обозначить намерение не использовать результат вызова функции с #[NoDiscard], авторы RFC предлагают добавить (void) каст. Он превратит выражение в инструкцию:


flock($stream, LOCK_EX); // E_WARNING

(void) flock($stream, LOCK_EX); // OK

if ((void) flock($stream, LOCK_EX)) {} // Parse error


Использование #[NoDiscard] в функциях и методах, возвращающих void, never, а также в магических методах и хуках свойств приведёт к фатальной ошибке на этапе интерпретации.

По мнению авторов, этот атрибут будет полезен для функций с сайд-эффектами, которые при этом ещё что-то возвращают, например, ошибки.

https://wiki.php.net/rfc/marking_return_value_as_important
👎75👍18🤔10🔥7
Пых
PHP RFC: Marking return values as important (#[\NoDiscard]) За internals не успеть в последнее время! Вот уже на голосование вышел RFC от Tim Düsterhus и Volker Dusch. Они предлагают добавить в PHP атрибут #[NoDiscard] — им можно будет пометить функции и…
Что я сам думаю по этому поводу?

Имхо, это такой же бесполезный атрибут, как и #[Override]. Никакого спроса лично у меня на эту фичу нет. Наверное, потому, что мои функции либо не мутируют стейт, либо возвращают void. Ну а к особенностям нативного апи я давно привык.

По сути, это очередная проблема, которая должна решаться статическим анализом, а не рантаймом.
👍49💯10🔥4👎2
В честь 8 марта я немножко помучил Midjourney:

This is the logo of my Telegram channel about PHP in the form of an elephant. Add a flower to its trunk. Please keep the same image style.


С праздником, дорогие подписчицы! 💙
Please open Telegram to view this post
VIEW IN TELEGRAM
64🔥23👍22🍓5💩3
Media is too big
VIEW IN TELEGRAM
Коллекционный PHP-слоник 💙 Пых!

Как вы все знаете, маскот языка PHP — слон. В 1998 году Vincent Pontier придумал дизайн оригинального плюшевого слоника, который с тех пор был многократно переосмыслен по различным поводам.

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

Чтобы запустить в производство целую партию, я решил создать краудфандинговую кампанию! Среди вознаграждений — слоник Пых, слоник PHP 8 Сергея, та самая долгожданная лекция по Message Bus и личная встреча со мной. Переходите по ссылке и принимайте участие. Буду бесконечно рад, если у нас получится воплотить в жизнь этот проект! 💙

https://planeta.ru/campaigns/phpyh_slon
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥43👍327👏7
Пых
Ребята, мы уже собрали 25%! Я в шоке. Спасибо!
58% за день. Вы мои герои! 🦾
🔥55👍196🥱2
Сумма прописью

В последнее время я частенько работаю с договорами. Когда в тексте нужно поменять сумму прописью, я использую первый попавшийся онлайн-сервис. Но вчера случайно обнаружил, что то же самое можно сделать в PHP одной консольной командой (должно быть установлено расширение intl):

php -r "echo new NumberFormatter('ru', NumberFormatter::SPELLOUT)->format(12_345);"

двенадцать тысяч триста сорок пять


Сейчас вы в комментариях напишете, что я просто мог попросить "чатик" поправить мне договор. Но давайте не будем об этом. 😅

Вообще intl умеет делать кучу полезных вещей, но этот факт всё время вылетает из головы. Наверняка существует огромное количество велосипедов, которые можно было бы заменить парой вызовов соответствующих функций.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥99👍53
Почему позднее связывание статическое?

В PHP есть такая фича, как позднее статическое связывание (late static binding или LSB). Она позволяет обратиться к вызываемому/инстанциированному классу в контексте наследования.

Когда-то давно для работы с LSB использовались функции forward_static_call, forward_static_call_array, get_called_class. Теперь всё это можно делать через static:


/**
* @psalm-consistent-constructor
* @phpstan-consistent-constructor
*/
class A
{
final public static function staticClass(): string
{
return static::class;
}

final public static function newStatic(): static
{
return new static();
}
}

class B extends A {}

var_dump(
A::staticClass(), // "A"
A::newStatic(), // object(A)
A::newStatic()::staticClass(), // "A"
B::staticClass(), // "B"
B::newStatic(), // object(B)
B::newStatic()::staticClass(), // "B"
);


Обратимся к документации, чтобы разобраться в нейминге. Почему связывание "позднее"?

Природа названия «позднее статическое связывание» возникает из внутренней логики работы языка. Связывание называется «поздним», потому что конструкция static:: разрешается не в тот класс, в котором определили метод, а вычисляется на основе информации в ходе исполнения программы.


Ок, это понятно. Но почему "статическое" и почему static?

Связывание также назвали «статическим», поскольку этот механизм в числе прочего умеет вызывать статические методы.


А вот тут не логично, согласитесь. static — это про то, что метод/свойство доступны без объекта, а не про то, на какой класс мы ссылаемся. Гораздо лучше было бы взять called:: или late::. Документация объясняет, почему так вышло:

Вместо введения нового ключевого слова для позднего статического связывания разработчики языка выбрали ключевое слово static, которое зарезервировали прежде.


Тем не менее, мы с вами так привыкли к static, что уже не чувствуем нелогичности этого нейминга...
👍55💯13🔥6🤯51👌1
Пых
Почему позднее связывание статическое? В PHP есть такая фича, как позднее статическое связывание (late static binding или LSB). Она позволяет обратиться к вызываемому/инстанциированному классу в контексте наследования. Когда-то давно для работы с LSB использовались…
self вместо static в финальных классах

Изначально я садился писать этот пост, но решил вас предварительно разогреть... 😉

Представьте себе такую ситуацию:


interface A
{
public static function new(): static;
}

final class B implements A
{
public static function new(): self
{
return new self();
}
}


Есть ли тут ошибка? Поначалу кажется, что есть. В интерфейсе сказано: нужно вернуть инстанс класса позднего статического связывания, а реализация использует более широкий тип self и поэтому нарушает LSP. PHP тоже так считает: https://3v4l.org/qWDQY.

А теперь обратим внимание, что класс B финальный! В цепочке наследования после B уже никого не может быть, это самый "поздний" возможный класс. В финальном классе всегда self =:= static. Так что ошибки на самом деле нет!

Недавно подписчик Пыха @m1chael19 закинул PR с исправлением этого недоразумения. Фикс посчитали очень логичным и смерджили в 8.5 без RFC. Поздравим Михаила с первым контрибьютом в PHP!

https://github.com/php/php-src/pull/17724
https://3v4l.org/qWDQY/rfc#vgit.master
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥93🎉40👍23🤔3
Друзья, я долго вынашивал этот план. Заручился поддержкой трёх родных ивент-компаний и сегодня принял окончательное решение:

В сентябре у нас будет Пых.Конф!

Подробности чуть позже.
🔥186👍38😱17🫡5🎃2🦄2🤯1
Кодим с джуном на PHP #2 / Павел Бучнев учит Валентина работать с Claude

На этот раз джуном буду я! Когда Павел Бучнев с канала PHP Fart Time узнал, что я всячески сопротивляюсь использованию LLM, он тут же решил меня переубедить, а заодно показать, как пишет код с помощью Claude и какие инструменты использует.

Встречаемся в ближайшую среду (26 марта) в 19:00!

YouTube: https://youtu.be/UIrl1lIF2tE
VK Видео: https://vkvideo.ru/video-228746873_456239029
5🔥79👍246😱3
Пых
Кодим с джуном на PHP #2 / Павел Бучнев учит Валентина работать с Claude На этот раз джуном буду я! Когда Павел Бучнев с канала PHP Fart Time узнал, что я всячески сопротивляюсь использованию LLM, он тут же решил меня переубедить, а заодно показать, как пишет…
Кодим с джуном на PHP #2 / Павел Бучнев учит Валентина работать с Claude

Сегодня Павел Бучнев заставит меня попробовать Claude! Посмотрим, что из этого выйдет!

Стрим перенесли на час, присоединяйтесь в 20:00.

YouTube: https://youtu.be/UIrl1lIF2tE
VK Видео: https://vkvideo.ru/video-228746873_456239029
Генератор контекста: https://docs.ctxgithub.com/
Промпт: https://gist.github.com/butschster/1b7e597691cc1a6476b15dc120ecbddb
🔥27👍6💩3😁1
Open Source Цех #4 / PHP-CS-Fixer, Brick\Math, Infection

Сегодня в очередном выпуске Цеха изучим ревью моего PR в PHP-CS-Fixer с прошлых стримов, поконтрибьютим в пару проектов и посмотрим на канал @open_source_php от Димы Дерепко.

Приходите в 18, разогрею вас перед стримом фартанов!

https://youtu.be/viWYmUUsD5I
https://vkvideo.ru/video-228746873_456239037
👍43🔥2
Пых
Open Source Цех #4 / PHP-CS-Fixer, Brick\Math, Infection Сегодня в очередном выпуске Цеха изучим ревью моего PR в PHP-CS-Fixer с прошлых стримов, поконтрибьютим в пару проектов и посмотрим на канал @open_source_php от Димы Дерепко. Приходите в 18, разогрею…
Как подменить файл из autoload.files

Сегодня в конце стрима я написал в тикете Infection, почему мутация функций очень полезна. Один из мейнтейнеров поставил под вопрос возможность подмены оригинальных файлов из секции autoload.files на мутированные. Ну а поскольку я обожаю такие вызовы, я пошёл смотреть не на жену, а в код сгенерированного автолоадера Composer:

if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

require $file;
}

И придумал следующую лазейку:

function disableAutoloadFile(string $vendorDir, string $file): void
{
/** @var array<non-empty-string, non-empty-string> */
$idToFileMap = require $vendorDir . '/composer/autoload_files.php';

$id = array_search(realpath($file), $idToFileMap);

if ($id === false) {
throw new LogicException("File `{$file}` is not registered in autoload.files");
}

if (isset($GLOBALS['__composer_autoload_files'][$id])) {
throw new LogicException("File `{$file}` is already loaded");
}

$GLOBALS['__composer_autoload_files'][$id] = true;
}

disableAutoloadFile(__DIR__ . '/vendor', __DIR__ . '/src/functions.php');
require_once $infectionTmp . '/functions_mutated.php';

require_once __DIR__ . '/vendor/autoload.php';

Да, грязновато, но, похоже, это единственный способ добавить мутацию функций в Infection...

Готовы вместе со мной поработать в Цеху в эти выходные?! Ставьте 💯, если да!
Please open Telegram to view this post
VIEW IN TELEGRAM
💯39👍17🥴12🔥72😁2🥰1🤔1