Задать вопрос
  • Где и как лучше прехватывать/обрабатывать исключения?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Главная вещь, которую надо понимать про исключения, это то что они бывают двух основных видов.
    После этого вся обработка становится совершенно естественной и очевидной.

    - Error exceptions, или по простому говоря - ошибки. Обычные ошибки при выполнении программы. Обычно код бросает их сам. Решение "обрабатывать все ошибки через set_exception_handler" будет вполне логичным.
    - Business logic exceptions - это не ошибка в строгом понимании этого слова, а скорее нормальное поведение программы. Ситуация исключительная, но только для бизнес-логики. Их всегда кидает программист.

    И вот просто тупо исходя из того что их два типа, уже можно сказать что единого ответа "где лучше" не существует.
    У каждого типа своя логика обработки. Но при этом, как только ты уложил в голове различия, эта логика становится совершенно очевидной:

    - Error exceptions почти никогда не ловятся через try-catch, по крайней мере на месте. За исключением редких исключительных ситуаций обработка ошибок производится в единой точке, обработчике ошибок
    - Business logic exceptions всегда ловятся через try-catch

    Отсюда мы видим, что

    - //PDOException при коннекте (эммм... я понимаю что пример, но блин, new PDO в конструкторе репы, серьёзно?ладно, мы сейчас не об этом) - это однозначно ошибка
    - //PDOException в запросе - это тоже ошибка, тут два раза думать не надо
    - условно пустое имя. Ну вот здесь мы уже переходим в область бизнес-логики. Коду тут без разницы, пустое имя, или полное. Это важно нам - программисту, пользователю.

    Но тут есть один, блин, тонкий момент.
    Валидация, по сути, пытается разорваться между всеми слоями приложения.
    С одной стороны, это функция Сущности (которую ошибочно называют моделью) - проверять валидность своих данных.
    С другой - если нам надо донести результаты валидации до пользователя, то как быть с переводами? Тащить в модель переводчик, серьёзно? Ну ок, ладно, возвращаем ключи для перевода. Хотя тоже как-то...
    Но вот проверка емейла на уникальность. Её-то где делать?
    В Сущности? И тащить в нее соединение с БД?
    На уровне БД? А где ловить тогда исключение? В сервисе? И ломиться через несколько уровней абстракции к сырому PDOException? Не вариант.
    Или, к примеру, для модели естественно проверять каждое поле отдельно, и кидать исключение. А для пользовательского интерфейса это неприемлемо - надо выдавать все ошибки валидации скопом, а не скармливать по одной.
    Вопросы...

    Но "где валидировать данные" - это отдельная тема, которая не относится напрямую к вопросу "где ловить ошибки".

    В данном случае я предлагаю оставить Сущность Юзер без валидации, а всю валидацию делать в сервисе.

    Хотя опять же - в современных фреймворках валидацию (Не будем показывать пальцем, но это был Ларавель) вообще делают еще до запуска контроллера, в миддлвари. Это кстати спорное решение, которое нарушает целостность модели. Если мы обращаемся к модели через другую точку входа, не контроллер, а, к примеру, создаем юзера через командную строку, то нам нужна точно такая же валидация. Запускать команды через мидлварь? В сущности, это мысль... Но всё равно, мы в итоге бизнес-логику размазываем между моделью и точками входа в неё, а это костыль.
    И при всём при этом оставлять Сущность Юзер совсем без валидации тоже как-то не комильфо... А если оставлять - то получится по сути дублирование кода.
    Вопросы, вопросы...

    Но вернемся к нашим баранам, в смысле юзерам.

    Начнем с того, что проверка имени на равенство пустой строке или нулю - это какой-то детский лепет (и кстати, почему ноль нельзя? вот у Маска ребеночка зовут X Æ A-12 - почему у кого-то не может быть имя "0.0"?).

    Отдельно побурчу насчет empty. Вообще, это один из самых сложных операторов, на нем спотыкаются все поголовно. В частности,
    function f($name){
        if (empty($name))...

    - это бессмыслица. Звучит, в переводе на русский, немного шизофренически: "пусть у нас будет переменная $name. Если у нас нет переменной $name...". Ну как нет, если мы только что ее в функцию передали?
    empty() проверяет переменную на существование И "пустоту". И в данном случае первая проверка будет бессмысленной. Никогда не надо писать бессмысленный код.
    Поэтому логичнее будет написать просто if(!$name). Хотя по нынешним временам это тоже говнокод. Что мы имеем здесь в виду? Имя не может быть пустой строкой? Пустым массивом? Нулём? null? false? А true или заполненный массив - это, получается, хорошее, годное имя?
    Лучше все-таки четче определять свои претензии. К примеру, проверять длину строки.

    У имени можно сделать миллион проверок: Минимальную длину, максимальную длину. Проверить что это строка, а не массив, в конце концов, и не булево значение.
    И так по каждому полю.
    То есть, по-хорошему, валидация данных на соответствие правилам бизнес-логики - это отдельный большой бизнес!

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

    class ValidationError extends Exception{ ... };
     
    class User
    {
        private string $name;
    
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    }
    
    class UserRepository
    {
        public function __construct(PDO $pdo)
        {
            $this->builder = $pdo;
        }
        public function add(User $user): User
        {
            $saved = $this->builder->query('INSERT INTO users (name) VALUES ("user")'); //PDOException
        }
    }
    
    class UserSerivce
    {
        private UserRepository $repository;
        private Validator $validator;
    
        public function new(array $data): User
        {
            $rules = [...] ;
            $errors = $this->validator->validate($data, $rules);
            if ($errors) {
                throw new ValidationException("", $errors);
            }
            $user = new User($data['name']); // в принципе, сучность может здесь бросить своё ValidationException
            return $this->repository->add($user);
        }
    }
    
    class UserController
    {
        private UserSerivce $service;
    
        public function store(array $data)
        {
            try {
                $user = $this->service->new($data);
            catch (ValidationError $e) {
                // рассказываем юзеру что он дурак
            }
            return redirect()->to('/' . $user->id);
        }
    }


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

    Как можно заметить, вот весь этот длинный и путанный текст посвящен исключительно ошибкам бизнес-логики.
    Поскольку с ошибками кода всё куда проще - единый хендлер тупо их обрабатывает в одном месте, как описано в статье по ссылке @Spartak-2205
    За исключением редких случаев, когда они ловятся по месту. Когда ошибка некритичная, или есть сценарий обработки - например, попробовать выполнить то же действие еще раз.
    Ответ написан
    3 комментария
  • Можно ли использовать die при валидации?

    Помимо уже перечисленных проблем, отметил бы ещё тестирование. В случае с PHPUnit, покрыть тестами код содержащий die или exit весьма затруднительно, так как такое завершение скрипта приведёт в том числе и к завершению скрипта теста.
    Ответ написан
    Комментировать
  • Битрикс отваливаются JS события на сайте?

    BornToFreeFall
    @BornToFreeFall
    Sielu ilman ihmistä
    Как уже отметил no_one_safe - использование "Asset::getInstance()->addJs" пригодно лишь в тех местах кода, которые не подвергаются всяческому кэшированию. Воспользуйтесь component_epilog.php вашего компонента. В самом же компоненте JS код подключается с помощью метода "addExternalJs". Ссылка на bitrix info Click
    Ответ написан
    Комментировать
  • Bitrix как же на нем правильно разрабатывать?

    @ZardoZAntony
    программист, сис. админ
    Делают везде как бог на душу положит. Тоже много где работал по битриксу.

    Стиль разработки, который задуман битрикс - это лучший варинат для разработчиков фулстеков или фронтендеров, которые хотя бы сдали экзамен по внедрению верстки. Он не грузит лишний js и css там где он не нужен. И чем больше проект, тем большее это благо.

    Вообще все проблемы людей, которые любят собирать всё в один js и один css файл - незнание архитектуры той CMS, с которой он работает. Тем более почти всегда это тупо верстальщик, который не знает куда пойдет его верстка, да и знать не хочет. Использовать BX он так же не умеет, что в итоге приводит к тому, что куча его скриптов и форм являются неудобными в применнии, т.к. есть гораздо более удобные нативные вещи. Это особо касается корзины и чекаута.

    Но скажу по секрету - webpack так же можно настроить, что он будет генерить шаблоны компонентов в нужных папках с стилями и js, а общие стили генерить в общие css и js. А фронтендер может по прежнему работать со своим postcss и ejs. Но да, чтобы настроить скрипты нужен спец по битриксу.

    У меня был большой проект на оптимизации, где я избавлялся от такой сборки и раскидывал все по компонентам. Почему? А как вам css+js - 27 мегабайт? Потом он со временем слез с битрикса, т.к. уже достаточно разросся.

    Какой вывод? За работу со сложной CMS берутся люди, которые не имею необходимых знаний по работе с ней, вот и начинают ругать битрикс. Нечего на зеркало пенять...
    Ответ написан
    5 комментариев
  • На чем лучше писать аналог Aliexpress?

    @caballero
    Программист
    человеку который не знает на чем писать рановато создавать аналоги алиэкспрес
    Ответ написан
    Комментировать
  • Почему не работает контактная форма (код php и html)?

    @66demon666
    Сетевой админ, АТС-админ
    Ну как минимум у вас в html и php имена полей формы не совпадают
    Ответ написан
    6 комментариев
  • Какое создать регулярное выражение?

    dollar
    @dollar
    Делай добро и бросай его в воду.
    Главное, чтобы было четыре секции между двоеточиями.

    Если это главное (и единственное) требование, то сами секции задаются как раз этим двоеточием. Поэтому банальное (но пока что ошибочное) рег. выражение:
    .*:.*:.*:.*
    Двоеточие в этом выражении соответствует двоеточию в исходной строке. Поэтому строка a:b:c будет не валидной - слишком мало секций. Выражение .* означает любое количество любых символов. Ошибка здесь в том, что любым символом также может быть двоеточие, поэтому это регулярное выражение разрешает более, чем 4 секции. Чтобы исправить это, нужно запретить символ двоеточия в последовательности любых символов. Выражение [^:] означает любой символ, кроме двоеточия:
    [^:]*:[^:]*:[^:]*:[^:]*

    Остался последний штрих. Пока что это рег. выражение всё ещё разрешает более одной секции, потому что поиск можно начинать с середины строки и заканчивать, не доходя до конца. Поэтому если подсунуть строку a:b:c:d:e:f выражение убедится, что подстрока a:b:c:d соответствует рег. выражению, а значит валидна. Чтобы исправить это, нужно указать, что проверку нужно начинать с самого начала строки и дойти до самого конца строки. То есть рассматривать строку целиком, а не по частям. Это делается с помощью указателей позиций. Символ ^ (в начале) означает начало строки, а символ $ (в конце) означает конец строки:
    ^[^:]*:[^:]*:[^:]*:[^:]*$

    Собственно, это и есть правильный ответ в общем виде на вопрос с главным требованием. Секции ровно четыре и они разделены двоеточием. В каждой секции двоеточие запрещено. Выражение [^:]* означает любое количество любых символов, кроме двоеточия, что нам и нужно.

    Однако данное выражение можно немного улучшить, в зависимости от дополнительных требований. Например, нас может не устроить, что для каждой секции считается валидным любое количество символов, даже нулевое. То есть строка a:b::c тоже будет валидной. Для этого нужно сменить квантификатор * на какой-либо другой. Например, можно сменить на +, который означает любое количество вхождений (символа) больше нуля, то есть 1 и более:
    ^[^:]+:[^:]+:[^:]+:[^:]+$

    Далее, может быть желательно выделить группы, чтобы рег. выражение не только проверяло исходную строку на соответствие шаблону ip:port:user:pass, но и извлекало эти самые переменные. Группы задаются просто скобками. Очевидно, что разделители и указатели позиций в группы не входят:
    ^([^:]+):([^:]+):([^:]+):([^:]+)$

    Далее можно вспомнить, что параметр port может содержать лишь арабские цифры. В регулярных выражениях \d (или [0-9]) означает любую цифру. Так что легко вносим улучшение:
    ^([^:]+):(\d+):([^:]+):([^:]+)$
    Хотя постойте-ка. Это ещё не всё с параметром port. Ведь абсолютное любое число, состоящее из цифр, нас не устроит. Как минимум, порт не может быть больше 65535, поэтому любое число выше считается ошибкой. В принципе, на данном этапе можно не заморачиваться и просто проигнорировать это требование, а реально проверить его позже кодом типа такого: $post < 65356, но в качестве примера можно всё же ограничить количество цифр от 2 до 5:
    ^([^:]+):(\d{2,5}):([^:]+):([^:]+)$
    Квантификатор {2,5} означает, что количество вхождений (цифр) должно быть не менее 2 и не более 5, иначе секция будет считаться не валидной, а значит и вся строка тоже.

    Далее, можем также сделать более строгое условие для параметра ip. Для простоты будем считать, что разрешён только IPv4, а IPv6 нельзя использовать. Тогда условием будет 4 цифры, разделённые точкой. Каждая цифра от 1 до 3 символов:
    \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}
    Ой, ошибочка вышла! Дело в том, что символ . является квантификатором. И чтобы рег. выражению сказать, что нам нужен сам символ точки, нужно его экранировать: \.
    В результате полностью рег. выражение получается таким:
    ^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{2,5}):([^:]+):([^:]+)$


    Да, получился монстр. Но нет предела совершенству.

    Правда, на этом этапе улучшать проверки уже не целесообразно. Далее уже кодом PHP можно проверить более строги условия. Например, сейчас в качестве ip будет валидной строка 300.400.500.600. Ведь всё сходится - 4 числа, разделённые точкой, в каждом от 1 до 3 цифр. Поэтому нужно либо более монструозное выражение лепить, либо кодом проверять, либо отдать на откуп сетевым ошибкам подключения - зависит от конкретного приложения и конкретной задачи.

    Рег. выражения не заточены на сравнение чисел, например. Чтобы проверить, что число находится в диапазоне от 0 до 255, придётся лепить что-то такое:
    (?:\d\d?|[0-1]\d\d|2[0-4]\d|25[0-5])
    То есть это вообще поразрядная проверка. Глупо. Проще это делать кодом, если это действительно нужно.

    На данном же этапе имеет смысл проверять лишь то, подо что заточены регулярные выражения. Например, можно ограничить класс символов, которые входят в user и в pass. Например, в пароле можно разрешить только латинские символы и цифры, а также ограничит длину: пароль не может быть меньше 6 и не может быть больше 32 символов:
    [a-z0-9]{6,32}
    (просто пример)

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

    JaxAdam
    @JaxAdam
    Junior Full-Stack Developer
    ORDER BY, LIMIT
    Ответ написан
    Комментировать
  • Как сформировать список товаров из JSON и вывести на страницу через PHP?

    Awilum
    @Awilum
    Частный разработчик, ментор и преподаватель курсов
    тут все ответы https://www.php.net/
    Ответ написан
    Комментировать
  • Как сформировать список товаров из JSON и вывести на страницу через PHP?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Фантастический вариант - изучить PHP, HTML и CSS, написать всё самостоятельно.
    Реалистичный вариант - заказать разработку на фрилансе.
    Ответ написан
    1 комментарий
  • Как правильно оформить метод?

    Тут всё просто
    В методе load нужно написать код для открытия файла, а в методе save для сохранения файла
    Ответ написан
    Комментировать
  • Книги по созданию сайтов на PHP?

    @posters
    Я тоже когда-то как вы размышлял. Только вот программирование это не то, чему можно научиться "пошагово". Можно конечно смотреть какую-нибудь серию видеоуроков, где автор лепит свой интернет-магазин, только вот в программировании главное это понимание. Программирование, это не какая-то механическая работа, вроде сборки шкафов по инструкции. Тут думать надо и тупо повторяя за кем-то, копируя куски кода из уроков, вы программированию не научитесь. У вас просто понимания того что вы делаете не возникнет. Потом нужно будет сделать что-то свое, не описанное в уроке, и вы тупо не будете знать как.
    Ответ написан
    1 комментарий
  • Как загрузить страницу со скроллом на определнный id на Nuxt/Vue?

    dicem
    @dicem Автор вопроса
    Решил эту проблему следующим способом, делаем в @/app/ файл router.scrollBehavior.js

    Далее там проверяю куда ведет роутер, если до нужного мне роута, то возвращаю в качестве position объект с селектором который мы передали в params роута.
    @/app/router.scrollBehavior.js
    export default function(to, from, savedPosition) {
    	const toName = to.params.name
    
    	if (to.name === 'menu-name') {
    		let position = { selector: `#${ toName }` }
    
    		return position
    	}
    }


    UPD: https://nuxtjs.org/docs/2.x/configuration-glossary...
    Ответ написан
    Комментировать
  • Как создать дополнительную страницу для товара?

    @PetrPo
    добавь свое правило question
    "SEF_URL_TEMPLATES" => array(
    	"sections"=>"",
    	"section"=>"section/#SECTION_CODE#/",
    	"element"=>"kkm/#ELEMENT_CODE#/",
    	"compare"=>"compare/",
    	"smart_filter"=>"section/#SECTION_CODE_PATH#/filter/#SMART_FILTER_PATH#/apply/",
    	"question" => "kkm/#ELEMENT_CODE#/question/"
    )


    Потом в шаблоне компонента каталога добавь файл question.php, в нем размести news-list с выводом нужной инфы
    Ответ написан
    Комментировать
  • Как определиться со стеком для торговой площадки(marketplace)?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега Веб-разработка
    Главный вопрос: какой стек я знаю лучше всего из тех, которые имеют необходимый функционал.

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

    Количество посетителей почти не важно, потому что почти на любом стеке можно сделать как плохо, так и хорошо.
    Ответ написан
    Комментировать
  • Можно как-нибудь оптимизировать цикл?

    maddog670
    @maddog670
    $arr = array("hello" => "world", "how" => "are", "you" => "dude");
    echo str_replace(["&", "?"], '', http_build_query($arr));
    Ответ написан
    3 комментария
  • PHP-скрипт полностью не выполняется. Какая причина?

    @vism
    любая, да миллион причин от железа до софта и искать можете от пары часов до пары лет и не найти

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

    через крон например
    Ответ написан
    5 комментариев
  • Как вывести PHP переменную?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Как вывести PHP переменную?

    Ждем вопросов как включить компьютер
    Ответ написан
    Комментировать
  • Можно ли разработать быстрый ИМ на Битрикс?

    shambler81
    @shambler81 Куратор тега 1С-Битрикс
    Все там нормально работает, и 400 тыс тоже может потянуть.
    Вы должны понимать что любой сложный инструмент требует более высокого уровня программиста.
    В противном случае вероятность сделать качественное решение уменьшается.
    Дело не в композите.
    1. Грамотная архитектура технического дизайна рассчитывая его сразу под CSS Framework, тем самым уменьшая количество ненужных css
    2. Учет расположения элементов и способ сборки на Bitrix сайтов, а та-же минимизируя количество тяжелых запросов ( это к любому движку относится)
    3. Кеширование всего живого, в идиале на странице должно оставаться некешируемых 4 хита. - это очень важно!
    4. Грамотно оптимизированый сервер под 1c-bitrix - тоже важно!
    5. Проходите монитор качества перед сдачей проекта ( а желательно сообщить разработчикам о этом в тз ) (особенно пункт кастомизация ядра) !!!!! Иначе плакали все ваши обновления, а желательно отказаться от разработчиков которые туда лезут, что ко сожалению не так редко бывает.
    И будет вам счастье. Битрикс сложная система в нем много возможностей и инструментария, но и ошибок там можно наделать много.
    Не зря он господствует в России на е-комерц рынке.
    Ответ написан