Comments 38
Собственно, почему бы и нет. Время идёт, PHP развивается. Только в глазах хейтеров он остаётся на том же уровне, что и был десяток лет назад.
Ох, помню опыт работы с Bunny. Тот еще ад в поддержке и внедрении чего-то. Используем React http в продакшене в качестве бекендов к api уже более двух лет. Не могу сказать, что все гладко и идеально, но много шишек уже набито и приложен подорожник. С учетом того, что вся инфраструктура масштабируется через rabbit, то stateless приложения дают ощутимый прирост производительности, нежели request-response
Спасибо за статью, в целом хороший экскурс в мир асинхронного PHP с тем для чего и как начать
Идите до дна. Вам нужен асинхронный режим работы с СУБД и весь ад, который оттуда вылезет.
В статье всё указано, быть может недостаточно отчётливо, но всё же: взаимодействие с постгресом выполняется в асинхронном режиме.
Видел, но давайте уточню: у вас каждый SQL запрос к базе выполняется асинхронно?
Давайте представим, что вам нужно либо добавить запись либо обновить. Для того, чтобы это понять, вам нужно проверить, есть ли такая запись в базе данных (по ID, например). Если записи нет, то сгенерировать sequence. То, что в PHP делается кодом в 4-6 строк, у вас станет на порядок больше (я помню, что на порядок это х10).
Все здорово, только это синхронное программирование. А я говорю, что нужно идти до конца и выполнять SQL запросы асинхронно, т.е. промисами ждать, пока он выполнится и только потом продолжать выполнение логики.

Вам нужно почитать статью от Никиты, тогда станет понятно откуда там взялся yield и почему код выглядит, как синхронный (каждый вызов execute и fetchOne возвращает Promise).


Мой косяк. Я не стал в статье углубляться в вопросы корутин и, вероятно, это повлияло на восприятие. Мне кажется, что вы имеете в виде callback hell, который мог бы случиться в случае, если бы я руками вызывал всю цепочку промисов.

Ага, разбираюсь, спасибо!
Идея понятна, удивительно, что я про такую возможность yield не подозревал (век живи..). Код, действительно, асинхронный и при этом красивый без всего этого чудовищного callback-а.
А транзакцию, подозреваю, вы передаете в $adapter?
Круто! Исключения тоже могут работать «в yield режиме»!

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

Да, вы совершенно правы, огромное спасибо, что разъяснили!
Забавно, что можно использовать привычные библиотеки, модифицируя их по мере «асинхронизации» проекта

Нет, в этом плане так легко не получится.
Какую-нибудь Doctrine на асинхронные рельсы не поставить. Наоборот, привычные инструменты придётся очень сильно пересмотреть.

А в чем проблема?
Код из проекта с Workerman+reactphp-mysql:


$account
            ->findUserByEmail($email)
            ->then(function($user) {
                if (!empty($user->id)) {
                    $exception = new\App\Exception\ValidationException("User Already Exist", 4);
                    $exception->setField("email");
                    throw $exception;
                }
            })
            ->then(function() use ($account, $email, $password) {
                $account->createUser($email, $password);
            })
            ->then(function() use ($email, $password) {
                $this->sendRegistrationEmail($email, $password);
            })
            ->then(function() use ($callback) {
                $this->sendAckSuccess(true, $callback);
            })
            ->otherwise(function(\Throwable $e) use ($callback) {
                $this->handleError($e, $callback);
            })
А в чем проблема?

В этом примере? Огромное количество лишнего и ненужного кода, например =)

Какой код здесь лишний по-вашему?
function-обертки? От них можно избавиться при желании, получим что-то такое:


$account
    ->findUserByEmail($email)
    ->then([$this, "validateUserDoesNotExist"])
    ->then([$this, "createUser"])
    ->then([$this, "sendRegistrationEmail"])
    ->then([$this, "sendAckSuccess"])
    ->otherwise([$this, "handleError"])
;

Мне удобнее писать:


$user = yield $account->findUserByEmail($email);

try {
    yield $this->validateUserDoesNotExist($user);
    yield $this->createUser($email, $password);
    yield $this->sendRegistrationEmail($email, $password);
    yield $this->sendAckSuccess(true, $callback);
} catch (\Throwable $e) {
    // ...
}

И автокомлит будет, и статический анализ, и меньше лишних then/otherwise

удобнее так :)


        try
        {
            $userData = yield $repository->findUserByEmail($email);

            if(null === $userData)
            {
                yield $this->createUser($email, $password);
                yield $this->sendAckSuccess();
            }
        }
        catch(\Throwable $throwable)
        {
            /** ... */
        }

в данном примере проблемы 2:


  1. Это невозможно нормально читать;
  2. Подключение всего одно.

И если с первой проблемой можно (и нужно) бороться пакетом recoil, то вторая не позволит нормально работать. И что есть там асунк, что нету — ничего не меняется.

Вопрос, предположу, в следующем: у вас на все потоки одно подключение к БД?

Потоков в php не густо (всего 1). А вот как только будет 2 промиса, в рамках которых необходимо выполнить транзакции, будет ждать сюрприз.

Теоретически это легко разрулить собрав их в очередь и/или заведя пул подключений. Уверен есть библиотеки для этого.
Простите, но это просто последовательный вызов функций. Хотелось бы увидеть работу с SQL, например, как вы тащите транзакцию через все это.

Шикарная статья. Все понятно и разжевано. И полезно. Автору респект. И особенно порадовало сравнение с go в benchmarks.


Да это все велосипеды и т.д. И golang или rust предпочтительнее для таких задач. А для именно такой задачи — быстрее всего и устойчивее будет работать вообще erlang. Но имел я ввиду все это учить… (Это я абстрактно — го я знаю).


По факту все придет к унифицированным блокам (вход в бизнес логику — выход из логики) между которыми на чем вокер написан вообще плевать. Nginx Unit наглядный пример, кроме этого. А это — крупная компания, с бабками, не типа нас нищебродов...


Так что с точки зрения экономии времени на изучение этой библиотеки или golang — вывод очевиден.

Only those users with full accounts are able to leave comments. Log in, please.