Ответы пользователя по тегу PHP
  • Как использовать vue с php?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    <?php
    // index.php
    $data = ['any data here'];
    echo base64_encode(json_encode($data));


    // index.js
    fetch('/api/index.php')
      .then(res => JSON.parse(atob(res.json())));
    Ответ написан
  • Какой парсер HTML на PHP выбрать?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Рекомендация Протько устарела.

    Парсер парсит с ошибками, стоит в тексте ссылки попасться &lt; и парсинг уже пошел по трубам, и хотя simple_html_dom заставляет шторм лагать больше, т.к. не поделен на неймспейсы, но работает быстрее, проверено на сайте с 50 тысячами страниц, субьективно simple делал быстрее.

    Сейчас буду искать новый.
    Пока попробую этот: `dimabdc/php-fast-simple-html-dom-parser`
    Ответ написан
    4 комментария
  • Расшифровать хеш?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    <?php
    
    $t = '\u0427\u0435\u0441\u043d\u043e\u043a: \u042e\u043c\u043e\u0440 \u0434\u043b\u044f \u0432\u0437\u0440\u043e\u0441\u043b\u044b\u0445';
    
    var_dump(preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function ($match) {
        return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
    }, $t)); // Чеснок: Юмор для взрослых
    Ответ написан
  • Объясните отрезок кода php?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    <?php
            /** @var bool */
            public $exit = true;
            /** @var bool */
            public $exitFullUsage = false;
            /** @var bool */
            public $help = true;
            /** @var bool */
            public $optionsFirst = false;
            /** @var ?string */
            public $version;


    это объявлены свойства, которые можно будет получить через $object->{ $name }; (потому как они помечены как публичные)
    для удобства работы в PhpStorm и чтения указаны их типы данных, когда часто работаешь с кодом позволяет не тратить время на то, чтобы долго не вкуривать и не разбираться. Достаточно знать что там лежит.

    <?php
          public function __construct($options=array())
            {
                foreach ($options as $k=>$v) {
                    $this->$k = $v;
                }
            }


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

    Но код косячный потому что пхп позволяет обьявлять свойства динамически. То есть даже если поля нет, его можно передать и оно появится. Надо проверять еще
    <?php
    if (! property_exists($this, $k)) throw new \Exception('Нет свойства');
    Ответ написан
    1 комментарий
  • Заполнение формы с переадресацией и автозаполнением полей?

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

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

    Если бы оба сервера твои были - то делаешь на црм-ке поддержку прихода данных и заполнения их автоматом, а потом на проекте 2 скрипт который пересылает на первый
    Ответ написан
  • Как передать id строки таблицы в другой php-файл?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    так она должна быть с бэка отдана при строительстве таблицы и вшита в кнопку Удалить

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

    gzhegow
    @gzhegow Автор вопроса
    aka "ОбнимиБизнесмена"
    Чуть позже обдумав - понял, что правило простое "если А зависит от Б, а Б зависит от А, нужно сделать В, от которого зависит и А и Б".

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

    Что по сути и написал index0h, только в голове не хватало мозайки, что валидатор, проверив путь, должен вернуть "проверенный path", который не нужно проверять в другом классе еще раз.

    устарело

    По проблеме с циклическими зависимостями найдено решение. Кому интересно напишите, расскажу весь путь как шли и почему так. Спасибо Андрей Ковалёв, Алексей Пастушенко, еще один Алексей, Александру Захаренко, Human с t.me@oop_ru канала, Александру Markwhide и Ярославу Кравцову, и еще двум парням в телеге

    1. Циклическая зависимость возникает когда нарушается принцип ООП - в зависимостях должны быть классы, которые меняются достаточно редко - а именно, когда происходит косяк или меняется задача. Не дополняется задача, а именно меняется то что было.

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

    3. В конкретном примере валидатор является сборкой методов, а должен быть их "загрузчиком" - создателем обьектов. Таким образом создавая новые классы мы расширяем валидатор не меняя сам валидатор. Тогда валидатор может быть передан в конструктор, его поведение не меняется.

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

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

    6. В пхп 7.3 ещё нельзя написать такой класс, который одновременно соответствует двум интерфейсам в двух разных модулях (как в фирме контракт нанимателя и контракт сотрудника) - таким образом приходится исходить из того что в рамках модуля зависимости можно переплетать. Есть способ - сделать обертку для класса и сунуть его зависимостью, а уже обертку повесить на собственный интерфейс, но тогда модулю нужен контейнер и конфиг который подсунет модуль в обертку параметром, и выдаст декорированный обьект. Если модулей несколько должно быть ядро, и код можно положить там. То есть модуль будет работать только с ядром. Либо делать компонент валидатора в каждом из модулей и копировать необходимые проверки, тогда модули можно безопасно выдергивать и вставлять. Да. Копирование кода.
    Ответ написан
  • Как сделать сокращение числа?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    количество раз когда после деления на тысячу число получается больше единицы следует прогнать через ключ массива - 3 раза поделилось - значит у нас миллиарды
    Ответ написан
    Комментировать
  • Как отправить письмо на эл. почту средствами php по времени?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Твой принцип работы в этой задаче
    1. создать список с планом отсылки и добавлять туда записи через скрипт 1.
    2. создать скрипт 2 который берёт первый десяток и списка и смотрит, наступило ли время отсылки, затем отправляет те, что уже должны быть отправлены
    3. запускать этот скрипт по планировщику (cron) или через механизм очереди - в этом случае пункты 1 и 3 обьединяются, т.к. стоит тебе сделать 1, как мгновенно выстрелит 3 в отдельной программе никак не знающей о том, кто и когда поставил новую задачу
    Ответ написан
    Комментировать
  • Почему сбрасывается соединение при выполнении php?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Ещё если ты работаешь с прокси частая проблема в том что круто настроенный под скорость nginx обрывает долгие запросы в ошибку 502 (долгие иногда фанатики считают - это 3 секунды). Стоит поиграть с конфигом nginx тоже.

    Если дело в самой проксе и она падает в ошибку, то перед запуском основного запроса рекомендую сделать запрос на какую-нибудь апишку гугла, которая заведомо вернет тебе json что в запросе косяк. Наша задача проверить - вернёт или нет. Если больше секунды выполняется запрос на апишку гугла, то проксю следует поменять на следующую по списку и повторить.
    Ответ написан
    Комментировать
  • PHP обфускатор Как запустить?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Для потомков:

    > php obs.php obs.php obs2.php
    > php obs2.php obs.php obs3.php


    <?php
    
    define('ERR_BAD_EXTENSION', 'ERR_BAD_EXTENSION');
    define('ERR_BAD_USAGE', 'ERR_BAD_USAGE');
    define('ERR_EMPTY_FILE', 'ERR_EMPTY_FILE');
    define('ERR_EXISTS_FILE', 'ERR_EXISTS_FILE');
    define('ERR_NOT_FOUND_FILE', 'ERR_NOT_FOUND_FILE');
    
    $messages = [
    	ERR_BAD_EXTENSION  => 'Incorrect file extension',
    	ERR_BAD_USAGE      => sprintf('Usage: php %s <input file> <output file>', basename(__FILE__)),
    	ERR_EMPTY_FILE     => 'File name should be not empty',
    	ERR_EXISTS_FILE    => 'File exists',
    	ERR_NOT_FOUND_FILE => 'File not found',
    ];
    
    function _error($err, $subject = null)
    {
    	echo PHP_EOL . $GLOBALS[ 'messages' ][ (string) $err ] . PHP_EOL . print_r($subject, 1);
    	die();
    }
    
    function _log($message, $subject = null)
    {
    	echo PHP_EOL . (string) $message . PHP_EOL . print_r($subject, 1);
    }
    
    if (! isset($_SERVER[ 'argv' ][ 1 ])) {
    	_error(ERR_BAD_USAGE);
    }
    
    if (! isset($_SERVER[ 'argv' ][ 2 ])) {
    	_error(ERR_BAD_USAGE);
    }
    
    $from = $_SERVER[ 'argv' ][ 1 ];
    $to = $_SERVER[ 'argv' ][ 2 ];
    
    if (! $from) {
    	_error(ERR_EMPTY_FILE, $from);
    }
    if (! is_file($from)) {
    	_error(ERR_NOT_FOUND_FILE, $from);
    }
    if ('php' !== ($ext = pathinfo($from, PATHINFO_EXTENSION))) {
    	_error(ERR_BAD_EXTENSION, [ $from, $ext ]);
    }
    if (is_file($to)) {
    	_error(ERR_EXISTS_FILE, $to);
    }
    if ('php' !== ($ext = pathinfo($to, PATHINFO_EXTENSION))) {
    	_error(ERR_BAD_EXTENSION, [ $to, $ext ]);
    }
    
    _log('Processing...',
    	[
    		$from,
    		$to,
    	]
    );
    
    $content = ''
    	. 'ob_end_clean(); ?>'
    	. php_strip_whitespace($from)
    ;
    
    $data = ''
    	. '<?php' . PHP_EOL
    	. sprintf('$a=\'%s\';', base64_encode(gzcompress($content, 9)))
    	. 'ob_start();'
    	. 'eval(gzuncompress(base64_decode($a)));'
    	. '$v=ob_get_clean();'
    ;
    
    file_put_contents($to, $data);
    
    _log('Done.', $to);
    Ответ написан
    Комментировать
  • Все значения массива в нижний регистр php?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    В пхп недостаточно удобных "стандартных" функций (в том смысле что хотелось бы больше)

    Если предлагать у них на трекере - они защищаются тем, что тебе нужно подымать голосование RFC чтобы много людей проголосовали "за"

    На текущем уровне разобщенности люди не способны за кого-то голосовать, а шанс что они столкнуться с одинаковой проблемой и тем более осознают что это проблема - вообще никакущий - это заморозило язык, они разрабатывают сейчас проверку типов по интерфейсу в 7.4 и прекомпиляцию исходников, но не делают язык удобнее для тех, кто ещё не освоил ООП)

    Очень часто язык предлагает не лениться писать foreach

    $result = array_map('mb_strtolower, array_map('trim', $arr));
    var_dump($result);


    или

    // передаем по ссылке чтобы заменить на любом уровне вложенности прямо в исходном массиве
    array_walk_recursive($arr, function (&$v) {
      $v = mb_strtolower(trim($v));
    });
    var_dump($arr);
    Ответ написан
    Комментировать
  • Как скачать динамически созданный файл и сделать location этой страницы?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    к сожалению только яваскрипт. ты не можешь отправить файл, а потом сделать редирект. отдача файла это код 200 - все ок. а редирект это 301 код

    логика действий - попробовать сделать как на megashare помоему или какой-то такой известный обменник который отдает файл своим способом, я полагаю он как-то его по кускам передают яваскрипту через вебсокет наверное, а потом соединяют куски файла уже на клиенте и скачивают как бы мгновенно. и после этого мгновенного скачивания - перенаправить человека
    Ответ написан
    Комментировать
  • Для чего используют функции serialize/unserialize?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    ещё чтоб сделать файловый кеш тебе нужно сохранить данные, время жизни и дату сохранения. сами данные в serialize, а массив из трех полей - в json. иначе было бы дважды json и велика вероятность потери
    Ответ написан
    Комментировать
  • Как обойти большой json файл и обновить все связанные записи в MySQL, с отставанием от файла < 2 сек.?

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

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

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

    Ещё можешь свой скрипт на ноде написать, там асинхронка может помочь. или сделать с помощью
    new class extends \Threaded подключив расширение pthreads.so/.dll

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

    Но учитывай, что запись и обновление в SQL все равно ставится в очередь, так что предел скорости присутствует
    Ответ написан
    2 комментария
  • Как выборочно удалить устаревшие кэшированные результаты из базы данных?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Именно так, инвалидация кеша довольно "весёлое" занятие.
    Немного упрощает работу с этим на мой взгляд группировка кешей - это когда кеш хранится не просто в файле или редисе с ключем в виде хеша, а когда он хранится типа такой строкой "models.users.find.city", еще я юзаю бывает константу __METHOD__ магическую - там неймспейс сразу есть (хотя это годится в основном для будущей ручной очистки, чем для автоудаления), осталось примесь добавить в виде параметров под юзера, кстати эта примесь тоже может например base64 стать потом и служить ключем (user:1 -> base64) и потом найти запись где есть такой-то base64. По крайней мере ты получаешь возможность найти все кеши связанные с city и их снести руками.

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

    Опять же есть колхоз на тему сохрани номер сотни пользователя для 912-го - девять. И снеси сотню кешей например. Или тысячу. Всяко лучше чем 100%. Ну и конечно подумать над необходимостью кешировать данные юзеров. Может есть возможность кешировать только неизменяемую часть. Или не кешировать вовсе то, что юзеры постоянно меняют.

    Так например кеш дерева категорий который показывается всем имеет смысл кешировать и очищать. А кеш профиля юзера приведет к тому что для миллиона юзеров миллион кешей, и лучше пусть загружается чем выжрет гиг оперативки под хранение того, что вот вот изменится

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

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

    Но наверняка кто-нибудь знает как проще.
    Ответ написан
  • Как упростить PHP цикл?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Пишу с телефона извините

    Total = 10000
    Max = 200
    While (0 < (total -= (limit = max))) {
    While (limit--) {}
    }

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

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Оттолкнуться от того что пользователь может передать (порядок важен везде, как задали - так и ищем)

    - фильтры (как правило массив критериев [ [ 'hello', 'like', 'world*' ], [ 'item', '>', 100 ] ])
    -- фильтры типа И/ИЛИ/НЕ - как правило отправляются в один уровень, либо вложенным массивом с ключами [ y => [filter,filter], n => [ y => [filter, filter], 'n' => [ filter ] ];
    - сортировку (как правило массив из массивов [ [ 'hello', 'asc' ], [ 'item', 'desc' ] ]
    - лимит записей
    - отступ от начала таблицы
    - номер страницы (отступ = лимит умножить на (номер-1))

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

    Потом написать обертку которая преобразует входящий GET запрос из массива в некий объект который знает про все вышеперечисленное чтобы дальше его передавать.

    Дальше этот объект передается в некий класс, который умеет искать по источнику данных. Репозиторий. И там делаются функции findByCriteria(Criteria $criteria) во все источники данных - где-то в апишку, где-то в базу, где-то в одну таблицу, где-то в другую.

    Задачка которую решает каждый разработчик на ПХП. А единого решения так и нет.
    Причем это не разу не легкая задачка если её видеть в том виде как автор написал.
    Если задача просто из таблицы по условию выдрать - то она упрощается. Не в 2 раза. А в сто-два.

    У архитекторов конечно есть. Иначе они бы не считали себя архитекторами. Но тебе они не дадут. Иначе ты тоже станешь архитектором, а так нельзя.
    Ответ написан
    2 комментария
  • Как реализовать свой абстрактный класс коллекции?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Коллекция это просто пачка. Массив с цифровыми ключами. Бывает двух типов я для себя назвал - массив и список.
    Массив - ключи строго цифровые и строго по порядку.
    Список - ключи строго цифровые но могут идти не по порядку и некоторые из них могут отсутствовать

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

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

    Почему в Ларавеле коллекции? Потому что им надоело прокидывать по ссылке вероятно и писать методы для работы над массивами. Может не смогли разобраться. Может задолбались. Но под капотом эта их штука спамит коллекциями так что страшно думать. $collection->merge() - мы вроде как с обьектами работаем, а значит должно добавить в нашу коллекцию. Но вместо этого она создает вторую коллекцию, а первую - удаляет, чтобы вести себя так, как это было бы с двумя массивами.

    Вот в Ларавеле получается с этим дичь - они начали юзать обьекты, а потом пытаться реализовать поведение по-старинке, как в массивах. И для чего им теперь эта коллекция кроме как для проверки что она такого-то типа - непонятно.

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

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

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

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

    Делим возникающие косяки на:
    1. уведомление разработчика, что программа кривая и так не должно было быть
    2. уведомление/перенаправление пользователя
    3. оповещение других модулей в соседних папках о том, что случилось что-то, что они могли бы решить, но в одиночку никак

    В первую группу в основном падают стандартные эксепшены. Пишем мы функцию
    function a() : int
    {
      return 'vasia';
    }

    Функия возвращает не то, что просили. Об этом должен узнать разработчик, который делает на базе вашего кода. Программа не должна запуститься. Удобный способ делать такие проверки, писать следующий код:
    function verifyEmail($email) : ? string
    {
      if (filter_var($email, FILTER_VALIDATE_EMAIL)) return null;
      return __FUNCTION__ . ' fails: ' . $email;
    }
    // ... code
    if ($err = verifyEmail(123)) throw new \UnexpectedValueException($err);

    Мы возвращаем текст ошибки если проверка не прошла, валидируем.
    Так, например, можно сделать проверку входных параметров на собственный тип не занимаясь ООП ересью на зашивание проверки в конструктор и разбивание массива на свойства, каждое из которых сеттер с валидатором и тд. минус файл и куча логики. Эти ошибки бывают что требуют вывода дополнительной информации в трейс. А поскольку эксепшен не принимает данные дополнительным параметром, я рекомендую дописать функционал `public function data(array $data))` и в особых случаях вызывать throw (new MyException($err))->data($data); и тогда в логах можно добавить эту самую $data не прибегая к танцем с бубном. Она врядли понадобится системному администратору или девопсу, но она точно понадобится тому, кто пойдёт ошибку править. Опять же - в эксепшене есть дерево вызовов и там есть аргументы. Но пару раз по причинам мне непонятным - пыха оставляет там не всё, что я ожидаю там прочитать. В той же валидации аргументом прилетает одна строка, если вывести все дерево - лог будет слишком огромный. А если одну строку - то это ничего не скажет. Чтобы понять, почему валидация сломалась часто нужно увидеть весь входной словарь данных.

    Во вторую группу я отнес ошибки HTTP приложения, приложения как штуки способной принимать команды и отвечать на них. Это разные редиректы. Это 500ые коды сделанные вручную. Это отсутствие прав доступа. Всё что по-любому закончится HTTPException или RedirectBack. Программа запуститься, но ошибка может быть вызвана тем, что во внешних условиях что-то идёт не так - нет прав доступа, или этот кусок программы сейчас отключен. То есть это не косяк кода, а сознательно установленный запрет. Эти ошибки чаще всего нужно переводить на другой язык или писать заглушку. Эти ошибки как правило бросаются фреймворком или приложением, и имеют либо неймспейс как у фреймворка, либо что-нибудь вроде \App\HttpException;

    В третью группу я отнёс ошибки, которые требуют внешних зависимостей. Насчет этой группы я пока не уверен, может быть это из-за того что я неправильно разобрался с первыми двумя. Предположим у нас есть модуль авторизации пользователя и есть модуль для работы с JWT-токенами. Вот когда модуль не смог разобрать JWT токен - он должен кинуть ошибку "я отработал и решил, что что-то пошло не так, но дальше - не моя забота". JWT разбор выполняет очень узкую задачу - парсинг токена. Туда не всунешь зависимостью модуль авторизации, это как поставить директора в подчинение работнику. Можно попробовать НЕ-бросать эту ошибку путем того, что инициировать проверку токена в модуле Авторизации, чтобы прямо там её и обработать. Но это странно, потому что Авторизация может быть сделана десятью путями и каждый из них зависимостью хардкодить - не очень хорошо. Именно эти ошибки должны иметь неймспейс, потому что их будут ловить и с ними работать, пытаясь их заглушить. То есть на уровне модуля - это критическая ошибка. А на уровне программы - это предупреждение.

    На текущий момент мне кажется это правильным подходом. Если найду что-то ещё исправлю.
    Ответ написан
    Комментировать