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

    @Flying
    Парсинг больших файлов осуществляется в потоковом режиме. Для XML существует стандарт потокового парсинга - SAX. В PHP есть стандартный модуль, реализующий SAX через libxml2.

    Для реализации именно фоновой обработки может быть множество различных подходов в зависимости от вашего приложения: это и банальный запуск задач по cron'у и организация очередей и т.п., есть масса информации по этому вопросу.

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

    Также хочу заметить что парсинг 200мб XML - не та задача которая требует отображения прогресса т.к. сам процесс парсинга будет занимать максимум единицы секунд, а скорее ещё быстрее. Больше времени может уйти на загрузку этого файла, или сохранение / обработку данных, полученных из XML, возможно вы это имели в виду?
    Ответ написан
    4 комментария
  • Почему советуют не выбирать yii2 для разработки?

    @Flying
    Даже если не учитывать массу очень дельных аргументов в других ответах - начинать новые проекты на Yii2 не стоит уже по той причине что 2-я версия уже почти два года официально находится в состоянии feature freeze т.е. по сути не развивается. Два года - огромный период в IT, к примеру поддержки только вышедшего PHP 7.4 и, тем более, 8-й версии там можно уже не ждать.

    Т.е. поддерживать уже имеющиеся проекты там ещё можно, но начинать новое лучше на framework'е у которого есть активная разработка и понятный план развития. В этом плане наиболее предсказуема Symfony.
    Ответ написан
    1 комментарий
  • Как сравнить строки в PHP?

    @Flying
    PHP поддерживает сравнение объектов DateTimeInterface напрямую, в данном случае стоит пользоваться именно этим:
    $format = 'd.m.Y H:i';
    $tz = new DateTimeZone('UTC');
    
    $d1 = DateTimeImmutable::createFromFormat($format, '01.01.2019 15:24', $tz);
    $d2 = DateTimeImmutable::createFromFormat($format, '02.01.2019 13:56', $tz);
    
    $newer = $d1 >= $d2 ? $d1 : $d2;
    echo $newer->format(DATE_ATOM);
    Ответ написан
    Комментировать
  • Какие принципы SOLID здесь нарушены?

    @Flying
    С моей точки зрения здесь в первую очередь нарушается S (принцип единственной ответственности). Box в целом не должен уметь что-то кроме хранения фигур. Как правильно заметил vgbege - из задачи не следует что в дальнейшем вариантов подсчёта каких-то метрик по фигурам с Box'е не станет больше, так что в первую очередь я бы выносил отдельно калькулятор. Также у вас нет обобщающего интерфейса для IArea и IShape из-за чего и возникает путаница в addShape.

    В целом у меня получилось нечто подобное:
    /**
     * Основной интерфейс для всех фигур которые можно хранить в Box'е
     */
    interface IFigure
    {
    
    }
    
    /**
     * Интерфейс для фигур которые могут обладать площадью
     */
    interface IArea extends IFigure
    {
        public function getArea(): float;
    }
    
    /**
     * Интерфейс для фигур которые могут обладать цветом заливки
     */
    interface IFillColor
    {
        public function setFillColor(string $color): self;
    
        public function getFillColor(): string;
    }
    
    /**
     * Обобщённый интерфейс для фигур, обладающих и цветом и площадью
     * По факту, думаю, он не имеет смысла, но нужен по условию задачи
     */
    interface IShape extends IArea, IFillColor
    {
    
    }
    
    /**
     * Коробка для хранения фигур
     */
    class Box
    {
        /**
         * @var IFigure[]
         */
        private $figures = [];
    
        /**
         * @param IFigure[] $figures
         */
        public function __construct(array $figures = [])
        {
            // Добавляем полученные через конструктор фигуры в объект
            // Используем addFigure() чтобы проконтролировать корректность типов
            array_walk($figures, [$this, 'addFigure']);
        }
    
        /**
         * @param IFigure $figure
         * @return $this
         */
        public function addFigure(IFigure $figure): self
        {
            $this->figures[] = $figure;
            return $this;
        }
    
        /**
         * @param IFigure $figure
         * @return bool
         */
        public function hasFigure(IFigure $figure): bool
        {
            return in_array($figure, $this->figures, true);
        }
    
        /**
         * @param IFigure $figure
         * @return $this
         */
        public function removeFigure(IFigure $figure): self
        {
            $this->figures = array_filter($this->figures, static function (IFigure $f) use ($figure) {
                return $f !== $figure;
            });
            return $this;
        }
    
        /**
         * @return IFigure[]
         */
        public function getFigures(): array
        {
            return $this->figures;
        }
    }
    
    /**
     * Интерфейс для калькуляторов фигур в Box'ах
     */
    interface IFigureCalculator
    {
        /**
         * @param Box $box
         * @param mixed ...$args
         * @return mixed
         */
        public function calculate(Box $box, ...$args);
    }
    
    /**
     * Пример калькулятора
     */
    class AreaCalculator implements IFigureCalculator
    {
        public function calculate(Box $box, ...$args): float
        {
            // Получаем список фигур которые обладают площадью
            $figures = array_filter($box->getFigures(), static function (IFigure $figure) {
                return $figure instanceof IArea;
            });
            // Получаем цвет из дополнительных аргументов калькулятора
            $color = array_shift($args);
            if ($color) {
                // У нас задан цвет, фильтруем фигуры по цвету
                $figures = array_filter($figures, static function (IFigure $figure) use ($color) {
                    return $figure instanceof IFillColor && $figure->getFillColor() === $color;
                });
            }
            // Подсчитываем суммарную площадь
            return array_reduce($figures, static function (float $area, IArea $figure) {
                return $area + $figure->getArea();
            }, 0);
        }
    }


    В качестве альтернативы я рассматривал также вариант дать Box'у возможность самому считать метрики через создание у него метода:
    public function calculate(IFigureCalculator $calculator, ...$args)

    но потом решил что лучше не захламлять интерфейс чтобы не усложнять логику.
    Ответ написан
    7 комментариев
  • Как на php ставить задачи в очередь например при парсинге сайта?

    @Flying
    Подобная задача решается через т.н. брокеры сообщений (Message broker). Есть несколько возможных вариантов, к примеру выделенные сервера, реализующие протокол AMQP (например RabbitMQ, ActiveMQ и другие), стриминговые сервера (к примеру Kafka), сервисы очередей (Amazon SQS и подобные), а также другие реализации паттерна PubSub, к примеру в Redis.

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

    В вашем сценарии скорее всего будет подразумеваться две очереди:
    1. Очередь задач на scraping. а которую подписываются множество worker'ов, осуществляющих непосредственный сбор данных
    2. Очередь с результатами сбора данных, куда worker'ы будут скидывать данные и на которую подписываются обработчики, решающие что же делать с данными дальше

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

    Для PHP существуют немало binding'ов к серверам, реализующим message brokering. Не знаю что именно на сервер вы выберете, поэтому навскидку приведу php-amqplib/php-amqplib для работы с AMQP (в первую очередь с RabbitMQ), enqueue/amqp-tools (также для AMQP) и superbalist/php-pubsub для реализации PubSub паттерна, к примеру через Redis.

    Вы не указали на чём написан ваш проект, но в целом также можно посмотреть в сторону компонента Messenger для Symfony, его можно использовать и вне Symfony и он даёт хорошую базу для реализации схем обмена сообщениями.
    Ответ написан
    3 комментария
  • Как мне убрать все эмодзи?

    @Flying
    Я в проекте для этой цели использовал пакет hidehalo/emoji, работает весьма неплохо.
    Ответ написан
    Комментировать
  • Как подсчитать при помощи php количество дней от рождения человека?

    @Flying
    $birthday = 19880315;
    $age = (new DateTime('now'))->diff(DateTime::createFromFormat('Ymd',(string)$birthday), true)->y;
    Ответ написан
    Комментировать
  • Как побороть, что fputcsv добавляет словам с пробелами двойные кавычки?

    @Flying
    Это связано с форматом CSV как таковым :) А также со значением аргумента $enclosure который вы, очевидно, оставили по-умолчанию. Всё это есть в документации.
    Ответ написан
  • Какое максимальное колво переменных можно передать в фунцию в регулярных выражениях?

    @Flying
    Поскольку PHP использует библиотеку PCRE, то логично искать ответ на этот вопрос в документации библиотеки. Он находится на странице описания лимитов и количество равно 65535.

    Я не могу сходу придумать задачу где потребовалось бы больше, равно как и с трудом представляю себе отладку подобного регулярного выражения. Однако если такая задача действительно есть - стоит выбирать более крупные куски основной регуляркой, а затем разбирать их дополнительными.
    Ответ написан
    5 комментариев
  • Почему не подключается xDebug к php 7.3?

    @Flying
    Причина в том что вы пытаетесь установить XDebug как обычное расширение PHP в то время как этот модуль является т.н. "расширением ядра". Для его установки необходима другая директива в php.ini:
    zend_extension="/path/to/php_xdebug"
    т.е. просто замените в php.ini extension на zend_extension, перезапустите php / веб-сервер (если они запущены в виде сервисов) и всё должно заработать
    Ответ написан
    7 комментариев
  • Как избежать ошибку 504 Gateway Time-out?

    @Flying
    Судя по 504 Gateway Time-out у вас перед PHP стоит nginx. Если это так - добавьте в конфигурацию сайта настройку для ожидания времени ответа upstream. Если у вас используется FastCGI то:
    fastcgi_read_timeout 30m;
    если используется проксирование, то:
    proxy_read_timeout 30m;

    А вообще такие скрипты запускают не через веб-сервер, а из консоли, устанавливая при этом set_time_limit(0);
    Ответ написан
  • Пройтись по строке и если есть одинаковый символ, exit?

    @Flying
    К примеру эта задача вполне себе решается через регулярное выражение, можно проверить здесь.
    Ответ написан
    1 комментарий
  • Как укоротить регулярное выражение?

    @Flying
    $subject = "23456/10000";
    echo preg_replace('/^(\d{2})(\d{2})/','\1.\2',$subject);
    Ответ написан
  • Асинхронные процессы PHP?

    @Flying
    По сути в данном сценарии можно обойтись гораздо более простым решением: по крону запускать скрипт который будет отправлять все запросы на внутренний сервер с передачей нужных параметров в get/post. Внутренний сервер - nginx + php-fpm которые в связке прекрасно умеют и асинхронность и менеджмент процессов и всё остальное. Дальше по необходимости возможно придётся подстроить параметры количества worker'ов.
    Ответ написан
    Комментировать
  • Придумать логику установки ошибок?

    @Flying
    Вообще подобный workflow обычно реализуется через конечные автоматы. Для PHP есть как минимум две популярные реализации: finite и компонент Symfony Workflow. В последнем точно поддерживаются event'ы.
    Ответ написан
    Комментировать
  • От чего возникает ошибка в PHP?

    @Flying
    Выключена настройка short_open_tag в php.ini, но в целом её использование сейчас считается плохой практикой, стоит использовать полноценный тег <?php
    Ответ написан
    Комментировать
  • Как обработать кириллические хештеги?

    @Flying
    Есть официальная библиотека от Twitter которая, в частности, предоставляет функциональность экстракции хэштегов (пример для JS).

    Если смотреть в код то там будет видно что реальный regexp формируется из кусков и его суммарный финальный размер весьма велик (думаю несколько кб). Кроме того есть ещё одна проблема, уже специфическая для PHP - библиотека PCRE, используемая как движок регулярных выражений для PHP не поддерживает Unicode Surrogates, выдавая для них ошибку Error 73 disallowed Unicode code point.

    Я в своё время для одного проекта конвертировал реализацию из библиотеки Twitter для PHP, если нужно - можно забрать здесь. Там правда есть небольшое отличие в обработке mentions т.к. нужно было учесть специфику Instagram, ну и то что касается специфики работы PCRE, см. выше.
    Ответ написан
    Комментировать