Ответы пользователя по тегу PHP
  • Как в PHP вырезать участок между двумя символами?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    В лоб без сложных ограничений
    <?php
    
    $inp = <<<TEXT
    /**
     * Use the default user interface font in all browsers (opinionated).
     */
    
    html {
      font-family:
        system-ui,
        /* macOS 10.11-10.12 */ -apple-system,
        /* Windows 6+ */ "Segoe UI",
        /* Android 4+ */ "Roboto",
        /* Ubuntu 10.10+ */ "Ubuntu",
        /* Gnome 3+ */ "Cantarell",
        /* KDE Plasma 5+ */ "Noto Sans",
        /* fallback */ sans-serif,
        /* macOS emoji */ "Apple Color Emoji",
        /* Windows emoji */ "Segoe UI Emoji",
        /* Windows emoji */ "Segoe UI Symbol",
        /* Linux emoji */ "Noto Color Emoji";
    }
    TEXT;
    
    $text = preg_replace('!/\*.*?\*/!s', '', $inp);
    
    var_dump($text);
    Ответ написан
  • Почему Unhandled Exception, если оно внутри try/catch?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    У вас Exception из метода resolveClass() не ловится, тк его вызов находится не в секции try{}

    try {
       // тут вызов кода, который может выбить исключение А
    } catch (ExceptionA $e) {
        // если A вылетело, то попадаем в отлове сюда
        // дальнейший код, который может кидать исключения, надо обрабатывать отдельно, 
        // тк тут УЖЕ произошел отлов исключения из секции try, а новые вызовы надо по новой покрывать
    }


    Вообще: управление программой через исключения — плохая практика. Например вот такими вложенными обертками и риск поймать непредвиденное исключение выше
    Ответ написан
    2 комментария
  • Как получился такой результат?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    $sum = function (callable $callback, int|float ...$numbers) — функция принимает другую функцию, какую сделаете и передадите, такая и прийдет (что логично?)

    $sum('foo', 1, 2, 3, 4) — тут немного особенностей PHP, если вызывать как callable строку, то будет вызываться функция с значением из строки в качестве названия, также если как callable вызывать массив с [$obj, 'foo', 1, 'Maks'],
    то будет вызов метода у объекта $obj->foo(1, 'Maks')
    Ответ написан
    1 комментарий
  • Как можно такое реализовать?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Если гибко и универсально, то поможет The ExpressionLanguage Component от Symfony
    Ответ написан
    Комментировать
  • Область видимости метода?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    В пхп классо-ориентированный дизайн —потому "внутри класса" доступно даже приватное состояние другого объекта, если у него тот же тип. То есть инкапсуляция в «схеме» объекта — в классе, а не у самого объекта

    Пример:

    class Bro {
         public function __construct(
               private string $name,
         ){}
    
         public function changeBro(Bro $bro) {
               $bro->name = 'я думал ты бро, а ты не бро';
         }
    }
    
    $maks = new Bro('Макс');
    $roma = new Bro('Рома');
    
    $roma->changeBro($maks);
    
    // теперь у Макса имя другое :)


    такая архитектура языка, объекты разные, а доступ есть
    К слову, это удобная фича… можно сравнить с видимостью в контексте одного package в го :)

    Ну а касательно иерархии типов вам выше накинули — ребёнок всегда является корректным родительским типом, это называю ковариативностью. Любой тигр — кошачьи, а кошачьи — животное, всегда — согласно иерархии типов
    Ответ написан
    Комментировать
  • Как сделать HTTP запрос в angular к php файлу?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    this.http.get('../php/user.php')

    Тут пути идут почему-то относительные, а надо абсолютный относительно корня вашего хоста.
    Если user.php открывается как domain.ru/user.php, то код будет таким

    this.http.get('/user.php')

    ВЫ должны понимать, что ангуляр — фронт, и его код выполняется в браузере, соответственно там нет ваших папок и ваших путей
    Ответ написан
    Комментировать
  • Как в PHP вычисляется count()?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Массив в PHP внутри — хэш-таблица (точнее чуть-сложнее), в ней есть необходимые данные для оптимизаций (отдельно ключи хранятся, отдельно значения и мета-информация, в которой есть все необходимые данные)
    Ответ написан
    Комментировать
  • Зачем в обычном проекте может понадобиться использование __invoke?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    __invoke() метод позволяет превратить объект в функцию, которую мы можем передавать/получать/резовлить через псевдо-тип callable.
    Этакий элемент функционального программирования.

    Хорошо подходит там, где мы выстраиваем pipe или reduce, для описания которых ФП подход является наиболее выразительным и лаконичным. Не знаком с архитектурой Ларавел, но могу предположить, что для авторизации прорисовывается некоторый пайплайн, где можно выполнять разные пайпы или фильтры для првоерки/валидации или чего-либо именно с таким подходом и это более лаконично...

    Пример:
    public function add(callable $pipe) {
        //..
    }
    
    ...
    
    $pipeline = (new Pipeline)
         ->add(fn() => true)
         ->add(fn(bool $enabled) =>'Maks enabled')
         ->add(new MaksHandler()) // тут класс с методом __invoke и работает как анонимка
    ;
    Ответ написан
    32 комментария
  • Как можно ускорить работу Exception?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    на расходы конкретно на исключения для 15 000 вызовов (на каждую строку по 1 исключению) будут около 0.01 секунды (сотая секунды крч) для моего локального компа (много, но и данных много)
    Пруф

    618e769ee759d433078044.png


    $error = $this->handle($json);
    if ($error === '') {
    // логируем что все ок
    } else {
    // логируем ошибку
    }

    Тут заменено не только это, а заменено что-то внутри в handle(), тк не летит исключение

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

    в 15 тыс новых объектов проблемы может не быть. Такие задержки по времени выглядят как проблема на уровне логирования исключений, тк I/O операции над файлом долгие, а сбор трейса исключений и его запись — долгие потенциально.
    Уйдя от исключений вы возможно ушли и от логирования исключений.
    Ответ написан
  • Как задать composer'у proxy в контейнере docker?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Вот корректный образ

    FROM php:8-fpm
    RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer


    Все собирается
    Ответ написан
    Комментировать
  • Как получить даты всех дочерних объектов бинарного дерева?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    У вас корректный код:
    sandbox.onlinephpfunctions.com/code/00ed97cf62c568...

    <?php
    
    class Node{
      private $arr = [];
      
      public function getChildren($node)
        {
    
            if (!empty($node->data)){
                array_push($this->arr, $node->data);
            }
    
            if (!empty($node->left)){
                $this->getChildren($node->left);
            }
    
            if (!empty($node->right)){
                $this->getChildren($node->right);
            }
    
            return $this->arr;
        }  
    }
    
    $node =  createNode(
        6 . '_base', 
        createNode(7 . '_right'),
        createNode(8 . '_left',
            createNode(81 . '_left'),
            createNode(82 . '_right',
               createNode(821 . '_right', 
                    null,  
                    createNode(824 . '_left') 
               )
              
            )
        )
    );
    
    function createNode($data, $right = null, $left = null) {
        $obj = new stdClass();
        $obj->data  = $data;
        $obj->right  = $right;
        $obj->left  = $left;
        return $obj;
    }
        
    var_dump((new Node)->getChildren($node));
    
    // [
    //  "6_base"
    //  "8_left"
    //  "82_right"
    //  "821_right"
    //  "824_left"
    //  "81_left"
    //  "7_right"
    // ]
    Ответ написан
  • Отделение бизнес логики от фреймворка Symfony?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Генератор — просто инструмент для помощи, по итогу сущности чисты, не считая аннотаций/атрибутов для маппинга в ORM, но это просто мета-информации и завязка не существенна (не считая маленького компромисса с ArrayCollection). То есть если вы выберите др ORM, то эти аннотации вам не помешают никак, просто лишние заюзанные классы аннотаций

    Имея сущности доктрины — у нас не связанный от фреймворка код, пишите спокойно бизнесуху, не обращая внимания на то, как оно потом маппится. То есть практически все по каннонам

    Чтобы отделить репозиторий от домена — просто в домене делайте интерфейс, а вот реализация этого репозитория будет в Infrastrucure Layer, но это избыточно... риск минимальный, если сделаете не совсем по канону, а именно риск стоит как основной аргумент такового отделения (не просто же вы словам следуете, а причину понимаете?)
    Разработка строится на компромисах, если смените доктрину на др ORM — так и так писать новые репозиторий, вероятность низкая и многие например не делают такие интерфейсы — слишком усложнит код...
    Вам надо будет просто репозиторий в маппинге ORM\Repository заменить в таком случае

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

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

    617588c41bdde421641847.png
    Ответ написан
    8 комментариев
  • Как инициализировать маршрутизатор Symfony в проекте?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Вам надо поставить еще пару пакетов:
    symfony/config
    symfony/cache
    doctrine/annotations


    по сути с конфигом вы почти симфони заведете в стандартной установке, не считая Request/Response из Symfony Foundation... уже тогда симфу и ставьте

    можете взять пакеты попроще, типа Aura/Slim, там при регистрации приложения просто добавляются новые роуты
    Ответ написан
  • Можно ли использовать сервисы в rich моделях?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    а? Если нет и нужно все равно писать абсолютно всю логику в обьекте модели, то тогда он станет просто god обьектом на 100500 строчек

    Потому что вы все делаете наоборот!

    Пишите по бизнес-процессу ваши UseCase, это некоторый хэндлер к примеру
    Пример
    final class HandleCheckOutShoppingCart
    {
        public function __construct(Carts $carts, PaymentGateway $gateway)
        {
            $this->carts   = $carts;
            $this->gateway = $gateway;
        }
    
        public function __invoke(CheckOutShoppingCart $command) : void
        {
            $shoppingCart = $this->carts->get($command->shoppingCart());
    
            $payment = $this->gateway->captureCharge($command->charge());
    
            $shoppingCart->checkOut($payment);
        }
    }


    Потом у вас вырисовываются границы сущности, и в сущностях уже инварианты, которые контролирует эта сущность. Никаких god object
    Ответ написан
    5 комментариев
  • Есть ли особенности работы Doctrine в долгоживущих приложениях?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Как такое может быть?

    Если вы достаете сущность по id, то она загружается один раз и потом не обращается к БД, следя за изменениями сущности из приложения
    Предлагаю очищать EM после каждой обработки задачи через $em->clear()

    Sometimes you want to clear the identity map of an EntityManager to start over. We use this regularly in our unit-tests to enforce loading objects from the database again instead of serving them from the identity map. You can call EntityManager#clear() to achieve this result.
    https://www.doctrine-project.org/projects/doctrine...


    Чтение можно в обход делать, изменение сущностей лучше не делать в обход EM

    Консьюмеру не хватате параметра какого - то?

    Он считает, что с сущностью вы работаете из приложения, а не в обход
    Ответ написан
    1 комментарий
  • Как сделать такой формат времени?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    у даты есть метод format()

    конкретно для вашего случая будет
    $date->format('c');

    https://www.php.net/manual/ru/datetime.format.php

    615eeda7241e0904013833.png
    Ответ написан
    Комментировать
  • Скажите, а шаблон проектирования (для PHP), где фичи для приложения выносятся в отдельные модули - имеет какое-то название?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    где фичи для приложения выносятся в отдельные модули

    В вопросе уже овтет :):):)

    Package By Feature

    Вот можете посмотреть на примере PHP-проекта от Удальцова Валентина, хорошая попытка (с привязкой по времени):
    https://www.youtube.com/watch?v=2iPNz3p5Xiw&t=3633s

    как разбить приложение на переиспользуемые модули-фичи

    А вот тут сомнения по моему ответу, тк цель обратная — понизить связанность, тогда как переиспользуемость — повышение ее в некотором роде
    Может быть вы сейчас про DRY? Don't Repeat Yourself?
    Ответ написан
    1 комментарий
  • Как добавить синтаксический сахар, связанный с оператором в php?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Проблема 0: В PHP нет перегрузки операторов и магических методов как в Пайтоне под такое дело

    Вариант 1: Условно функциональный
    Можно например так (если конечно вам подойдет)
    $a() - $b()

    Тогда надо просто __invoke() реализовать в каждом из классов

    Плюс такого, что в $a или $b может быть не только класс, но callable
    <?php
    
    class N {
        private int $n;
        public function __construct(int $n = 0) {
            $this->n = $n;
        }
    
        public function __invoke(): int {
            return $this->n;
        }
    }
    
    $a = new N(5);
    $b = fn() => 100;
    
    var_dump($a() - $b()); // -95


    И даже на лету передавать аргументы, например мультипликатор:
    <?php
    
    class N {
        private int $n;
        public function __construct(int $n = 0) {
            $this->n = $n;
        }
    
        public function __invoke(int $multiplier = 1): int {
            return $multiplier * $this->n;
        }
    }
    
    $a = new N(5);
    $b = fn(int $multiplier = 1) => $multiplier * 100;
    
    var_dump($a(100) - $b()); // 400
    sandbox.onlinephpfunctions.com/code/331eef7f9ad530...
    А можно передавать еще callable :) Крч вот вариант функциональный очень гибкий
    Или наоборот в конструкторе зашить мультипликатор, а сами числа передавать на лету, по-разному можно сделать

    Вариант 2: Value Object
    Можно посомтреть как сделан интерфейс например у объекта DateTime и увидеть, как работает diff() (разница времени) и можно сделать похожий интерфейс

    <?php
    
    interface NumericInterface {
        public function add(Numeric $second): NumericInterface;
        public function toInt(): int;
    }
    
    class Numeric implements NumericInterface {
        private $n;
        
        public function __construct($n = 0) {
            $this->n = $n;
        }
    
        public function add(Numeric $second): self {
            return new self($second->n +  $this->n);
        }
        
        
        public function toInt(): int {
            return $this->n;
        }
    }
    
    $num1 = new Numeric(10);
    $num2 = new Numeric(18);
    
    $result = $num1->add($num2)->toInt();
    
    var_dump($result); // 28
    Ответ написан
    1 комментарий
  • Как заставить работать Guzzle асинхронно?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Во время работы с Async Guzzle вам нужен вызов $curl->tick(), чтобы он мог продолжить работу. wait() под капотом делает именно это

    Вот даже есть пример, как интегрировать курл с реакт-пхп и там есть этот тик, который делает движение
    https://gist.github.com/psampaz/7f2aad5d1d54eeeec8...

    use GuzzleHttp\Client;
    use GuzzleHttp\Handler\CurlMultiHandler;
    use GuzzleHttp\HandlerStack;
    use Psr\Http\Message\ResponseInterface;
    
    $curl = new CurlMultiHandler;
    $handler = HandlerStack::create($curl);
    $client = new Client(['handler' => $handler]);
    
    $p = $client
        ->getAsync('http://google.com')
        ->then(
            function (ResponseInterface $res) {
                echo 'response: ' . $res->getStatusCode() . PHP_EOL;
            },
            function (\Exception $e) {
                echo $e->getMessage() . PHP_EOL;
            }
        );
    
    while ($p->getState() === 'pending') {
        $curl->tick();
        // sleep(1);
    }
    echo 'bottom' . PHP_EOL;


    Если у вас синхронный фреймворк, то вам не пройти мимо синхронизации ожидания запроса. Профит в синхронном исполнении от асинхронных запросов есть только тогда, когда есть больше 1 запроса одновременно, тогда время выполнения станет равным самому длинному из запросов и это время придется ждать. Если запрос один — надо все равно прокрутить и дождаться...

    Опишите изначальную задачу, которую преследуете

    UPD после выяснения задачи:

    Задача: рассылать почту, не задерживая клиента
    Типовое решение: Выполнить fastcgi_finish_request и сделать после него отправку почты. То есть после выполнения данной функции идет разрыв с сервером, то есть браузер прогрузится до конца! Но сам скрипт еще поработает до того, как все сделает (и браузер об этом не узнает).

    Можете сообщение записать в БД, а после fastcgi_finish_request всю очередь вычесать и отправить
    Ответ написан
    3 комментария