• Как сформировать через рекурсию многомерный массив?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    function _array_set(array &$array, array $fullpath, $value) : void
    {
        if (! $fullpath) {
            throw new InvalidArgumentException('The `fullpath` should be not-empty');
        }
    
        $last = array_pop($fullpath);
    
        $valueRef =& $array;
        while ( null !== ( $k = key($fullpath) ) ) {
             $valueRef =& $valueRef[ $fullpath[ $k ] ];
    
             next($fullpath);
        }
    
        $valueRef[ $last ] = $value;
    }
    
    $array = [];
    _array_set($array, [ 1, 2, 3 ], 'abc');
    var_dump($array[1][2][3]); // 'abc'
    Ответ написан
    Комментировать
  • Как написать чат на php?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Чат это хранилище переписки и способ их доставки.

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

    Но в пхп есть работа с сокетами используя команды stream_*, чтобы подключить обоих участников (подписать) к третьему серверу и он принудительно присылал ожидающим сообщения обновления как только они придут на сервер.

    Если это будет консоль двух клиентов и консоль сервера то столкнешься с проблемами на windows, где у cmd.exe нельзя писать в консоль и одновременно слушать соединение с сервером, только по-очереди, на линуксе - можно. В смысле и там и там по-очереди, просто винда не умеет до завершения того как ты печатаешь быстро переключаться между "послушать сокет" и "послушать ввод юзера" - слушает ввод юзера пока enter не нажмешь.

    Если будешь делать морду на html, будешь использовать либо периодический опросник с "морды" клиента на javascript к серверу через асинхронные запросы (ajax), либо будешь применять пакет для javascript socket.io и протокол веб-сокетов, чтобы уменьшить задержку между получением с "времени опроса" до "как только пришло сразу показать".
    Ответ написан
    2 комментария
  • Как заставить IDE воспринимать данное выражение как указанный обьект Class'а?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    /** @var MyClass $theCache */
    $theCache = i()->app->cache;


    Обычно это делают когда пишут сам объект, задавая тип возвращаемого значения. Но разработчикам часто не дают времени этого делать, а потом все равно обвиняют в ленивости люди, которые кроме экселя в жизни ничего не умеют. Делайте это, а то аджайл и скрам мастера отожмут все результаты вашего труда а потом еще тебя в суде разденут. Будешь и без денег и с фалосом в нужном месте.

    Когда это поймет начальник?
    Действительно. Кстати, а зачем ему это понимать? Всё работает, что вы тут лодку раскачиваете. Это происходит в России? Нет. В США, в Канаде, в Украине, в Беларуси и в России тоже. Везде. Линия границ проходит не по странам, а по способу получения прибыли - одни получают деньги за свою работу, а другие - за чужую. Вот кто за чужую - готов говорить что белое это черное. А если упрямишься - лишают работы, должен молчать и кланяться.
    Ответ написан
  • Как поменять домен временному URL?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    В ларавель конфиг файлы загружаются до старта приложения и только внутри них можно безопасно брать данные из env() (в теории можно везде конечно, но я как-то ловил с этим проблему либо они пропадают, либо глюк какой-то был, года два назад долбался)

    то есть сначала ты в папке /config/ создаешь любой файл с расширением myfilename.php который возвращает массив, там хаваешь данные:

    # ./.env
    APP_API_URL=http://localhost


    <?php
    // ./config/myfilename.php
    return [ 'api_url' => env('APP_API_URL') ];


    <?php
    // ./src/Commands/MyCommand.php
    
    namespace App\Commands;
    
    class MyCommand {
      public function handle() {
        $apiUrl = config('myfilename.api_url');
      }
    }


    Иногда руководитель не хочет привязываться к ларавель и требует написать код работающий для любого фреймворка, в этом случае на вход исполняющего класса нужно передать array $configFilename, который потом настроить в AppServiceProvider.php (который по сути просто настройщик контейнера-инжектора):

    <?php
    // ./src/Providers/AppServiceProvider
    
    namespace App\Providers;
    
    Class AppServiceProvider {
      public function register() {
        $app->when(\App\Commands\MyCommand::class)
          ->needs('$configFilename')
          ->give(function () { return config('filename'); });
      }
    }


    <?php
    // ./src/Commands/MyCommand.php
    
    namespace App\Commands;
    
    class MyCommand {
      protected $configFilename;
    
      public function __construct(array $configFilename) {
        $this->configFilename = $configFilename;
      }
    
      public function handle() {
        $apiUrl = $this->configFilename['api_url'];
      }
    }


    Похожий настройщик будет и у любого другого фреймворка, но смысл в том, что мы можем настроить это, а можем передать вручную. Это и делает код фреймворко-независимым.

    Это что касается как прокинуть свою переменную окружения в любое место.

    Есть еще вопрос как работает фасад Url и его метод ::temporarySignedUrl(). У каждого фасада есть ->getFacadeAccessor() который возвращает класс, занимающийся работой. Фасад это всего лишь "вызывалка" действий, которая вопреки всем законам ООП решили сделать статической.

    Тебе нужно достать оттуда класс в каком-то методе ->handle() (создай себе TestCommand::class), или написать метод ->test() в каком-то из контроллеров (MainController.php или TestController.php), достать акцессор, посмотреть что за класс с помощью dd() или var_dump(get_class()). Потом найди этот класс в папке ./vendor/illuminate и посмотри внутри какую конкретно переменную оно использует. Может быть не APP_API_URL, а просто APP_URL ?

    Если просто APP_URL, то надо подумать можно ли тебе её менять. Ведь скорее всего на эту переменную подвязан какой-нибудь Sitemap Generator, и значит нужно наследовать и подменять фасад для Uri, или писать свой класс декоратор, куда на вход будет исполнитель фасада прилетать, а все что он умеет - единственный метод, который делает то же действие по-другому.

    Ларавель и архитектура это не друзья. Зато ларавель и короткий синтаксис - это работает.

    Способ ларавеля это же сделать чуть другой (я думаю):
    в файле routes.php ты своему роуту "verification.verify" в документации роутера на их сайте ищешь как установить домен. При любой попытке его создать он либо как-то будет использовать твой новый указанный домен, либо "попросит" (упадет в ошибку и не будет работать) его передать вместе с "id" и "hash".
    Ответ написан
  • У кого был опыт в программировании транзакциий(вопрос легкий)?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Если вакансия не прогера то это вопрос чтобы тебя поймать и проверить твой кризис менеджмент. Тебя просят оттолкнуться от задачи, которая вероятно может быть, но при это берут на вакансию человека, который должен просто уметь сочинять и налаживать контакт.

    То что ты решил, что это вопрос на знание предметной области - это тебя и завалило. Ты должен был решить что это вопрос на умение заставить человека говорить. Идея в том что ты всегда будешь получать задачи в которых ничего не шаришь, а нужно сделать вид, что ты мастер. Это можно "Знать" и быть, но бизнес всегда требует "Казаться". Он требует "Быть" только когда задает вопрос "Где результат?" и ему бы очень понравилось, если бы за вас всю работу сделали коллеги. Вас бы ещё и повысили при этом. И то что вы сейчас это спросили - хороший ход кстати. Зачем самому делать?

    Что-то вроде:

    1. Что ж, хорошо. В вашей системе есть агенты, приведите мне аналогию того, что вы называете агентом, предположив, что я не знаю, о чем вы говорите? Мне придется объяснять это разработчику, а вы же знаете их - они все на своей волне...
    2. Понятно. Комиссии. Давайте разберемся в какой конкретно момент вы считали бы нужным её взимать? Есть у этого процесса ожидаемый план действий в каких условиях взимать не нужно? Расскажите мне детальнее.
    3. Похоже я понял, можете ещё пояснить поподробнее про новый тип этих комиссий?"

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

    Такой вопрос если был задан на интервью - ты можешь выкрутить через харизму. Если такой вопрос написан на бумажке, да ещё и надо целых 10 примеров, а не "2-3" что достаточно для понимания уровня, это пахнет долбаловом мозгов. На тебе проверяют флоу собеседования, и ты как единица здесь не то что не получишь работу, ты вообще погрешность.
    Ответ написан
    Комментировать
  • Перебирая SimpleXML файл как многомерный массив, он выдает только первый массив останавливаясь на нем?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Осторожнее с SimpleXML.
    Он очень непривычным способом обходит по дереву разметки.
    А ещё удаление или перезапись через него делать "одно удовольствие".
    Помните, что ещё есть класс DOM, который часто используют в спарке.
    Ну вот такие мы пыхари лентяи, нормальный пакет для работы с XML хрен кто написал.
    Можно попробовать симфонийский кроулер, но он вроде как под HTML писался, хотя под капотом использует DOM, а значит в теории умеет в XML.
    Ответ написан
    Комментировать
  • Поддерживает ли PHP асинхронность на уровне ядра языка программрования?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Чтобы сделать пример асинхронки на коленке, не вдаваясь в детали, нужно завернуть действие в генератор и перед каждой строкой кода писать "yield <строка кода>", чтобы код останавливался и передавал управление наружу. В этом случае собрав пачку генераторов и используя форич чтобы в КАЖДОМ ШАГЕ двигать КАЖДЫЙ ГЕНЕРАТОР на один шаг вперед - можно получить асинхронное выполнение.

    Если чуть глубже то yield на самом деле стоит писать перед теми операциями, что делаются долго, но при этом не то, что они тяжелые, а они предполагают ожидание чего-то. Например, отсылка почты сама по себе происходит быстро, а вот пока подключишься к серверу - это висим. Вот эти самые нетяжелые но долгие операции имеют время простоя, которое можно куда-то еще применить, пока ждем, если написать свою функцию mail(), которая открывает соединение и шлет что-то серверу, то есть по тому самому SOLID не сразу отсылает емейл а делает это в пару этапов, между которыми будут запускаться "шаги" из других генераторов.

    Но оно не будет параллельное в полном смысле (одновременно делаться не будет, просто будет более грамотное управление простоями).

    А вот блокирующие функции, например, функция sleep() она по умолчанию блокирующая, то есть вызвав её мы будем висеть сколько-то секунд. Она блокирующая не потому, что она "родилась такой", а потому что в ней внутри не сделаны передача управления наружу в каждом тике. Поэтому пишут так как еще в яваскрипте показывали - ставят таймер на 1 секунду к примеру (а лучше на так называемое "время тика"), и в каждом шаге проверяют - "столько-то секунд с момента запуска таймера прошло уже?" и если прошло то двигают генератор дальше, если нет - продолжают ждать.

    Это создает некую иллюзию асинхронного кода, но это не совсем то же самое что сделать pcntl_fork(), который в конечном итоге будет делать действительно в двух разных процессах (программах) и ему будет люто наплевать что делается в соседней. А затем родитель, породивший все форки просто вешает ожидалку всех детей до состояния "пока закончилось", тем самым получается нечто вроде Promise.all(tasks).

    Как итог pcntl_fork() - это переброс ответственности за опрос потомков на саму прогу php и на железо компьютера вместо кода, написанного на php, где каждая команда под капотом будет выполнять множество машинных вызовов, протупливать и так далее. Когда железо следит за этим получается НАМНОГО быстрее, задействуется больше ресурсов компьютера и т.д. Но в действительности там тоже нет прям вот "одновременного" с точки зрения момента времени, но есть "пока есть свободный исполнитель возьми это на себя", что действительно является одновременностью с точки зрения промежутка времени.

    Есть и прикольная новость. То что в винде до сих пор этого нет (хотя помнится вместе с PowerShell уже как-то вкрутили через три села и корчи), то это значит что если вы подымаете эту тему, то ваш уровень примерно "майкрософт". Можете запихнуть это в глотку рекрутеру, который будет говорить что вы "не имеете опыта в высоконагруженных распределенных системах" и улыбаться тому, что она едва умеет в эксель.

    ====

    Немножко практики - "когда без асинхронки не обойтись". Еще пару лет назад я был уверен что в пхп асинхронка не нужна вообще. Ну дескать - язык такой, нет здесь асинхронных задач.
    А вот и нет. Просто асинхронность у пхп разработчиков берет на себя Nginx + PHP-FPM или Апач. Это его задача на каждый запрос подымать процесс и делать его отдельно.
    Когда система ТЯЖЕЛЕЕТ и не может справляться с поставленными задачами потому что Nginx имеет время ожидания, и скрипты запущенные из апача висящие в браузере (например) часами - это ересь и бред, или когда буквально не хватает ресурсов одного компьютера и всё глючит, а нагрузка шкалит под 90%, задаешься тем, что нужно МАСШТАБИРОВАТЬ приложение. Это значит что операции требующие много времени нужно выбросить на другую машину. Сразу такой "как же это сделать". Начинаешь читать про БРОКЕРЫ СООБЩЕНИЙ. Редисы (rpush, lmove), Раббиты (ampq, тормознутый как старое пердало), Кафки (event sourcing из коробки на компах с 384гб оперативы - у вас такого нет), Натсы (к которым не найдешь пхпшной обертки нормальной). И тут выясняется следующее. Что когда из пыхи ты стрельнул сообщением в брокер, а кто-то, кто на него подписался сообщение получил, то он делает его СИНХРОННО, одно за другим. И нет там апача который заботливо на каждое сообщение подымает для тебя новый процесс. И вот тут ты задумываешься как же сделать так, чтобы пришедшие сообщения делались не одно за одним, а сразу десяток. И понимаешь - как хорошо, когда асинхронка уже есть, приручаешь pcntl_fork() и делаешь ручками. В этот момент происходит отсев разработчиков на "пыха дерьмо" и "пыха может всё". Вот первые уходят в GoLang или долбятся с NodeJs и прикручивают, а другие понимают что в пыхе есть другие преимущества, потерять которые - дороже.

    Кое-что про Pthreads и почему его "забыли". Его не забыли. Просто pthreads подымал разные задачи от начала до конца. То есть в каждом процессе требовалось произвести инициализацию того же фреймворка например. Это дорого и тяжело. В отличие от форка, который в нужный момент просто отпочковывается в другую задачу сохраняя всё, что уже было сделано. Это лучше, чем стартовать целые скрипты заново.
    Ответ написан
    1 комментарий
  • Как записать в JSON число только с ДВУМЯ цифрами после точки?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Вам программа подсказывает что вы неверно работаете с сущностью "бабло".
    Бабло должно быть строкой или интом.
    Вы делаете из него флоат и получаете ровно то, с чем борятся говоря "бабло должно быть строкой".

    1) Функции связанные с деньгами это отдельный класс в приложении который использует для их расчета функции bcmath, умеющие считывать произвольное число знаков до и после запятой и считать число не взирая на разряд.

    2) Для работы с деньгами используют библиотеку phpmoney где большая часть нужных вам вещей уже завернута, есть парсер и форматтер, поддерживаются валюты и с гемором но можно даже создавать свои. К сожалению, парсинг валют с сайта банков вы скорее всего будете писать сами, т.к. предложенный вариант парсит их из какого-то источника, который не учитывает ситуацию в вашей стране, но сама поддержка переводов валюта-валюта есть.

    3) Для работы с деньгами дописывают функции "округление в большую сторону и округление в меньшую сторону с учетом копейки в последнем разряде", их в пхп нет, они считаются "не математическими", как и вся экономика основаны на "кто кому чего должен" а не "сколько будет". Так округление 1.0005 до двух знаков равно 1.00, тогда как экономика считает что 1.01. И тут тоже два пути. Если вы выставляете клиенту цену, то это 1.01 (копейку содрать с клиента), а если клиент пополняет баланс, то это округление в меньшую сторону - на баланс зачисляется 1.00 (снова содрать копейку). Экономика очень подлая хрень. Она экономит всё. Но не за счет себя, а за счет того, кто платит. И вы еще спрашиваете почему "бизнес это благо", потому что те кто им занимаются грабят остальных средь бела дня (если даже в программировании вопрос копейки, то что в маркетинге - я боюсь даже представить, цена из воздуха, хайп и лексусы) и никто еще и доказать этого не может. Везде бумага "сам согласился и подписал".

    4) Для работы с баблом также вводят собственную валюту (желательно), т.к. остальные скачут как хотят, а ваша цена на сайте остается прежней, но при этом в самих валютах имеет разное выражение. Помните, да, "Игровое золото"? Это не просто "прикольно". Это юридически и экономически необходимо. Вам. Ведь если компания теряет деньги, то внезапно оказывается, что сам директор кроме бумаг ничего не выдает в мир. А вот из-за вас, программистов, у него из кармана утекает. Замалчивая факт "откуда приходит" очень весело обвинять всех, что "из-за них - уходит".

    Как и в экономике. Кто делает - тот платит. Кто не делает - тот выигрывает. В общем - мобилизация не случайность. Медитируйте. Желательно с книгой Ленина.
    Ответ написан
    24 комментария
  • Как правильно спроектировать функционал для работы с платежной системой под laravel?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Вот здесь про ивент-сорсинг можно поговорить. Где каждое действие программы не трогает юзера там, его баланс или заказы, а создает обьект, наполняемый изменившимися данными и сохраняет их в таблицу истории. А потом когда надо сделать вторую операцию - берем все события, загружаем назад в объект "проигрываем" - и получаем реальную сумму на счете и все остальное.

    Но для платежей кроме лога действий обычно нужен еще номер транзации в платежке, название действия, статус самой транзакции, которая обновляется по мере того как приходит ответ "оттуда", можно конечно всё в лог действий писать, а потом разгребсти что и откуда из этой мусорки, а можно и традиционно - таблица "payment_transactions" и там поле "status: wait/processing/done/fail" и кусочки кода которые сдвигают этот статус.

    Что до верхнего слоя апи - то первые пару методов такие - списать бабло, зачислить бабло, подарить бабло от имени админа, забрать бабло от имени админа.

    Валюты точно потребуются. А значит вводите понятие "базовая валюта", именно в ней будут ваши цены. Можете условно приравнять её к 1 доллару, но не используйте сам доллар/евро/рубль в качестве валюты, сделайте новую. Лучшая аналогия (в том числе юридическая) - какие-нибудь танки. Там могли бы платить баксами, но платят игровым золотом, а золото покупают за баксы.
    Ответ написан
    Комментировать
  • Laravel eloquent. Большое потребление памяти, долгая загрузка и огромное количество моделей. Как оптимизировать?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Там же фильтровать можно:

    $query = Model::query()
      ->with([
        'relation' => function ($query) { $query->where('field', 'value'); },
      ]);


    И потом, на кой вам сдалось выдергивать из базы ВСЕ ОПРОСЫ, на странице поди больше десятка не поместится. А варианты ответов тоже не сразу нужны, вероятно, что можно для одного "открытого" запрашивать, это если за оптимизацию говорить.
    Ответ написан
    Комментировать
  • Какая архитектура приложения лучше?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Всегда упирается в производительность машины.

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

    Нужно ли нам запускать отдельно фронтенд? Как напишешь. Мастер в пхп может написать код внешнего вида на пхп, а потом на фротенд-фреймворке описать только визуальные эффекты и метаморфозы страницы. Мастер фронта предпочтет использовать один javascript, чтобы написать всю логику, но при этом он сделает всякие сторы, пагинаторы и то, что бекенд тоже делает - у себя еще раз. По мере разбивания на машины это будет влиять либо в то, что ваши фронты постоянно вынуждены чуть чуть понимать в пхп, либо в то, что ваш бек понятия не имеет как оно у фронтов там работает.

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

    По моему опыту - даже у нас, программистов, тут кромешный хаос, а ведь все последовательно и понятно. Там же вообще "нейронная сеть правит бал" (читай: мы выкатили, оно пошло, потом графики посмотрим, как работает? - "ну работает же!")
    Ответ написан
    Комментировать
  • Как подключить browser-sync при работе на open-server?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Я обычно отдельно вебпаки не настраиваю, больно это сложно для меня. Я беру компонент "symfony/encore", пишу класс, который работает с манифестом, и там в энкоре уже есть как watch, так и listen.

    Не то чтобы это правильно, но это просто чуть быстрее, чем вдуплять чего там яваскриптеры (у которых стандарты программирования (читай: последовательность мыслей) или возводятся в абсолют до тайпскрипта или вообще отсутствуют) позволили конфигурировать и как это в компоновке с вебпаком и npm варится.
    Ответ написан
    Комментировать
  • Как грамотно реализовать пагинацию через класс?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Попытка не пытка.

    1. Пагинация (постраничная навигация) НЕ НАСЛЕДУЕТ соединение, а ИСПОЛЬЗУЕТ его. наследовать = быть КОПИЕЙ С ИЗМЕНЕНИЯМИ, использовать = требовать в коде (ЗАВИСЕТЬ). В ООП можно писать "extends" (наследовать), а можно пробрасывать через конструктор (зависимости). То что вы сделали - это использование "наследования" для "зависимости", оно к вам завтра вернется, когда что-то захотите ещё сюда всунуть, как будете второе наследование делать?

    2. Размышляйте так. Чтобы сделать навигацию вам нужно:
    1 - имя таблицы
    2 - число страниц
    3 - отступ, чтобы переходить на вторую страницу
    4 - (необязательно) SELECT COUNT результатов, чтобы показать сколько всего страниц
    5 - фильтр, чтобы скрыть ненужные результаты (самый прикол в том, что фильтр универсальный сделать не выйдет, т.к. придется написать SQL заново, он весь про фильтры)
    6 - сортировка, чтобы выдать в нужном порядке (бывает несколько-ступенчатая сортировка "сначала-по-подгруппе-потом-по-цене", но её никто никогда не делает, лень правит мир)

    Вы здесь крышей упадете писать одну функцию, которая делает это всё.

    К человекам здесь пришло понимание, что нужно передавать "недоделанный" запрос из функции в функцию, дописывая в него кусочек. Для удобства запрос оборачивают в объект, которые называют Query.

    Если вы пытаетесь сделать на чистом SQL запросы - вам придется очень многое изучить. Поэтому как решение я предлагаю такую последовательность действий:
    1 - Изучаете, что такое composer, ставите в ваш проект какой-нибудь пакет (пока любой, например, symfony/var-dumper), добиваетесь что работает функция dd() (этот пакет её содержит, вам не нужно функцию создавать) в вашем коде. На самом деле там один консольный вызов и одна строка в коде, там нет "методики на 40 действий"
    2 - ставите пакет illuminate/database
    3 - гуглите статью "eloquent without laravel"
    4 - создаете модельку под вашу таблицу
    5 - на модельке вызываете метод ->paginate(), где его для вас заботливо написали
    6 - и только здесь начинаете изучать детали, которые хотели выучить сразу, чтобы сделать не просто пагинацию, а фильтруемую и сортируемую пагинацию (если оно надо). Скорее всего у вас появятся классы FilterBuilder, SorterBuilder, PaginationBuilder и Pagination, в которой будет метод вроде ->paginate($query, $paginationBuilder)
    7 - что такое паттерн "строитель" (Builder) читать на https://refactoring.guru

    У вас долгий путь впереди. Если вы делаете задачу впервые, возможно, вы ушатаете неделю или полторы.

    3. Кое-что о запросах. Пагинация с OFFSET имеет смысл только в очень простых запросах. На практике запросы имеют UNION, JOIN и "subquery", чтобы собирать данные, и кое-где работать не будет. Рекомендуется либо сразу оттолкнуться от (id > ?) вместо OFFSET (а заодно охренеть от того, что "айди больше" + "сортировка" опять не пашут, то есть вам по сути надо сделать "rowNum > ?", но почти все СУБД не дают такого параметра и придется КЕШИРОВАТЬ сделав запрос первый раз тяжелый, а следующий раз выбирать номер результата в кеше), либо делать велосипед с выгрузкой результатов в файл, например, и потом с помощью условного $splFileObject->fseek() выбирать прямым указанием номер первой строки и число результатов после (сложнее, веселая задачка потренироваться, на практике - создает больше гемора, чем пользы)
    Ответ написан
  • Как запустить файл.py с помощью php?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Попробуйте proc_open() вместо shell_exec(), и не забывайте прокидывать в него $env и $cwd. У вас хоть поток stderr будет, откуда можно почитать что там сломалось.

    Посмотрите, как реализовано, но я там пока с логгерами натупил, выключить нельзя, так что скопируйте код.
    https://github.com/6562680/support/blob/main/src/X...
    https://github.com/6562680/support/blob/main/src/X...
    Ответ написан
  • CQRS/ES (или это EventDriven вообще) - Кто поможет разобраться с терминами?

    gzhegow
    @gzhegow Автор вопроса
    aka "ОбнимиБизнесмена"
    Вопрос все еще открыт.

    Из того к чему пришел опрашивая несколько человек (среди них два архитектора, два сисадмина и два программиста):

    - в идеи нет никакой магии. простейшая реализация - закидываем код проекта в github, запускаем его на двух машинах вместо одной, просто вместо http-роутера мы используем message-брокер + eventbus, и соотственно каждая из машин обслуживает свои роуты. придумывать "ивенты" которые продвигают рабочий процесс, где один ивент является началом другого рабочего процесса - сулит головняк, такой же как если бы мы в пхп не использовали классы-сервисы, а вообще всё и всегда делали на ивентах. задолбались бы и запутались кто начало кто конец.

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

    - брокеры сообщений. краткий обзор их такой - они работают всегда в одном из трех режимов. первый - сообщение:
    1) "точка-точка" - "я отослал, ты придешь - получишь".
    2) "трансляция" - я вещаю, кто хочет слушает, кто не пришел - пропустил
    3) "трансляция-точка" - я вещаю, все слушают, кто не пришел - получит когда подключится.
    Команды работают в режиме "трансляция-точка", ивенты "трансляция", уведомления "точка-точка".
    Если бы мы делали хранение истории транзакций - то здесь ивенты должны работать в "трансляция-точка", ведь нам нельзя потерять ни один из них, их надо в постоянный ящик сохранить. Ещё в брокерах есть понятие "подтверждение". Это про надежность. После получения сообщения если выставить режим работы "нужно подтверждать" - непрочитанное удаляется только тогда, когда его подтвердили, иначе запихивается обратно в канал, причем не "следующим", а по временной марке на свое место. Это нужно там где есть "входящая точка", и да, если команда вернула "готово" или "невозможно" - сообщение подтверждается, если команда вернула "перебой связи" и "что-то пошло не так" - сообщение не подтверждается.

    - параллелизация. пока не понятно, какие проблемы вызовет параллель всего, попробую методом тыка. Когда мы использовали роутер - параллелизацией занимался nginx/fpm запуская десяток процессов. И если "обновить заказ" запускалось раньше чем "создать его", мы справедливо получали ошибку мол "невозможно" или "заказ не существует". Когда у нас есть брокер - то параллельно будут созданы "джобы" на первой машине, и их нужно резолвить на второй. Если мы дальше синхронно будем выполнять команды - это будет дольше, чем раньше, пользователей много, а поток всего один. Нам нужно их выполнять точно так же параллельно, только без nginx, а вручную, используя "ext-pcntl" для unix или "composer require react/async" для windows.

    - не путать event-sourcing и event-driven-design (что я и сделал в начале топика). ивент сорсинг в широких кругах известен как "история транзакций". Что получается, когда мы все приложение делаем в режиме "история транзакций" - получается биткоин. Кто-то миллионер, а вся планета тратит электричество на расчет его данных и мощностей все равно не хватает. у вас есть своя планета с людьми и компьютерами? думаю, пока нет.

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

    Поправляйте кто знает.
    Ответ написан
    Комментировать
  • Где хранить идентификатор оповещений(событий) пользователя?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Если "уведомление пользователя", то клиент всегда отсылает "кто он".
    На этот флаг можно привязать положить куда хочешь.

    Это значит - можно в редис. Можно в мемкэш. Можно в базу. Можешь в сессию.

    Быстрей работает мемкеш (оператива работает быстро).
    На втором месте редис (тоже оператива, но еще и включенная программа, которая получает запрос).
    На третьем файловая система (файловый кеш по ключу notifications.user_id, ssd диск все равно медленнее оперативы)
    На четвертом - база (все равно файлы только еще процессинг запроса).

    Но вся эта дичь имеет смысл на безумных количествах запросов. Даже для тысяч юзеров в день вообще пофиг.
    Ответ написан
    Комментировать
  • Как выполнять SOAP запросы в нескольких параллельных потоках?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Если SOAP запрос не удастся сделать через Curl, сделав все заголовки ручками, то установите "composer require react/async".

    <?php
    
    $loop = Loop::get();
    
    $limitThreads = 3;
    
    $soaps = [
      // ...
    ];
    
    $tasks = [];
    
    $limit = $limitThreads;
    while ($limit--) {
       $soap = array_shift($soaps);
    
       $tasks[] = function () use ($soap) {
         // do soap request...
         return $result = doSoapRequest($soap);
       };
    }
    
    if ($tasks) {
      $results = await(parallel($tasks));
    
      foreach ($results as $result) {
        var_dump($result);
      }
    }
    
    $loop->run();
    Ответ написан
    Комментировать
  • Как переключить устройство, вставленное в Jack 3.5 на микрофонный/линейный вход в android?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Есть Virtual Audio Cable для компьютеров, она не то что переопределяет, она умеет создать виртуальный-повторитель, который входной и выходной сигнал может смиксовать на другое виртуальное устройство, которое потом выбирается в винде как "основное" и работает будто так и было.
    Ответ написан
  • Как узнать количество уникальных результатов random.shuffle?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    import itertools.
    itertools.permutations.
    Ответ написан
    Комментировать
  • Как получить GET параметры?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    решетка на сервер не передается, это чисто клиентская хрень.

    нужно на яваскрипте делать.
    Ответ написан
    Комментировать