Это копия, сохраненная 25 марта 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Предыдущий тред был тут: >>1118555 (OP) . Остальные треды есть в архиве: https://phpclub.tech/ или ищутся в гугле по словам "клуб изучающих php" и в архиваче.
Мейлач лежит? Есть запасной тред на доброчане: /s/res/23225.xhtml#i46467
Что самое главное для программиста? Умение аккуратно оформлять код (как, написано во втором посте).
Правила: ведем себя воспитанно, помогаем новичкам, читаем учебники, решаем задачки, постим ссылки на решения, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
С чего начать
У нас есть свои уроки по основам PHP, они собраны и выложены по адресу http://codedokode.github.io/phpbook (вас отредиректит на другой домен, не читайте, не сохраняйте, не запоминайте его, он временный). Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то можно начать с него. Он простой и понятный. Там есть задачи, их нужно решать (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению. С другой стороны, если этот учебник тебе не нравится, можно читать любой другой. Или официальный мануал. Или все сразу.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка PHP, этого недостаточно. Вот что в идеале надо изучить еще: ООП, как работает веб-сервер, HTML/CSS, SQL, PDO, работа с таблицами в БД, работа с формами, MVC, git, composer, JS, фреймворки, автоматизированное тестирование.
Надо переходить к более серьезным задачкам, которые научат тебя всему этому.
- для начала прочти урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- установи Апач + PHP (советы выше и ниже) и читай туториал http://php.net/manual/ru/tutorial.php
- Учи HTML/CSS и SQL, PDO, хотя бы основы
- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Symfony: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование https://gist.github.com/codedokode/a455bde7d0748c0a351a
- Если ты все решил, переходи к Symfony 3/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Параллельно стоит подучивать английский, на первых порах можно без него, но по мере развития придется все чаще сталкиваться с англоязычными статьями, так что лучше не откладывать. Читать можно news.ycombinator.com - это что-то вроде их хабра. Также можно начинать смотреть фильмы и видео на английском.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://github.com/codedokode/pasta/blob/master/db/databases.md
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1
- Новости IT на англ. https://news.ycombinator.com/
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.
Платиновые вопросы
- Почему PHP? Потому что вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery. У нас в треде были люди, которые практически с нуля учились и смогли найти работу.
- Что будут спрашивать на собеседовании если 0 опыта - гонять по теории, по официальному мануалу PHP, давать дурацкие задачки на переворачивание строк, гонять по SQL (транзакции, внешние ключи, напиши запрос), по JS (как сделать анимацию при нажатии кнопки), ну погугли, не ленись
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.
Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492
Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:
- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)
Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:
PSR-1: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
- написал еще комментарии по https://github.com/TheSidSpears/testhub/ >>1135039
- ответил про ER диаграмму базы данных: >>1135042
- проверил задачу про антикризисные меры >>1135043
Если я кому-то не ответил, напомните о себе тут.
а то задача прилетела, а я с синтаксическим разбором никогда не сталкивался
>>1134788
Ты можешь посмотреть в сторону компонента Symfony ExpressionLanguage: https://symfony.com/doc/current/components/expression_language.html - там уже есть парсер выражений. Но если тебе интересно, как вообще это делается, читай пасту:
Разбор выражений делается с помощью синтаксического анализа. Он же применяется, например, при разборе компьютерных программ. Мы определяем "грамматику" (набор правил) и по ней делаем разбор.
Для записи грамматики есть разные стандартные способы:
- BNF https://en.wikipedia.org/wiki/Backus–Naur_form
- EBNF https://en.wikipedia.org/wiki/Extended_Backus–Naur_form
- ABNF https://en.wikipedia.org/wiki/Augmented_Backus–Naur_form (спецификация на рус: https://rfc2.ru/5234.rfc )
- и даже можно использовать регулярки https://habrahabr.ru/post/171667/
Все эти грамматики определяют правила составления конструкций из минимальных неделимых кусочков языка (терминалы) и других составных конструкций. Например, для математического выражения терминалами могут быть числа и знаки арифметических операций, а составной конструкцией - "сумма", определенная как последовательность конструкций ЧИСЛО "+" ЧИСЛО.
Традиционно разбор выражения делают в 2 этапа:
1) В рамках лексического анализа лексер (токенайзер) разбивает выражение на массив токенов (лексем): "-(22 + 2) ^ 3 ^ 4" -> ['-', '(', '22', '+', '2', ')', '^', '3', '^', '4']. На этом этапе числа группируются в токен, удаляются незначащие символы. Токен может быть представлен строкой, массивом, объектом, в зависимости от задачи. Последовательность токенов можно представить в виде массива или объекта.
2) В рамках синтаксического анализа парсер получает на вход поток токенов и строит дерево выражения их узлов. Тут есть разные алгоритмы: https://ru.wikipedia.org/wiki/Синтаксический_анализ
Дерево выражения удобно представлять в виде дерева из объектов-узлов разного типа (AST). Ну например, математическое выражение 10 + 2 + 3 ^ 4 можно представить в виде дерева объектов:
SumNode(
NumberNode(10),
NumberNode(2),
PowerNode(
NumberNode(3),
NumberNode(4)
)
)
Имея такое дерево, мы можем вычислить выражение, преобразовать его, упростить итд.
Для твоей задачи самым простым будет метод "рекурсивного спуска". На вход алгоритм получает "поток токенов", на выходе выдает объект-корень дерева выражения (AST). С деревом потом можно делать что угодно.
Мы представляем поток токенов в виде некоей сущности tokens (это может быть объект, итератор, и тд), которая поддерживает по сути 2 операции: "подглядеть" текущий токен (peek) и "поглотить" (consume) текущий токен с переходом к следующему. Таким образом, парсер читает последовательность токенов за один проход и никогда не "отступает" назад. Это позволяет нам подсоединить выход лексера так, что мы не накапливаем массив токенов, а сразу же разбираем их по мере получения. Вот пример потока токенов, представленного в виде класса:
class TokenStream
{
// Возвращает текущий токен либо null, если они закончились
public function peek(): ?Token { ... }
// Берет токен, проверяет, что он указанного типа, возвращает его
// и переходит к следующему токену
public function consume($type = null): Token { ... }
}
Для начала, мы записываем "грамматику", то есть полный набор правил, по которым разбираются выражения, начиная с верхнего уровня. Я использую синтаксис ABNF ( https://en.wikipedia.org/wiki/Augmented_Backus–Naur_form , советую почитать также про BNF и EBNF):
-------
; Правила записываются в виде "конструкция = определение"
; Например, ниже "операнд" может быть одной из перечисленных ниже конструкций
; Знак / обозначает "или"
; ЧИСЛО - это один токен, который далее не делится на части (терминал)
; строки в кавычках вроде "(" обозначают соответствующие символы (скобку)
операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс
унарный-минус = "-" операнд
унарный-плюс = "+" операнд
; * значит, что выражение в скобках повторяется сколько угодно раз, включая ноль,
; то есть конструкция "степень" может содержать много операндов и знаков ^,
; а может состоять из одного операнда без знака ^
степень-или-операнд = операнд *( "^" операнд )
; произведение - это набор конструкций "степень", разделенный
; знаками деления и умножения
произведение = степень-или-операнд *( ( "*" / "/" ) степень-или-операнд )
сумма = произведение *( ( "+" / "-" ) произведение )
выражение = сумма
-------
Читать правила удобнее снизу вверх (а писать - наоборот).
Эти правила по сути задают алгоритм разбора той или иной конструкции. Ну например, правило 'операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс' значит следующее:
Когда мы хотим разобрать конструкцию "операнд", мы должны:
- проверить, является ли токен ЧИСЛОм ? Если да - создаем из него узел и разбор закончен
- является ли первый токен скобкой? Если да, поглощаем его, затем вызываем правило разбора "выражение", затем поглощаем закрывающую скобку
- является ли первый токен минусом? Если да, разбираем конструкцию "унарный-минус"
- является ли первый токен плюсом? Если да, разбираем конструкцию "унарный-плюс"
- иначе, выдаем синтаксическую ошибку
Правило 'сумма = произведение *( ( "+" / "-" ) произведение )' надо читать так:
Конструкция "сумма" состоит из конструкции "произведение", за которой может идти любое число последоватльностей из знака плюс или минус и конструкции "произведение".
Эти правила можно записать и по-другому. Например, "степень-или-операнд" можно сформулировать так:
; правоассоциативное выражение
степень-или-операнд = операнд "^" степень-или-операнд / операнд
; левоассоциативное
произведение = степень-или-операнд ( "*" / "/" ) произведение / степень-или-операнд
Возвращаясь к методу "рекурсивного спуска". В нем мы для каждого правила грамматики пишем соответствующую функцию, которая его реализует. Она выглядит так:
function parseSomething(tokens): [Node, tokens]
Она получает на вход поток токенов, поглощает часть из них, возвращает соответствующий им узел дерева и измененный поток токенов. Возвращать на самом деле tokens не обязательно, можно договориться, что функция изменяет состояние переданного ей аргумента.
Если она не может распарсить поток токенов, она сигнализирует о синтаксической ошибке (например, выбросив исключение). Функция может вызывать другие функции для разбора конструкций (отсюда и название "спуск").
Если взять правила выше, то у нас будут функции:
parseOperand
parseUnaryMinus
parseUnaryPlus
parsePower
parseMultiplication
parseSum = parseExpression
Опишу для примера алгоритм функции parseOperand(tokens):
- если текущий токен == ЧИСЛО, то создаем узел типа NumberNode и возвращаем его
- иначе, если текущий токен = "(", то поглощаем его, вызываем parseExpression и поглощам идущий далее токен ")". И возвращаем получившийся узел.
- если текущий токен - знак минус, то, вызываем parseUnaryMinus и возвращаем результат
- если текущий токен - знак плюс, то вызвыаем parseUnaryPlus и возвращаем результат
- сигнализируем об ошибке
Пример:
class Parser
{
...
function parseOperand(TokenStream $tokens)
{
$token = $tokens->peek();
if ($token->type == Token::TYPE_NUMBER) {
$tokens->consume();
return [new NumberNode($token), $tokens];
}
if ($token->value == "(") {
$tokens->consume("(");
list($node, $tokens) = $this->parseExpression($tokens);
$tokens->consume(")");
return [$node, $tokens];
}
if ($token->value == "-") {
return $this->parseUnaryExpression($tokens);
}
if ($this->value == "+") {
return $this->parseUnaryExpression($tokens);
}
$this->throwExpectedError("expected NUMBER, (, +, or -");
}
Мои правила предполагают, что узел может содержать не 2, а более детей. То есть для выражения "2 + 4 - 3" я создаю один узел SumNode с 3 детьми: 2, 4 и 3. Но это можно поменять и на узлы с 2 детьми, это не принципиально.
Я советую попробовать реализовать метод "рекурсивного спуска".
Если хочешь усложнить задачу, попробуй добавить в выражение: дроби (1/3), функции (sin(x)). Также, можешь попробовать сделать парсер какого-нибудь языка программирования, например, урезанной версии PHP, поддерживающей переменные, функции, конструкции if и for. Начать можешь с описания грамматики.
Ты, может быть заметил, что ключевой элемент парсера - это правила грамматики, а остальной код пишется по ним. Когда правил много, это превращается в скучную рутинную работу.
Потому для таких случаев придуманы генераторы парсеров. Довольно известный - ANTLR ( https://github.com/antlr/antlr4 ), он написан на Яве, но умеет генерировать парсеры на разных языках программирования. Для него, например, есть куча грамматик разных языков: https://github.com/antlr/grammars-v4.
Также, есть написанный на PHP PEG: https://github.com/hafriedlander/php-peg
Ты даешь им грамматику и они по ней генерируют код парсера. "Взрослые" парсеры для компьютерных программ делаются по такому принципу, так как вручную их писать долго и легко ошибиться.
>>1134788
Ты можешь посмотреть в сторону компонента Symfony ExpressionLanguage: https://symfony.com/doc/current/components/expression_language.html - там уже есть парсер выражений. Но если тебе интересно, как вообще это делается, читай пасту:
Разбор выражений делается с помощью синтаксического анализа. Он же применяется, например, при разборе компьютерных программ. Мы определяем "грамматику" (набор правил) и по ней делаем разбор.
Для записи грамматики есть разные стандартные способы:
- BNF https://en.wikipedia.org/wiki/Backus–Naur_form
- EBNF https://en.wikipedia.org/wiki/Extended_Backus–Naur_form
- ABNF https://en.wikipedia.org/wiki/Augmented_Backus–Naur_form (спецификация на рус: https://rfc2.ru/5234.rfc )
- и даже можно использовать регулярки https://habrahabr.ru/post/171667/
Все эти грамматики определяют правила составления конструкций из минимальных неделимых кусочков языка (терминалы) и других составных конструкций. Например, для математического выражения терминалами могут быть числа и знаки арифметических операций, а составной конструкцией - "сумма", определенная как последовательность конструкций ЧИСЛО "+" ЧИСЛО.
Традиционно разбор выражения делают в 2 этапа:
1) В рамках лексического анализа лексер (токенайзер) разбивает выражение на массив токенов (лексем): "-(22 + 2) ^ 3 ^ 4" -> ['-', '(', '22', '+', '2', ')', '^', '3', '^', '4']. На этом этапе числа группируются в токен, удаляются незначащие символы. Токен может быть представлен строкой, массивом, объектом, в зависимости от задачи. Последовательность токенов можно представить в виде массива или объекта.
2) В рамках синтаксического анализа парсер получает на вход поток токенов и строит дерево выражения их узлов. Тут есть разные алгоритмы: https://ru.wikipedia.org/wiki/Синтаксический_анализ
Дерево выражения удобно представлять в виде дерева из объектов-узлов разного типа (AST). Ну например, математическое выражение 10 + 2 + 3 ^ 4 можно представить в виде дерева объектов:
SumNode(
NumberNode(10),
NumberNode(2),
PowerNode(
NumberNode(3),
NumberNode(4)
)
)
Имея такое дерево, мы можем вычислить выражение, преобразовать его, упростить итд.
Для твоей задачи самым простым будет метод "рекурсивного спуска". На вход алгоритм получает "поток токенов", на выходе выдает объект-корень дерева выражения (AST). С деревом потом можно делать что угодно.
Мы представляем поток токенов в виде некоей сущности tokens (это может быть объект, итератор, и тд), которая поддерживает по сути 2 операции: "подглядеть" текущий токен (peek) и "поглотить" (consume) текущий токен с переходом к следующему. Таким образом, парсер читает последовательность токенов за один проход и никогда не "отступает" назад. Это позволяет нам подсоединить выход лексера так, что мы не накапливаем массив токенов, а сразу же разбираем их по мере получения. Вот пример потока токенов, представленного в виде класса:
class TokenStream
{
// Возвращает текущий токен либо null, если они закончились
public function peek(): ?Token { ... }
// Берет токен, проверяет, что он указанного типа, возвращает его
// и переходит к следующему токену
public function consume($type = null): Token { ... }
}
Для начала, мы записываем "грамматику", то есть полный набор правил, по которым разбираются выражения, начиная с верхнего уровня. Я использую синтаксис ABNF ( https://en.wikipedia.org/wiki/Augmented_Backus–Naur_form , советую почитать также про BNF и EBNF):
-------
; Правила записываются в виде "конструкция = определение"
; Например, ниже "операнд" может быть одной из перечисленных ниже конструкций
; Знак / обозначает "или"
; ЧИСЛО - это один токен, который далее не делится на части (терминал)
; строки в кавычках вроде "(" обозначают соответствующие символы (скобку)
операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс
унарный-минус = "-" операнд
унарный-плюс = "+" операнд
; * значит, что выражение в скобках повторяется сколько угодно раз, включая ноль,
; то есть конструкция "степень" может содержать много операндов и знаков ^,
; а может состоять из одного операнда без знака ^
степень-или-операнд = операнд *( "^" операнд )
; произведение - это набор конструкций "степень", разделенный
; знаками деления и умножения
произведение = степень-или-операнд *( ( "*" / "/" ) степень-или-операнд )
сумма = произведение *( ( "+" / "-" ) произведение )
выражение = сумма
-------
Читать правила удобнее снизу вверх (а писать - наоборот).
Эти правила по сути задают алгоритм разбора той или иной конструкции. Ну например, правило 'операнд = ЧИСЛО / "(" выражение ")" / унарный-минус / унарный-плюс' значит следующее:
Когда мы хотим разобрать конструкцию "операнд", мы должны:
- проверить, является ли токен ЧИСЛОм ? Если да - создаем из него узел и разбор закончен
- является ли первый токен скобкой? Если да, поглощаем его, затем вызываем правило разбора "выражение", затем поглощаем закрывающую скобку
- является ли первый токен минусом? Если да, разбираем конструкцию "унарный-минус"
- является ли первый токен плюсом? Если да, разбираем конструкцию "унарный-плюс"
- иначе, выдаем синтаксическую ошибку
Правило 'сумма = произведение *( ( "+" / "-" ) произведение )' надо читать так:
Конструкция "сумма" состоит из конструкции "произведение", за которой может идти любое число последоватльностей из знака плюс или минус и конструкции "произведение".
Эти правила можно записать и по-другому. Например, "степень-или-операнд" можно сформулировать так:
; правоассоциативное выражение
степень-или-операнд = операнд "^" степень-или-операнд / операнд
; левоассоциативное
произведение = степень-или-операнд ( "*" / "/" ) произведение / степень-или-операнд
Возвращаясь к методу "рекурсивного спуска". В нем мы для каждого правила грамматики пишем соответствующую функцию, которая его реализует. Она выглядит так:
function parseSomething(tokens): [Node, tokens]
Она получает на вход поток токенов, поглощает часть из них, возвращает соответствующий им узел дерева и измененный поток токенов. Возвращать на самом деле tokens не обязательно, можно договориться, что функция изменяет состояние переданного ей аргумента.
Если она не может распарсить поток токенов, она сигнализирует о синтаксической ошибке (например, выбросив исключение). Функция может вызывать другие функции для разбора конструкций (отсюда и название "спуск").
Если взять правила выше, то у нас будут функции:
parseOperand
parseUnaryMinus
parseUnaryPlus
parsePower
parseMultiplication
parseSum = parseExpression
Опишу для примера алгоритм функции parseOperand(tokens):
- если текущий токен == ЧИСЛО, то создаем узел типа NumberNode и возвращаем его
- иначе, если текущий токен = "(", то поглощаем его, вызываем parseExpression и поглощам идущий далее токен ")". И возвращаем получившийся узел.
- если текущий токен - знак минус, то, вызываем parseUnaryMinus и возвращаем результат
- если текущий токен - знак плюс, то вызвыаем parseUnaryPlus и возвращаем результат
- сигнализируем об ошибке
Пример:
class Parser
{
...
function parseOperand(TokenStream $tokens)
{
$token = $tokens->peek();
if ($token->type == Token::TYPE_NUMBER) {
$tokens->consume();
return [new NumberNode($token), $tokens];
}
if ($token->value == "(") {
$tokens->consume("(");
list($node, $tokens) = $this->parseExpression($tokens);
$tokens->consume(")");
return [$node, $tokens];
}
if ($token->value == "-") {
return $this->parseUnaryExpression($tokens);
}
if ($this->value == "+") {
return $this->parseUnaryExpression($tokens);
}
$this->throwExpectedError("expected NUMBER, (, +, or -");
}
Мои правила предполагают, что узел может содержать не 2, а более детей. То есть для выражения "2 + 4 - 3" я создаю один узел SumNode с 3 детьми: 2, 4 и 3. Но это можно поменять и на узлы с 2 детьми, это не принципиально.
Я советую попробовать реализовать метод "рекурсивного спуска".
Если хочешь усложнить задачу, попробуй добавить в выражение: дроби (1/3), функции (sin(x)). Также, можешь попробовать сделать парсер какого-нибудь языка программирования, например, урезанной версии PHP, поддерживающей переменные, функции, конструкции if и for. Начать можешь с описания грамматики.
Ты, может быть заметил, что ключевой элемент парсера - это правила грамматики, а остальной код пишется по ним. Когда правил много, это превращается в скучную рутинную работу.
Потому для таких случаев придуманы генераторы парсеров. Довольно известный - ANTLR ( https://github.com/antlr/antlr4 ), он написан на Яве, но умеет генерировать парсеры на разных языках программирования. Для него, например, есть куча грамматик разных языков: https://github.com/antlr/grammars-v4.
Также, есть написанный на PHP PEG: https://github.com/hafriedlander/php-peg
Ты даешь им грамматику и они по ней генерируют код парсера. "Взрослые" парсеры для компьютерных программ делаются по такому принципу, так как вручную их писать долго и легко ошибиться.
спасибо! это как раз то, что нужно
еще вопрос: я правильно понимаю, что в QueryBuilder доктриновский (а именно в его метод where()) просто так не всунешь условие селекта типа '((ID = 10) OR (NAME = 'VASYA' AND ID < 5))' ну то есть которое в обычный sql бы переварил?
и для этого там есть всякие методы типа expr()?
возможно ли вообще в некий свой метод типа filterNews('where ((id > 5 or (name = ... ))') в качестве аргумента подать подобное условие и на выходе каким-то образом получить queryBuilder, который подставляя свои методы-хелперы такую логику реализует? или лучше использовать доктриновский query() для таких целей?
Великовозрастный долбоёб и php с pdo;
Вопросы такие: Как правильно добавлять данные с формы в таблицу? Допустим форма регистрации. Не забивать же каждое поле в переменную? В массив, а потом этот массив запихивать в бд?
Как правильно упаковать запись в таблицу с помощью pdo? Есть два файла: index.php, pdo.php. В индексе, в шапке, инклуд файла pdo.php, и сама форма с кнопкой. В файле pdo.php - простой коннект к бд. Пишу корявый prepare вместе с bindParam (допустим без массива, а данные с поля - попадают в переменную) - нихуя не происходит. В то время как форма по загрузке файла, с добавлением в бд инфы по нему - рабочие. Что за магия?
try {
$dbh = new PDO('mysql:host = localhost;dbname = $dbname', $user, $pass, array(PDO::ATTR_PERSISTENT => false));
// само подключение
$addUsr = $dbh->prepare("INSERT INTO user (group, name, pass, salt, email) VALUES (:group, :name, :passwd, :salt, :email)");
$addUsr->bindParam(':group', $group);
$addUsr->bindParam(':name', $usrName);
$addUsr->bindParam(':passwd', $salted);
$addUsr->bindParam(':salt', $salt);
$addUsr->bindParam(':email', $email);
// подготовленное выражение
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
// закрываем трай
Допустим на подобном ублюдском примере с "значение поля = переменная". После условия формы, в индексе, стоит $addUsr->execute();
Ну и вариант "красивой" передачи, пожалуйста. Пробовал, кстати, $dbh->exec в начале скрипта, с болванистыми данными, которые должны забиваться при отработке скрипта, но ему похуй. В бд ничего не появляется. Как так, ёбаный в рот? Вопрошал в факе, но там всем настолько похуй, что нихуя вообще не написали.
Великовозрастный долбоёб и php с pdo;
Вопросы такие: Как правильно добавлять данные с формы в таблицу? Допустим форма регистрации. Не забивать же каждое поле в переменную? В массив, а потом этот массив запихивать в бд?
Как правильно упаковать запись в таблицу с помощью pdo? Есть два файла: index.php, pdo.php. В индексе, в шапке, инклуд файла pdo.php, и сама форма с кнопкой. В файле pdo.php - простой коннект к бд. Пишу корявый prepare вместе с bindParam (допустим без массива, а данные с поля - попадают в переменную) - нихуя не происходит. В то время как форма по загрузке файла, с добавлением в бд инфы по нему - рабочие. Что за магия?
try {
$dbh = new PDO('mysql:host = localhost;dbname = $dbname', $user, $pass, array(PDO::ATTR_PERSISTENT => false));
// само подключение
$addUsr = $dbh->prepare("INSERT INTO user (group, name, pass, salt, email) VALUES (:group, :name, :passwd, :salt, :email)");
$addUsr->bindParam(':group', $group);
$addUsr->bindParam(':name', $usrName);
$addUsr->bindParam(':passwd', $salted);
$addUsr->bindParam(':salt', $salt);
$addUsr->bindParam(':email', $email);
// подготовленное выражение
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
// закрываем трай
Допустим на подобном ублюдском примере с "значение поля = переменная". После условия формы, в индексе, стоит $addUsr->execute();
Ну и вариант "красивой" передачи, пожалуйста. Пробовал, кстати, $dbh->exec в начале скрипта, с болванистыми данными, которые должны забиваться при отработке скрипта, но ему похуй. В бд ничего не появляется. Как так, ёбаный в рот? Вопрошал в факе, но там всем настолько похуй, что нихуя вообще не написали.
есть доктрина и симфони. есть некие входные данные (прилетают по апи), в которых лежит sql-условие where типа "(name='ABC' AND (category1 = 'X' OR category2 = 'X' OR category3 = 'X')
AND price > 10)" в виде строки. оно всегда валидное, т.к. проверяется до попадания и может быть очень сложным с большим уровнем вложенности. задача - отдать выборку по нему.
оно всегда относится к выборке одной и той же сущности. как это условие скормить доктрине?
EAV вроде как уродство и все значения в строках. Как вообще делаются современные интернет-магазины/витрины, не особо крупные, например
А вот никаких. Данные в переменные передаются, проверял. Оно просто не пишет в базу. Я хуй знает чому. Скрипт отрабатывает и... пусто. Попробую ещё параноидальный режим ошибок ебануть, чтоб на каждый пёрд выводилось, посмотрю. поле id имеется, оно автоинкрементируемое, его, я так понял, в запросе можно не указывать - оно само ложится. По крайней мере то что мне файл в бд кладёт - так и делает
>>1131535
По тестам. Их лучше вынести в отдельную папку (например, /tests), и классы в отдельный неймспейс, чтобы отделить продакшен-код от тестов. Написать для них отдельное правило автозагрузки в autoload-dev, чтобы оно не применялось на продакшене.
Тестировать код можно на разных уровнях. Можно тестировать отдельный метод, класс, группу классов или все приложение в сборе. Что касается юнит-тестов, ими можно протестировать не любой код. Если, например, код вызывает die(), то его через юнит-тест не протестировать.
Вот, например, твой роутер явно не проверить юнит-тестом, так как он может подключать контроллеры, делать там кучу вещей. Это ведь по сути фронт-контроллер, который занимается роутингом и вызовом контроллера страницы. Как можно его протестировать? Есть разные подходы:
- можно попробовать изолировать его от остального кода, подсунув ему моки вместо настоящих контроллеров. Если бы он не создавал контроллеры сам, а брал их из контейнера, можно было бы передать ему контейнер с моками. Но это, по моему, очень плохое решение, так как оно требует сложной настройки и всегда можно что-то упустить, плюс при правках роутера наша сложная схема может перестать работать.
- можно попробовать переделать код роутера, сделать его более тестируемым, вынеся отдельно компонент, который никаких контроллеров не вызывает, а просто разбирает URL. И тестировать этот компонент
- ну и наконец, можно перейти на другой уровень, и тестировать роутер вместе со всем приложением. То есть поднять тестовый веб-сервер, вызывать на нем разные URL и смотреть, что придет в ответ.
На мой взгляд, тут разве что третий вариант подходит. В фреймворках вроде Симфони контроллеры лучше поддаются тестированию: там используются объекты Request (вместо $_GET, POST) и Response (вместо вывода страницы напрямую), и там мы можем создать Request, вызвать контроллер и проверить Response. У тебя, к сожалению, это невозможно и контроллер можно тестировать только через end-to-end тесты.
Вдобавок, у тебя в тесте ошибка: REQUEST_URI почти всегда начинается со слеша (еще я видел вариант, когда он начинается с вопроса), а не с букв.
По https://github.com/moabit/student-list/blob/master/app/Tests/UtilTest.php
Для readJson() можно было добавить еще позитивный сценарий: чтение файла с правильным путем и извлечение из него какой-то строчки. Файл можно положить в папку вроде assets, resources или создать перед тестом во временной папке (наверно, не стоит).
Далее, если мы посмотрим на testCheckCSRFToken(), то видим, что тут явно не очень удобный для тестирования код. Он не принимает входные параметры явно, а берет их из каких-то глобальных переменных. Тестировать код, который работает с объектами вроде Request было бы конечно удобнее.
Тут конечно в тесте заложено знание подробностей работы защиты от CSRF: тест знает, какие куки проверяет код, какой алгоритм он использует. Если в алгоритме защиты что-то поменять, тест может сломаться. Это можно было бы попробовать исправить, организовав тестирование по-другому:
- вызвать setCSRFToken() и записать выставленные им куки (это было бы удобно делать, если бы он не работал с setcookie(), а записывал бы куки в объект Response), сохранить возвращенный токен
- сформировать объект Request с запросом от формы, подставить туда полученный токен и выданные куки
- вызвать проверку
Но это требует добавления Request/Response. Еще один вариант - использовать end-to-end тест - сделать тестовую страницу с формой и защитой от CSRF, поднять временный веб-сервер, зайти на страницу, заполнить форму, отправить, проверить ответ. Опять же, требует значительных усилий.
Но зато оба этих варианта могут дать более надежные тесты.
Есть разные точки зрения по организации тестов, но мне кажется, что удобно делать один тестовый метод на каждое требование. Ну то есть, мы думаем, какие мы требования предъявляем к коду проверки CSRF?
- если дан токен в POST и кука, то проверка проходит
- если дан токен и кука, но они не совпадают, проверка не проходит
- если токен в POST пустой, проверка не проходит
- если куки нет, проверка не проходит
На каждое требование можно написать свой метод: testCheckSuccessWIthCookieAndToken, testCheckFailsWithInvalidToken, checkTestFailsWithMissingToken, итд. Для надежности, сам токен можно генерировать с помощью setCSRFToken, чтобы он был гарантированно правильный. Это потребует немного больше писанины, но зато:
- при падении тестов позволит увидеть, что именно не работает
- сделает сами функции маленькими и простыми, в них будет легче разобраться, если тест упал и надо его поправить
То же можно сказать и про тест валидатора. Можно было бы тестировать каждую проверку в отдельности (testInvalidEmailFails, testInvalidNameFails и тд). Также, если бы у тебя валидатор не был заточен только на проверку студентво, а был бы разбит на компоненты (отдельно метод или класс проверки email, отдельно имени), то их тоже можно было бы тестировать по отдельности.
Но конечно, и тот тест, что есть, уже полезен и может обнаруживать проблемы.
Также, в тесте testStudentValidation() у тебя есть одно слабое место - там ведь есть проверка уникальности email, и если в БД есть email rabinovicC-vhANUSgm%qqailPUNCTUMco]%am, то она может провалиться. Можно наверно этим пренебречь, а можно попробовать придумать email, которого в базе точно не может быть. Тем более, что этот же email используется в тесте вставки студента.
https://github.com/moabit/student-list/blob/master/app/Tests/StudentDataGatewayTest.php#L30
> public function testCountStudents()
> {
> $this->assertNotFalse($this->studentDataGateway->countStudents());
Этот тест полагается на то, что в тестовой базе есть хотя бы один студент. Можно избавить его от этой проблемы, например, добавив студента в тесте и проверив, что количество увеличилось на один.
> public function testGetStudentsWithWrongField()
> {
> $this->expectException(\PDOException::class);
> $this->studentDataGateway->getStudents('wrongOrderField', 'asc', 15, 0);
Этот тест полагается на знание внутреннего устройства StudentGateway. Что, если ым там поменяем PDO на mysqli? Решить это можно, сделав специальный класс исключений на такой случай или взяв одно из SPL исключений: http://php.net/manual/ru/spl.exceptions.php
В README:
> To add more students uncomment addStudents function in index.php file
лучше написать про вызов cli-скрипта
> echo "Please enter a number of students you want to add to the database:\n";
> $input=intval(fgets(STDIN));
В CLI-скриптах обычно параметры передают как аргументы командной строки, то есть пишут
php addStudents.php 10
Почитай про $argv, $argc и getopt:
- http://php.net/manual/ru/features.commandline.usage.php
- http://php.net/manual/ru/reserved.variables.argv.php
- http://php.net/manual/ru/reserved.variables.argc.php
- http://php.net/manual/ru/function.getopt.php
getopt довольно примитивный (он например не умеет формировать подсказку по аргументам), потому для более сложных случаев ты можешь захотеть поискать какие-то библиотеки для разбора аргументов. Как минимум, такие классы есть в компоненте Symfony Console, ну и наверно есть отдельные библиотеки для этого.
Также, ты в cli скрипте почему-то не подключил ErrorHandler.
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L90
> ucfirst
Эта функция не поддерживает кириллицу в utf-8: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Плюс, ты не делаешь проверку, что в POST есть нужный элемент. Лучше писать $_POST['name'] ?? ''.
https://github.com/moabit/student-list/blob/master/app/Entities/Student.php
тут не помешали бы тайп хинты.
https://github.com/moabit/student-list/blob/master/app/Helpers/Authorisation.php
Вот этот класс обладает состоянием. Было бы логичнее в контейнере пометить его ,чтобы при каждом обращении создавался бы новый экземпляр. А иначе, представь что ты попробуешь обработать 2 запроса подряд: обработчик первого запроса поменяет состояние объекта и это может повлиять на обработку заипроса от второго пользователя.
Также, метод getStudent возвращает объект студента, но signIn() принимает токен, а не студента. Было бы лучше и тут сделать аргументом студента и таким образом скрыть подробности авторизации (какие поля используются) внутри класса. Это позволит нам менять алгоритм авторизации, не трогая остальной код.
https://github.com/moabit/student-list/blob/master/views/templates/profileForm.twig#L22
> {% if user.gender is defined and user.gender =="f" %}
лучше сделать, чтобы user всегда бы передавался в шаблон. Если это так, то is defined можно убирать.
Класс pager назван не очень удачно, он же не только за пагинацию отвечает. Лучше назвать его ViewParams, TableParams или TableFilter. И тогда можно добавить туда методы вроде isSearchActive() вместо {% if pager.search is not null %}.
>>1131535
По тестам. Их лучше вынести в отдельную папку (например, /tests), и классы в отдельный неймспейс, чтобы отделить продакшен-код от тестов. Написать для них отдельное правило автозагрузки в autoload-dev, чтобы оно не применялось на продакшене.
Тестировать код можно на разных уровнях. Можно тестировать отдельный метод, класс, группу классов или все приложение в сборе. Что касается юнит-тестов, ими можно протестировать не любой код. Если, например, код вызывает die(), то его через юнит-тест не протестировать.
Вот, например, твой роутер явно не проверить юнит-тестом, так как он может подключать контроллеры, делать там кучу вещей. Это ведь по сути фронт-контроллер, который занимается роутингом и вызовом контроллера страницы. Как можно его протестировать? Есть разные подходы:
- можно попробовать изолировать его от остального кода, подсунув ему моки вместо настоящих контроллеров. Если бы он не создавал контроллеры сам, а брал их из контейнера, можно было бы передать ему контейнер с моками. Но это, по моему, очень плохое решение, так как оно требует сложной настройки и всегда можно что-то упустить, плюс при правках роутера наша сложная схема может перестать работать.
- можно попробовать переделать код роутера, сделать его более тестируемым, вынеся отдельно компонент, который никаких контроллеров не вызывает, а просто разбирает URL. И тестировать этот компонент
- ну и наконец, можно перейти на другой уровень, и тестировать роутер вместе со всем приложением. То есть поднять тестовый веб-сервер, вызывать на нем разные URL и смотреть, что придет в ответ.
На мой взгляд, тут разве что третий вариант подходит. В фреймворках вроде Симфони контроллеры лучше поддаются тестированию: там используются объекты Request (вместо $_GET, POST) и Response (вместо вывода страницы напрямую), и там мы можем создать Request, вызвать контроллер и проверить Response. У тебя, к сожалению, это невозможно и контроллер можно тестировать только через end-to-end тесты.
Вдобавок, у тебя в тесте ошибка: REQUEST_URI почти всегда начинается со слеша (еще я видел вариант, когда он начинается с вопроса), а не с букв.
По https://github.com/moabit/student-list/blob/master/app/Tests/UtilTest.php
Для readJson() можно было добавить еще позитивный сценарий: чтение файла с правильным путем и извлечение из него какой-то строчки. Файл можно положить в папку вроде assets, resources или создать перед тестом во временной папке (наверно, не стоит).
Далее, если мы посмотрим на testCheckCSRFToken(), то видим, что тут явно не очень удобный для тестирования код. Он не принимает входные параметры явно, а берет их из каких-то глобальных переменных. Тестировать код, который работает с объектами вроде Request было бы конечно удобнее.
Тут конечно в тесте заложено знание подробностей работы защиты от CSRF: тест знает, какие куки проверяет код, какой алгоритм он использует. Если в алгоритме защиты что-то поменять, тест может сломаться. Это можно было бы попробовать исправить, организовав тестирование по-другому:
- вызвать setCSRFToken() и записать выставленные им куки (это было бы удобно делать, если бы он не работал с setcookie(), а записывал бы куки в объект Response), сохранить возвращенный токен
- сформировать объект Request с запросом от формы, подставить туда полученный токен и выданные куки
- вызвать проверку
Но это требует добавления Request/Response. Еще один вариант - использовать end-to-end тест - сделать тестовую страницу с формой и защитой от CSRF, поднять временный веб-сервер, зайти на страницу, заполнить форму, отправить, проверить ответ. Опять же, требует значительных усилий.
Но зато оба этих варианта могут дать более надежные тесты.
Есть разные точки зрения по организации тестов, но мне кажется, что удобно делать один тестовый метод на каждое требование. Ну то есть, мы думаем, какие мы требования предъявляем к коду проверки CSRF?
- если дан токен в POST и кука, то проверка проходит
- если дан токен и кука, но они не совпадают, проверка не проходит
- если токен в POST пустой, проверка не проходит
- если куки нет, проверка не проходит
На каждое требование можно написать свой метод: testCheckSuccessWIthCookieAndToken, testCheckFailsWithInvalidToken, checkTestFailsWithMissingToken, итд. Для надежности, сам токен можно генерировать с помощью setCSRFToken, чтобы он был гарантированно правильный. Это потребует немного больше писанины, но зато:
- при падении тестов позволит увидеть, что именно не работает
- сделает сами функции маленькими и простыми, в них будет легче разобраться, если тест упал и надо его поправить
То же можно сказать и про тест валидатора. Можно было бы тестировать каждую проверку в отдельности (testInvalidEmailFails, testInvalidNameFails и тд). Также, если бы у тебя валидатор не был заточен только на проверку студентво, а был бы разбит на компоненты (отдельно метод или класс проверки email, отдельно имени), то их тоже можно было бы тестировать по отдельности.
Но конечно, и тот тест, что есть, уже полезен и может обнаруживать проблемы.
Также, в тесте testStudentValidation() у тебя есть одно слабое место - там ведь есть проверка уникальности email, и если в БД есть email rabinovicC-vhANUSgm%qqailPUNCTUMco]%am, то она может провалиться. Можно наверно этим пренебречь, а можно попробовать придумать email, которого в базе точно не может быть. Тем более, что этот же email используется в тесте вставки студента.
https://github.com/moabit/student-list/blob/master/app/Tests/StudentDataGatewayTest.php#L30
> public function testCountStudents()
> {
> $this->assertNotFalse($this->studentDataGateway->countStudents());
Этот тест полагается на то, что в тестовой базе есть хотя бы один студент. Можно избавить его от этой проблемы, например, добавив студента в тесте и проверив, что количество увеличилось на один.
> public function testGetStudentsWithWrongField()
> {
> $this->expectException(\PDOException::class);
> $this->studentDataGateway->getStudents('wrongOrderField', 'asc', 15, 0);
Этот тест полагается на знание внутреннего устройства StudentGateway. Что, если ым там поменяем PDO на mysqli? Решить это можно, сделав специальный класс исключений на такой случай или взяв одно из SPL исключений: http://php.net/manual/ru/spl.exceptions.php
В README:
> To add more students uncomment addStudents function in index.php file
лучше написать про вызов cli-скрипта
> echo "Please enter a number of students you want to add to the database:\n";
> $input=intval(fgets(STDIN));
В CLI-скриптах обычно параметры передают как аргументы командной строки, то есть пишут
php addStudents.php 10
Почитай про $argv, $argc и getopt:
- http://php.net/manual/ru/features.commandline.usage.php
- http://php.net/manual/ru/reserved.variables.argv.php
- http://php.net/manual/ru/reserved.variables.argc.php
- http://php.net/manual/ru/function.getopt.php
getopt довольно примитивный (он например не умеет формировать подсказку по аргументам), потому для более сложных случаев ты можешь захотеть поискать какие-то библиотеки для разбора аргументов. Как минимум, такие классы есть в компоненте Symfony Console, ну и наверно есть отдельные библиотеки для этого.
Также, ты в cli скрипте почему-то не подключил ErrorHandler.
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L90
> ucfirst
Эта функция не поддерживает кириллицу в utf-8: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Плюс, ты не делаешь проверку, что в POST есть нужный элемент. Лучше писать $_POST['name'] ?? ''.
https://github.com/moabit/student-list/blob/master/app/Entities/Student.php
тут не помешали бы тайп хинты.
https://github.com/moabit/student-list/blob/master/app/Helpers/Authorisation.php
Вот этот класс обладает состоянием. Было бы логичнее в контейнере пометить его ,чтобы при каждом обращении создавался бы новый экземпляр. А иначе, представь что ты попробуешь обработать 2 запроса подряд: обработчик первого запроса поменяет состояние объекта и это может повлиять на обработку заипроса от второго пользователя.
Также, метод getStudent возвращает объект студента, но signIn() принимает токен, а не студента. Было бы лучше и тут сделать аргументом студента и таким образом скрыть подробности авторизации (какие поля используются) внутри класса. Это позволит нам менять алгоритм авторизации, не трогая остальной код.
https://github.com/moabit/student-list/blob/master/views/templates/profileForm.twig#L22
> {% if user.gender is defined and user.gender =="f" %}
лучше сделать, чтобы user всегда бы передавался в шаблон. Если это так, то is defined можно убирать.
Класс pager назван не очень удачно, он же не только за пагинацию отвечает. Лучше назвать его ViewParams, TableParams или TableFilter. И тогда можно добавить туда методы вроде isSearchActive() вместо {% if pager.search is not null %}.
PDO по умолчанию никак не сообщает об ошибках. Включи в PDO ERRMODE_EXCEPTION и увидишь подробности ошибки.
http://php.net/manual/ru/pdo.error-handling.php
Также, если какая-то функция может вернуть false или другой признак ошибки, ты обязан его проверять.
cпасибо, анон. я жестко тупанул
Дано две таблицы mysql, их условная структура:
orders(
id,
created,
... // всякие обычные неинтересные поля
)
orders_properties(
id,
order_id,
param enum('height', 'weight', 'length', 'color'),
value varchar(100)
)
Получается между таблицами связь один-ко-многим: у каждого заказа может быть ни одного, одно или несколько свойств, которые указаны в поле param таблицы orders_properties. На мой взгляд, решение странное, но такая таблица уже есть, с ней ничего не сделать.
Как из этого сделать сущность Доктрины?
Типа такой:
class Order
{
private $id;
private $created;
private $height;
private $weight;
private $length;
private $color;
...
}
Чтобы оно обновлялось само и значения брались из orders_properties либо были пустыми, если там нужных нет.
Те способы, которые я нашел (например, http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/mysql-enums.html) мою проблему, увы, не решают.
Дано две таблицы mysql, их условная структура:
orders(
id,
created,
... // всякие обычные неинтересные поля
)
orders_properties(
id,
order_id,
param enum('height', 'weight', 'length', 'color'),
value varchar(100)
)
Получается между таблицами связь один-ко-многим: у каждого заказа может быть ни одного, одно или несколько свойств, которые указаны в поле param таблицы orders_properties. На мой взгляд, решение странное, но такая таблица уже есть, с ней ничего не сделать.
Как из этого сделать сущность Доктрины?
Типа такой:
class Order
{
private $id;
private $created;
private $height;
private $weight;
private $length;
private $color;
...
}
Чтобы оно обновлялось само и значения брались из orders_properties либо были пустыми, если там нужных нет.
Те способы, которые я нашел (например, http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/mysql-enums.html) мою проблему, увы, не решают.
Сущности Доктрины должны довольно-таки близко соответствовать таблицам. Но это касается только полей. Методы ты можешь делать любые.
Соответственно, ты можешь сделать метод Order#getWeight(), а он будет искать вес в связанных с Order свойствах OrderProperty.
Многие задачи решаются именно через методы. Ну например, ты можешь сделать поле неизменяемым, убрав метод setX().
То есть не делать такие поля вообще?
А как тогда задавать условия поиска по этим полям в QueryBuilder?
Пошел по твоему пути (но не совсем), сделал так:
В классе сущности написал
private $weight;
public function getWeight(OrderRepository $repo)
{
return $repo->findWeightByOrder($this->getId());
}
Затем в классе репозитория:
public function findWeightByOrder(int $id)
{
$conn = $this->getEntityManager()->getConnection();
$sql = 'SELECT o.value FROM orders_properties o WHERE o.param = \'weight\' AND o.order_id = :id';
$stmt = $conn->prepare($sql);
$stmt->execute(['id' => $id]);
return $stmt->fetch();
}
Плюс тут в том, что не надо заморачиваться с привязкой поля типа ENUM к сущности, т.к. он по дефолту в Доктрине не поддерживается (хотя если бы это была единственная заморочка, было бы заебись), но у меня есть ощущение, что это пиздец костыли и можно как-то намного лучше и изящнее.
То есть, мне кажется, не должно быть такого, чтобы Entity обращался к Repository. По идее должно быть Controller > Repository > Entity
Да, я помню что в ПЕДЕО надо отдельно включать обработку ошибок. В общем че я выяснил:
- каким-то хуем я указал путь до файла с подключением в относительном виде "./pdo.php", вместо просто "pdo.php" - начало мне ошибки выводить;
- ошибка такая:
> Warning: PDOStatement::execute(): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near
По гуглению понял, что из формы данные по POST не экранируются и получается пиздос. Но я сонный и нихуя не понял. Данный из формы жкранировать отдельно? Форма загрузки файла не предполагает введённые данные, а только путь до файла.
алсо, как, всё-таки, более правильно формочки такие ебенить? По минимуму и аккуратно. В массив всё подбивать?
Делаю вот такую штуку
abstract class A
{
protected $var;
}
class B extends A
{
$this->var = '2ch';
}
И шторм начинает светить мол unexpected assign, и пiзда.
Но та же хуйня через метод работает. Как без метода то переназначить?
Посоветуйте годный курс, можно платный. Пока только нашел на английском https://knpuniversity.com
в симфони без английского делать вообще нечего. если хочешь на русском, иди битрикс учи.
основные источники начальной инфы - это документация, потом их демо-проект, этот knpuniversity и исходники. другой я пока не нашел (сам учу около месяца). конечно было бы круто посмотреть на код какого-то реального большого опенсорс приложения на 4.
кстати на knpuniversity платно только видео, а оно везде дублируется бесплатным текстом, даже где видео само по себе скрыто. то есть, тебе бесплатно доступны ЛЮБЫЕ уроки. я думаю, там люди платят, чтобы поддержать проект (другая ментальность мол).
стоит сразу на 4, конечно.
алсо, все эти материалы (особенно мануал) знать нужно, но они достаточно базовые. самый лучший курс - это взять на хх.ру какое-нибудь тестовое задание на симфони мидла-удаленщика и попробовать его решить в срок.
потому что надо сначала ее переопределить. иначе это динамически объявленная переменная, что считается плохой практикой из-за своей неявности
Вот я написал скрипт на пхп, который перебирает 100 миллионов значений (допустим, там только массив и цикл перебора, ничего более) и тратит на это 1 минуту. В течении этой минуты я хочу запустить другой скрипт с этого же домена (допустим test.localhost), но второй скрипт не запускается до тех пор, пока не отработает первый, перебирающий значения. Из-за чего это? Сессий внутри скрита нет, но второй всегда ждет выполнения первого? Какова "природа" этого явления и как по возможности это обойти?
cli-cкрипт? если да, то тебе нужно запускать его со значком &, чтобы запустить в бэкграунде. либо открыть новую вкладку с консолью.
>cli-cкрипт?
Нет, скрипт я запускаю через сервер, например так:
запускаю test.localhost/1.php и он выполняется минуту, параллельно в другой вкладке я запускаю test.localhost/2.php и он не "отрабатывает" до тех пор, пока первый не завершит работу.
> я запускаю через сервер
Через какой сервер?
Кто запускает твой php скрипт? Кто принимает запрос? апач, нгникс?
Как именно ты понимаешь, что ждет завершение первого скрипта? Работаешь ли ты с какими-то файлами в этих скриптах? Что в процессах у тебя в этот момент происходит? Сколько процессов php висит\запускается?
Уверен, что браузер не использует тот же коннект к серверу? Попробуй, запустить второй скрипт в другом браузере параллельно. Или вовсе вызвать через какой-нибудь wget
>Как именно ты понимаешь, что ждет завершение первого скрипта?
Да я же на тестовом серве делаю на тестовых скриптах. Запускаю первый скрипт, он выполняется, вертится "загрузка" на вкладке. Параллельно запускаю второй скрипт во второй вкладке, в нем одна строка "echo 1", но он выполняется и выводит "1" только после того, как первый скрипт закончит перебирать массивы отработает. Если я запускаю второй отдельно (то есть, первый на этот момент не запущен), то он сразу мне выдает в браузер"1", выполняется он меньше секунды. Короче, я делаю вывод, что он ждет выполнение первого.
>Работаешь ли ты с какими-то файлами в этих скриптах?
Нет, там просто огромный цикл, который перебирает миллионные массивы несколько раз, он вообще выполняется дольше минуты (почти 2).
>>36032
Если запускаю в другом браузере - то он выполняется сразу, то есть, второй скрипт не ждет выполнение первого.
>Если запускаю в другом браузере - то он выполняется сразу, то есть, второй скрипт не ждет выполнение первого.
Поясняю. Причины может быть две.
Одна - браузер использует одно и тоже соединение до сервера, а так как ты не написал\не заточил сервер для такого юзкейса, то он ждет, и поэтому все тсопорится. Гугли http 1.1вот это все.
Вторая - браузер может использовать для рендеринга вкладок на одном домене один и тот же процесс с целью оптимизации, в заивисмости от браузера и его настроек. Поэтому у тебя просто стопарится рендеринг, пока не будут получены результаты от первого.
А какая причина наиболее вероятная? Мне кажется, что первая. И где можно поподробнее почитать про это? Или если нагуглю http 1.1 - то понимание придет?
>И где можно поподробнее почитать про это?
Начинай отсюда https://ru.wikipedia.org/wiki/Постоянное_HTTP-соединение
>А какая причина наиболее вероятная?
Замени во втором скрипте echo на file_put_cintents в какой-нибудь файл. И смотри, если файл появился сразу, до завершения первого скрипта, значит дело в рендеринг. Если после, значит в запросах.
Окей, спасибо большое!
Если ты используешь сессии, то они блокируются: https://habrahabr.ru/company/bitrix/blog/179803/
Нефиг их везде использовать.
Также, длительные скрипты надо запускать через командную строку.
Он же написал, что неиспользует сессии. И ко всему прочему, мы выяснили, что при одновременном запросе из разных браузеров, все отрабатывает нормально. Так что дело либо в общей песочнице webview, либо в кип-аливе.
attributes(param enum('param1','param2','param3'), value varchar)
зачем так делать? какая выгода? как связывать такие сущности с другими в контексте ОРМ?
В браузере есть ограничение на число параллельных коннектов к серверу, но оно в районе 6-8. Правда, там еще есть HTTP/2, у которого все как-то по другому.
> либо в кип-аливе.
вряд ли
> в общей песочнице webview
Какой песочнице?
>Также, открою секрет за 1 евро в мес. можно у арубы арендовать.
Благодарю, так и сделал. Единственное что мне не понравилось у арубы - это плохой дизайн. Я ожидал выбор датацентра в процессе создания, а оказалось (потом), что выбор был вкладками в личном кабинете. Поднял OpenVPN - всё отлично, пинг правда 200 (Италия по умолчанию, хотел Германию).
Такой вопрос, ОП у тебя нет статей по настройке рабочего окружения через системы виртуализации?
>>36225
Меня не сами юникс-системы интересуют, скорее процесс развертывания проектов на докере и для чего он.
Я работаю на win10, на vbox у меня ubuntu17.04, в /var/www я примаунтил проекты. Удобно,
так как IDE работает с локальными файлами, а сам проект поднят на апаче убунту.
Встречал в интернете упоминания о том, что на докере/вагранте разворачивают себе рабочее окружение и мне стало интересно насколько это будет удобнее (и будет ли)
Сайт состоит из разных статей и их разделов. Например, при переходе к статьям articles_IT, в раздел PHP выводятся данные из таблицы БД - articles_it, где в записи указана секция PHP. И в итоге есть 4 вида статей articles_X, в которых разное количество их секций. Главное, что в итоге модель узнает, что это за статьи и их секции, и в итоге выполняет необходимое действие исходя из этих данных. Меняется по факту только один лишь запрос к БД.
Сейчас написал действие только для главной страницы, в роутах вызывается метод контроллера:
Route::get('/', 'MainController@showArticle');
Этот метод возвращает вид, с данными из модели Article:
return view('index', ['article'=> Article::loadArticle()]);
В модели формируется одна запись из рандомных статей, рандомной секции.
Так как передать модели вид статей и их секцию исходя из запроса, как правильно описать в этом случае роут? Посмотрел в документации, дошёл до параметров роутов, но плохо понимаю, как их применять.
<?
$x= __DIR__;
$y= explode( '/', $x);
array_pop($y);
array_pop($y);
var_dump($y);
?>
Типа (array_pop($y)) * 2 ;
Благодарю.
запись в одну строку - это что имеется в виду? я не очень понял.
>вопрос по контексту ORM неясен.
если у нас есть доп.таблица user_attributes(age, sex)
то мы сущности User (которая лежит в таблице users) можем задать поле $sex, которое по связи OneToOne будет ссылать на столбец sex из таблицы с аттрибутами.
а если у таблицы структура users_attributes(param enum('age','sex'), value), то мы так сделать уже не можем.
можно было бы сказать, что так мы можем добавлять любое количество параметров без изменения таблицы, но это не так - все равно придется менять столбец param - добавлять в него разрешенные значения.
короче я не понимаю, в чем плюсы. может, это во времена динозавров так делали
а еще тебя ждет огромное веселье, если нужно в одном запросе сделать where по произвольному количеству этих param. попробуй напиши автоматизацию where с подготовленными запросами. чтобы на вход подавать условие типа 'age = m AND age >= 18' а на выходе получать соответствующие сущности.
>Используй математику. Есть 2 функции для разделения чисел на части, $x % 1000 - берет 3 последние цифры, floor($x / 1000) - отбрасывает 3 последние цифры.
А если я не знаю, что там за число?
Допустим, я подобрал для сотен тысяч форму слова, отбросив по три цифры с концов, а на деле число оказалось миллиардом. Остальные шесть цифр не переведутся же.
Или нужно делать сперва проверку, не будет ли делимое меньше делителя?
$result[0] = $this->repo->findByWhereCondition('u.id >= 1000'); // дернулись из репозитория 10, 11, 12
$result[1] = $this->repo->findByGravatarCondition('equals', 'true'); // дернулись по АПИ 7, 11
$result[2] = $this->repo->findByLogicCondition('OR', [$result[0], [$result[1]]) // отдал 7, 10, 11, 12
?
Изучи Query Builder. Symfony Expression может превратить строку в AST (дерево выражения). Ты должен обойти это дерево и составить соответствующее ему условие для Query Builder:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html
Обрати внимание на выражение
$qb->expr()->orX(
$qb->expr()->eq('u.id', '?1'),
$qb->expr()->like('u.nickname', '?2')
)
Тебе надо что-то похожее составить на основе AST.
1. Можно ли расчёты будет сохранять в каком-нибудь формате прямо из браузера, а потом их туда загружать?
2. В чем сейчас актуально рисовать? Канвас или уже что-то лучше и новее есть? Может существуют библиотеки для построения простых чертежей/эскизов в браузере?
3. Не ошибся ли я с выбором джс? Сейчас считаем в экселе.
благодарю, анон
>1.Local storage
У него есть лимит.
Ничто не мешает загружать файлы с пеки, работать с ними и потом сохранять на пеку.
Если тебе надо работать с чертежами, может тебе лучше писать скрипты для какого-то CAD приложения? Ну там автокад, компас, или какой-нибудь из открытых CAD ( https://opensource.com/alternatives/autocad )?
А так, трудно прокомментировать, не зная задачу. Сам по себе JS неплохой, и к нему много библиотек есть.
Это была бы хорошая идея, если бы потом за программой не должно было бы сидеть пол офиса дамочек. И каждой ставить автокад, хехмда. Я там один его знаю, мне нужно чтобы канвас или что-то подобное само отрисовывало картинку на основе 3.5 введённых данных, чтобы дамочки могли распечатать и сохранить на будущее. Эксель норм, но там нельзя адаптивно рисовать. Плюс нужно расширить функционал, и я подумал, что сделать уже нужно нормально.
С задачей идеально справитс php. Сам писал подобное. Данные в файле (а лучше в майскул базе), отрисовку делает пхп (вместе с расчётами), а отображение в браузере на хтмл+цсс+жс.
Пхп не считает на ходу, я должен сабмиты хуярить с формами или учить ту хуйню, забыл название. Джс удобнее 100% в этом случае.
краткость записи чего? явно не селекта, если ты хочешь прописать алиас колонке из такой таблицы.
также если для тебя уже все несложно, расскажи как в доктрине запись из таблицы users_attributes с енамами, допустим 'param = age' указать в качестве поля $age сущности User(@ORM\Table(name="users"))
Мне конкртно сейчас лень, для меня это уже слишком мелочи. Мб на днях загляну в тред.
ага. как сердце подсказывает
>Пхп не считает на ходу
Считает. Только отправлять нужно не через форму с перезагрузкой страницы, а аяксом. Это чуть сложнее, но не сильно.
Если же тебе хочется всё-в-одном-флаконе, то используй Access, царствие тебе небесное.
JS, в принципе, тоже это может, но скорее всего будут подводные камни и тебе придётся осваивать не только кондовый жс, но и серверную ноду.
Такой-то поток мысли...
Только не ajax, а sockets, с которыми шикарно работает РНР. И асинхронного РНР также полно, если вдруг ноде-дауны начнут кукарекать.
https://www.youtube.com/watch?v=i07m_TFR9no
для работы здесь и сейчас yii2, т.к. его используют только в легаси и динозавры-тимлиды, которым лень переучиваться. они не будут обновляться еще 10 лет.
а для будущего развития более современные и актуальные фреймворки.
>динозавры-тимлиды
любой убогий вкатывальщик пытается скомпрометировать реалии корпоративного сегмента, за что ему и гореть в аду нищеты.
проблема двощей в том, что долбоёбы-вкатывальщики 2010+ тут имеют какое-то анонимное мнение, хотчя из приличных контор их гонят ссаными тряпками, ха
я с симфони работаю и мне заебись. через месяцок перекатимся на четверку, а ты дальше сиди и правь легаси. сказочки про жестокую реальность и проверенные технологии рассказывай на вебмастер.ру
Оставь свои фантазии себе. Что я делаю, никогда тут не заплалю, ты, ссаный неудачник.
Умный анон не пришел, я в итоге дернул все с помощью Goutte и Symfony DomCrawler. Охуенно получилось.
Задача про вклад.
> $investor = вкладчику;
Строку надо брать в кавычки.
А так, решено верно.
>>1133423
> Чем отличается инструкция error_reporting(-1) от error_reporting(E_ALL)?
В error_reporting передается число. Функция преобразует его в двоичную систему счисления (двочичные числа - это числа, состоящие только из цифр 0 и 1 вроде 001011001, подробнее http://www.reshinfo.com/dvoichnaya_systema.php ). В этом двоичном числе каждый разряд соответствует виду ошибок, и если он установлен в 0, то PHP игнорирует этот вид ошибок. А если в 1 - то не игнорирует и сообщает о них.
Вообще, мне очень не нравится сама эта идея, что можно игнорировать какие-то ошибки и мне кажется, это очень вредная опция. Но оставим мое мнение в стороне.
E_ALL - это константа, в которой для всех видов ошибок стоит единица (ее значение можно увидеть тут http://php.net/manual/ru/errorfunc.constants.php ). -1 в двоичной форме выглядит как число из всех единиц (то есть единицы стоят даже там, где это не требуется). Зачем писать -1 вместо E_ALL? В старых версиях PHP была такая проблема, что E_ALL раньше не включала в себя определенный вид ошибок (E_STRICT), несмотря на название. Потому люди начали писать -1, чтобы гарантированно все ошибки и предупреждения были включены.
Сейчас конечно писать -1 нет никакого смысла и можно просто использовать E_ALL.
>>1133839
> Создавать класс-валидатор, который будет смотреть сколько файлов было отправлено, их размер и т.д. , или все это через middleware можно сделать?
Миддлвеар не для этого. Оно для вмешательства в процесс обработки запроса (оно может менять Request или Response), например:
- ограничение доступа (требовать пароль для доступа в админку)
- шифрование и подпись содержимого кук
- логгирование обрабатываемых запросов
- модификации HTTP-ответа, например, поддержка gzip-сжатия
- кеширование страниц целиком
Задача про вклад.
> $investor = вкладчику;
Строку надо брать в кавычки.
А так, решено верно.
>>1133423
> Чем отличается инструкция error_reporting(-1) от error_reporting(E_ALL)?
В error_reporting передается число. Функция преобразует его в двоичную систему счисления (двочичные числа - это числа, состоящие только из цифр 0 и 1 вроде 001011001, подробнее http://www.reshinfo.com/dvoichnaya_systema.php ). В этом двоичном числе каждый разряд соответствует виду ошибок, и если он установлен в 0, то PHP игнорирует этот вид ошибок. А если в 1 - то не игнорирует и сообщает о них.
Вообще, мне очень не нравится сама эта идея, что можно игнорировать какие-то ошибки и мне кажется, это очень вредная опция. Но оставим мое мнение в стороне.
E_ALL - это константа, в которой для всех видов ошибок стоит единица (ее значение можно увидеть тут http://php.net/manual/ru/errorfunc.constants.php ). -1 в двоичной форме выглядит как число из всех единиц (то есть единицы стоят даже там, где это не требуется). Зачем писать -1 вместо E_ALL? В старых версиях PHP была такая проблема, что E_ALL раньше не включала в себя определенный вид ошибок (E_STRICT), несмотря на название. Потому люди начали писать -1, чтобы гарантированно все ошибки и предупреждения были включены.
Сейчас конечно писать -1 нет никакого смысла и можно просто использовать E_ALL.
>>1133839
> Создавать класс-валидатор, который будет смотреть сколько файлов было отправлено, их размер и т.д. , или все это через middleware можно сделать?
Миддлвеар не для этого. Оно для вмешательства в процесс обработки запроса (оно может менять Request или Response), например:
- ограничение доступа (требовать пароль для доступа в админку)
- шифрование и подпись содержимого кук
- логгирование обрабатываемых запросов
- модификации HTTP-ответа, например, поддержка gzip-сжатия
- кеширование страниц целиком
Надо написать преобразователь дерева AST, которое дает Symfony Expressions, в критерии для Query Builder.
>>35141
> Как правильно добавлять данные с формы в таблицу?
Во-первых, есть урок про обработку данных формы: https://github.com/codedokode/pasta/blob/master/forms.md
Во-вторых, полученные данные надо вставиь в БД. Для этого достаточно подготовить запрос с помощью PDO, а затем выполнить его с данными из формы. Это описывается в любой статье про PDO.
Также, наверно не надо ловить исключения и выводить их содерждимое пользователю. Логичнее логгировтаь подробности ошибки в лог, а пользователю показывать страницу-заглушку. Описано например тут: https://github.com/codedokode/pasta/blob/master/php/exceptions.md
>>35377
> зря создавал отдельные сущности, так как в будущем их слишком много может быть и не понятно, как потом поддерживать.
А в чем проблема? Я не понимаю. Никак специально их поддерживать не надо.
> Однако не понял, как хранить разные характеристики, ну есть, конечно, json,
Есть паттерн EAV.
> ну как по нему условия, читай фильтры в каталоге, делать.
По JSON - если БД поддерживает разбор и индексацию JSON (например Postgres), то ещ можно что-то сделать, если нет то EAV. Хотя у тебя с десятком кроватей проблем с производительностью в любом случае не будет.
Получишь свалку нетипизированных данных, только и всего.
>>35546
Никак. Искать по связанным полям:
SELECT o FROM Order o
JOIN o.properties p
WHERE p.type = ? AND p.value = ?
Доктрина не позволяет произвольно мапить таблицы на сущности. Одна таблица - одна сущность.
>>35578
Сущность не должна работать с репозиторием. Она лишь представляет одну запись в таблимце и не занимается извлечением оттуда чего-то еще. Твой метод getWeight элементарно реализуется через отношения. Ты можешь почитать про отношения между сущностями в Доктрине: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html
Если получать weight напрямую неэффективно или невозможно (у тебя тысячи свойств на один заказ), и тебе надо работать с репозиторием, то метод getWeight придется перенести в репозиторий тоже:
public function findWeight(Order $order)
> не надо заморачиваться с привязкой поля типа ENUM к сущности, т.к. он по дефолту в Доктрине не поддерживается
Ставится string и вроде как все работает.
> и можно как-то намного лучше и изящнее.
Можно взять в Order свойства заказа, перебрать их и найти то, которое отвечает за weight. Хотя я не понимаю, зачем это свойство сделано через EAV. Если оно есть у всех товаров, его проще было просто как поле сделать.
>>35658
Не понимаю, что печального. Так и надо делать.
Получишь свалку нетипизированных данных, только и всего.
>>35546
Никак. Искать по связанным полям:
SELECT o FROM Order o
JOIN o.properties p
WHERE p.type = ? AND p.value = ?
Доктрина не позволяет произвольно мапить таблицы на сущности. Одна таблица - одна сущность.
>>35578
Сущность не должна работать с репозиторием. Она лишь представляет одну запись в таблимце и не занимается извлечением оттуда чего-то еще. Твой метод getWeight элементарно реализуется через отношения. Ты можешь почитать про отношения между сущностями в Доктрине: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html
Если получать weight напрямую неэффективно или невозможно (у тебя тысячи свойств на один заказ), и тебе надо работать с репозиторием, то метод getWeight придется перенести в репозиторий тоже:
public function findWeight(Order $order)
> не надо заморачиваться с привязкой поля типа ENUM к сущности, т.к. он по дефолту в Доктрине не поддерживается
Ставится string и вроде как все работает.
> и можно как-то намного лучше и изящнее.
Можно взять в Order свойства заказа, перебрать их и найти то, которое отвечает за weight. Хотя я не понимаю, зачем это свойство сделано через EAV. Если оно есть у всех товаров, его проще было просто как поле сделать.
>>35658
Не понимаю, что печального. Так и надо делать.
У тебя ошибка в синтаксисе SQL-запроса. Значения из формы тут вряд ли при чем. Попробуй такой же запрос руками в консоли выполнить и посмотреть, что будет.
>>35741
Потому что в теле класса нельзя писать код вроде $this->var = '2ch';, а можно писать только определения констант, полей и методов. А вот уже в методах писать код можно. Класс это не функция.
Если что, у нас есть в шапке учебник и там есть глава про ООП.
>>36049
> Вторая - браузер может использовать для рендеринга вкладок на одном домене один и тот же процесс с целью оптимизации, в заивисмости от браузера и его настроек.
Маловероятно. Браузеры делаются, чтобы грузить страницы параллельно, единственное, если загрузка одной вкладки как-то умудряется подвесить процесс, то тогда возможно такое.
Проверить можно, открыв инструменты разработчика (Ctrl + Shift + I) на вкладке Network и посмотрев, где висит. Также, можно попробовать strace на сервере посмотреть, где ждет php-fpm/apache.
Я все же подозреваю, что у него где-то спрятан session_start про который он забыл - симптомы указывают на него.
>>36207
Это EAV.
Посмотри новую версию студентов https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3
Производительность при такой схеме с монтированием файлов не очень высокая может быть.
Вагрант пытается решить проблему настройки окружения для проекта. Современные горекодеры это слово я сам придумал пишут такой код, что он ломается даже от смены минорной версии библиотеки (не говоря о смене дистрибутива или, упаси, замене ОС на винду), потому они придумывают способы как-то зафиксировать конфигурацию системы, в которой проект точно работает, и запускать приложение именно в этой системе. Разработчики языков вроде Го тоже любят периодически ломать совместимость, что добавляет мотивации.
Вдобавок, если у тебя несколько проектов, то они могут требовать разные версии программ, а в линуксе (в отличие от виндоуз) поставить параллельно разные версии программ сложно - попробуй поставь без компилятора несколько версий PHP или mysql. (линуксоиды делают пакетный менеджер nix/guix, который должен решить эти и другие проблемы и вообще хорош, но им никто не пользуется).
В принципе, ничего плохого в этом нет. Мы ведь используем менеджер пакетов composer для указания зависимостей. Логично, что серверный софт вроде mysql или nginx это тоже зависимости приложения и их стоит описывать. Но почему для этого нужна целая виртуальная машина?
В моем понимании, хватило бы просто строчки в ридми apt-get install php mysql nginx. Не знаю, почему другие так не могут. Для моих проектов обычно этого хватает.
Мне все это не нравится, так как оно скорее всего тормозное, особенно на виндоуз. Требует много места на диске. Но может у тебя этих проблем не будет, а места предостаточно, кто знает.
Вагрант - позволяет настраивать виртуальную машину (virtual box) с помощью конфига на Руби. Обычно используется для описания среды для разработчика. При этом в конфиг можно включить установку в ВМ нужных программ. Про плюсы надо наверно читать документацию. Ну например, плюс то, что новый разработчик не должен мучаться с поиском и установкой программ, а просто выполняет одну команду и получает работающее окружение.
Как я понимаю, идея в том, что разработчик кладет в проект конфиг с описанием ВМ, а ты скачиваешь проект, запускаешь вагрант, он гудит пару часов и ты (если все хорошо и использованные пакеты не удалили из репозитория ОС) получаешь настроенную ОС в виртуалке, в которой проект 100% (а может и не 100) работает. Из минусов, как я понимаю, то, что там например может быть не тот дистрибутив, который тебе нравится, там может быть vi вместо нормального редактора, то есть все настроено не под тебя (как разработчик захотел, так и настроил). Плюс, виртуалка может работать медленно, занимать много места на диске. Ну например, вместо маленького дебиана кто-нибудь засунет туда многогигабайтный центос или десктопную убунту. Также, у тебя может быть например 3 Гб памяти, а кто-нибудь пропишет для виртуалки 2 Гб и она съест всю память.
Докер решает ту же проблему, описание зависимостей, но с кое-какими отличиями. Во-первых, под линуксом используется не виртуалка, а контейнеры, которые просто изолируют процессы от остальной системы и не снижают производительность. Но это только в линуксе - в винде или маке там виртуалка. Во-вторых, докер предлагает запускать контейнеры не только у разработчика, но и выгружать их на продакшен. Таким образом, разработчику теперь не нужен админ, он сам ставит любой софт путем модификации конфига докера. В-третьих, докер поддерживает кое-какие средства для генерации множества связанных контейнеров с прицелом на масштабирование на много серверов. Еще докер умеет оптимизировать хранение образов. Если у тебя есть базовый образ ОС, и ты добавляешь в него нгинкс, то он не создает новый огромный образ, а лишь сохраняет разницу между ними.
Также докер упрощает взаимодействие контейнера с хостом - тебе не надо руками пробрасывать папки, TCP-соединения, он все это делает сам.
Выглядит это так же, в репозиторий кладется конфиг, разработчик запускает докер и через какое-то время получает либо контейнер(ы) с запущенным в нем приложением, либо виртуалку.
Из плюсов - там есть хранилище готовых образов (Docker Hub).
Минусы те же, что и у вагранта. Образ могут настроить не так, как тебе нравится (и скорее всего так и будет). Плюс, не знаю, как сейчас, а раньше демон докера работал из-под рута.
Некоторые пытаются использовать докер как песочницу для запуска недоверенного кода, хотя в документации написано, что такой функицонал не предусмотрен.
Докеру есть альтернатива - lxc. Это свободный инструмент для запуска линукс-контейнеров. Плюсы в том, что его пишут не хипстеры на Го, а серьезные дядьки из Интел и они не навязывают какие-то паттерны использования, минусы в том, что когда я его последний раз пробовал, там многие вещи не работали вообще. Ну и фич меньше чем у докера.
Ансибл - позволяет на основе конфига (они называются плейбуки) настраивать по SSH сервер или группу серверов, можно использовать для деплоя (когда серверов много), для настройки серверов. Ну например, админ может сделать плейбук "поставить nginx, php, postgres" и в одну команду сконфигурировать чистый сервер или несколько серверов вместо того, чтобы заходить на каждый и что-то там править руками.
Хотя мне он не нравится тем, что ему нужен inventory файл и нельзя просто IP сервера в командной строке указать. Плюс, не работает под виндой нормально и под cygwin. Я хотел сделать на его основе playbook, который разворачивает VPN на произвольной чистой машине, но из-за inventory это не удобно и я вернулся к bash скриптам, у которых конечно корявый синтаксис, но нет такой проблемы.
> Встречал в интернете упоминания о том, что на докере/вагранте разворачивают себе рабочее окружение и мне стало интересно насколько это будет удобнее (и будет ли)
Ну проверь.
Производительность при такой схеме с монтированием файлов не очень высокая может быть.
Вагрант пытается решить проблему настройки окружения для проекта. Современные горекодеры это слово я сам придумал пишут такой код, что он ломается даже от смены минорной версии библиотеки (не говоря о смене дистрибутива или, упаси, замене ОС на винду), потому они придумывают способы как-то зафиксировать конфигурацию системы, в которой проект точно работает, и запускать приложение именно в этой системе. Разработчики языков вроде Го тоже любят периодически ломать совместимость, что добавляет мотивации.
Вдобавок, если у тебя несколько проектов, то они могут требовать разные версии программ, а в линуксе (в отличие от виндоуз) поставить параллельно разные версии программ сложно - попробуй поставь без компилятора несколько версий PHP или mysql. (линуксоиды делают пакетный менеджер nix/guix, который должен решить эти и другие проблемы и вообще хорош, но им никто не пользуется).
В принципе, ничего плохого в этом нет. Мы ведь используем менеджер пакетов composer для указания зависимостей. Логично, что серверный софт вроде mysql или nginx это тоже зависимости приложения и их стоит описывать. Но почему для этого нужна целая виртуальная машина?
В моем понимании, хватило бы просто строчки в ридми apt-get install php mysql nginx. Не знаю, почему другие так не могут. Для моих проектов обычно этого хватает.
Мне все это не нравится, так как оно скорее всего тормозное, особенно на виндоуз. Требует много места на диске. Но может у тебя этих проблем не будет, а места предостаточно, кто знает.
Вагрант - позволяет настраивать виртуальную машину (virtual box) с помощью конфига на Руби. Обычно используется для описания среды для разработчика. При этом в конфиг можно включить установку в ВМ нужных программ. Про плюсы надо наверно читать документацию. Ну например, плюс то, что новый разработчик не должен мучаться с поиском и установкой программ, а просто выполняет одну команду и получает работающее окружение.
Как я понимаю, идея в том, что разработчик кладет в проект конфиг с описанием ВМ, а ты скачиваешь проект, запускаешь вагрант, он гудит пару часов и ты (если все хорошо и использованные пакеты не удалили из репозитория ОС) получаешь настроенную ОС в виртуалке, в которой проект 100% (а может и не 100) работает. Из минусов, как я понимаю, то, что там например может быть не тот дистрибутив, который тебе нравится, там может быть vi вместо нормального редактора, то есть все настроено не под тебя (как разработчик захотел, так и настроил). Плюс, виртуалка может работать медленно, занимать много места на диске. Ну например, вместо маленького дебиана кто-нибудь засунет туда многогигабайтный центос или десктопную убунту. Также, у тебя может быть например 3 Гб памяти, а кто-нибудь пропишет для виртуалки 2 Гб и она съест всю память.
Докер решает ту же проблему, описание зависимостей, но с кое-какими отличиями. Во-первых, под линуксом используется не виртуалка, а контейнеры, которые просто изолируют процессы от остальной системы и не снижают производительность. Но это только в линуксе - в винде или маке там виртуалка. Во-вторых, докер предлагает запускать контейнеры не только у разработчика, но и выгружать их на продакшен. Таким образом, разработчику теперь не нужен админ, он сам ставит любой софт путем модификации конфига докера. В-третьих, докер поддерживает кое-какие средства для генерации множества связанных контейнеров с прицелом на масштабирование на много серверов. Еще докер умеет оптимизировать хранение образов. Если у тебя есть базовый образ ОС, и ты добавляешь в него нгинкс, то он не создает новый огромный образ, а лишь сохраняет разницу между ними.
Также докер упрощает взаимодействие контейнера с хостом - тебе не надо руками пробрасывать папки, TCP-соединения, он все это делает сам.
Выглядит это так же, в репозиторий кладется конфиг, разработчик запускает докер и через какое-то время получает либо контейнер(ы) с запущенным в нем приложением, либо виртуалку.
Из плюсов - там есть хранилище готовых образов (Docker Hub).
Минусы те же, что и у вагранта. Образ могут настроить не так, как тебе нравится (и скорее всего так и будет). Плюс, не знаю, как сейчас, а раньше демон докера работал из-под рута.
Некоторые пытаются использовать докер как песочницу для запуска недоверенного кода, хотя в документации написано, что такой функицонал не предусмотрен.
Докеру есть альтернатива - lxc. Это свободный инструмент для запуска линукс-контейнеров. Плюсы в том, что его пишут не хипстеры на Го, а серьезные дядьки из Интел и они не навязывают какие-то паттерны использования, минусы в том, что когда я его последний раз пробовал, там многие вещи не работали вообще. Ну и фич меньше чем у докера.
Ансибл - позволяет на основе конфига (они называются плейбуки) настраивать по SSH сервер или группу серверов, можно использовать для деплоя (когда серверов много), для настройки серверов. Ну например, админ может сделать плейбук "поставить nginx, php, postgres" и в одну команду сконфигурировать чистый сервер или несколько серверов вместо того, чтобы заходить на каждый и что-то там править руками.
Хотя мне он не нравится тем, что ему нужен inventory файл и нельзя просто IP сервера в командной строке указать. Плюс, не работает под виндой нормально и под cygwin. Я хотел сделать на его основе playbook, который разворачивает VPN на произвольной чистой машине, но из-за inventory это не удобно и я вернулся к bash скриптам, у которых конечно корявый синтаксис, но нет такой проблемы.
> Встречал в интернете упоминания о том, что на докере/вагранте разворачивают себе рабочее окружение и мне стало интересно насколько это будет удобнее (и будет ли)
Ну проверь.
Я не очень понимаю, как что у тебя сделано, но конечно, тут надо использовать параметры роутов, чтобы был роут вроде /articles/{topic}/, то есть где раздел задан параметром. Контроллер смотрит на параметр и находит статьи из нужного раздела.
Если у тебя 2 уровня категорий, разделы и секции, то нужен еще роут /articles/{topic}/{section}/
Если тебе непонятна документация, дай ссылку и напиши, какая именно фраза непонятна. Так я вряд ли что-то могу подсказать.
Также, если я верно понял, у тебя несколько таблиц со статьями, это все дурь, и хватит одной таблицы статей. Плюс, таблица разделов и таблица секций. Но тут еще стоит подумать об объединении их в одну таблицу с деревом категорий. Так как интуиция мне подсказывает что это просто категории.
Ты, к сожалению, так описал вопрос, что я ничего не могу понять:
- Чем раздел отличается от секции.
> Например, при переходе к статьям articles_IT
Что такое "статьи articles_IT"? Название роута? Название категории статей?
>>36373
Твой вопрос какой-то странный. Давай лучше рассмотрим товары. Правильно было написать "Есть таблица товаров, товары разной категории, у них бывают разные свойства. В чем плюсы/минусы EAV в сравнении с просто добавлением полей в таблицу с товарами (single table)". И как разные варианты реализовать с помощью ORM.
Вообще, надо начать с формулирования задачи. А она ставится так: есть сущность товар, есть разные варианты товаров, у каждого варианта есть свои наборы свойств (у телевизора - размер экрана, у стиральной машины - число оборотов).
Это называется "наследование таблиц", и там есть разные паттерны:
- http://design-pattern.ru/patterns/single-table-inheritance.html
- http://design-pattern.ru/patterns/concrete-table-inheritance.html
- http://design-pattern.ru/patterns/class-table-inheritance.html
То, что ты предлагаешь, добавлять колонки в одну таблицу - это как раз паттерн Single Table Inheritance.
Два других паттерна плохо работают для товаров, так как потребуют много таблиц, по числу категорий товаров. Тут-то на помощь и приходит EAV.
ORM тут надо рассматривать во вторую очередь, так как нормальный ORM большинство этих паттернов поддерживает.
Сравниваем:
Плюсы EAV:
- в EAV новые свойства можно добавлять не меняя схему базы данных (не делая ALTER TABLE). Менеджер может делать это через админку, не привлекая программиста. В случае ORM, надо еще переделывать код при добавлении новых свойств.
- в схеме с single table (когда у нас есть одна таблица товара с кучей колонок), если свойств много, то колонок тоже будет очень много - сотни, и мы упремся в разные ограничения БД и потери производительности. В случае ORM, у нас еще будет гигантский класс с сотней полей, с которым неудобно работать.
- в single table, если свойств много, то большинство колонок будут хранить null и просто зря расходовать место
- в single table никак не определено, какие свойства могут быть у той или иной категории товара. В EAV это можно определить через связи.
- в single table для эффективного поиска надо создавать огромное число (десятки и сотни) индексов, что негативно скажется на производительности и требует кучу места
Минусы EAV:
- запросы будут с джойнами и в неумелых руках могут работать медленно
- вытягивание данных по одному или нескольким товарам может быть чуть медленнее
- поиск по нескольким условиям потребует нетривиальной комбинации джойнов (чем больше условий тем больше джойнов) и могут быть проблемы с производительностью.
Если появляются проблемы с поиском, то проще всего подключить поисковый демон вроде сфинкса, который будет держать внутри данные в денормализованном и удобном для поиска виде.
Если ты знаешь еще минусы, напиши. Но я смотрю на список плюсов/минусов и не понимаю, где выигрыш в использовании Single Table Inheritance.
> если у нас есть доп.таблица user_attributes(age, sex)
То не очень понятно, зачем она нужна и что мешает эти колонки сразу поместить в таблицу users. Не понятно, зачем вы городите EAV для таблицы пользователей, которые явно отличаются от товаров. Ради производительности?
> то мы сущности User (которая лежит в таблице users) можем задать поле $sex, которое по связи OneToOne будет ссылать на столбец sex из таблицы с аттрибутами.
Не можем. Мы не можем в одном классе замапить поле на колонку из другой таблицы. Мы можем только связать поле с другой сущностью (user_attributes).
> а если у таблицы структура users_attributes(param enum('age','sex'), value), то мы так сделать уже не можем.
Доктрина так не работает. Она мапит таблицы на классы так, что одна таблица обычно соответствует одному классу, а колонки в таблице - полям класса. Нельзя в один класс замапить колонки из разных таблиц.
Но это и не нужно. Ты в сущности User можешь получить атрибуты и найти в них то, что тебе нужно.
> можно было бы сказать, что так мы можем добавлять любое количество параметров без изменения таблицы, но это не так - все равно придется менять столбец param - добавлять в него разрешенные значения.
Это у вас не EAV. В EAV для разрешенных значений обычно делают таблицу.
> короче я не понимаю, в чем плюсы.
Скорее всего там у пользователя много атрибутов, большинство их не заполняет и им не хочется хранить NULL. Но вообще, почему так сделано, надо спрашивать у тех, кто это делал.
Я не очень понимаю, как что у тебя сделано, но конечно, тут надо использовать параметры роутов, чтобы был роут вроде /articles/{topic}/, то есть где раздел задан параметром. Контроллер смотрит на параметр и находит статьи из нужного раздела.
Если у тебя 2 уровня категорий, разделы и секции, то нужен еще роут /articles/{topic}/{section}/
Если тебе непонятна документация, дай ссылку и напиши, какая именно фраза непонятна. Так я вряд ли что-то могу подсказать.
Также, если я верно понял, у тебя несколько таблиц со статьями, это все дурь, и хватит одной таблицы статей. Плюс, таблица разделов и таблица секций. Но тут еще стоит подумать об объединении их в одну таблицу с деревом категорий. Так как интуиция мне подсказывает что это просто категории.
Ты, к сожалению, так описал вопрос, что я ничего не могу понять:
- Чем раздел отличается от секции.
> Например, при переходе к статьям articles_IT
Что такое "статьи articles_IT"? Название роута? Название категории статей?
>>36373
Твой вопрос какой-то странный. Давай лучше рассмотрим товары. Правильно было написать "Есть таблица товаров, товары разной категории, у них бывают разные свойства. В чем плюсы/минусы EAV в сравнении с просто добавлением полей в таблицу с товарами (single table)". И как разные варианты реализовать с помощью ORM.
Вообще, надо начать с формулирования задачи. А она ставится так: есть сущность товар, есть разные варианты товаров, у каждого варианта есть свои наборы свойств (у телевизора - размер экрана, у стиральной машины - число оборотов).
Это называется "наследование таблиц", и там есть разные паттерны:
- http://design-pattern.ru/patterns/single-table-inheritance.html
- http://design-pattern.ru/patterns/concrete-table-inheritance.html
- http://design-pattern.ru/patterns/class-table-inheritance.html
То, что ты предлагаешь, добавлять колонки в одну таблицу - это как раз паттерн Single Table Inheritance.
Два других паттерна плохо работают для товаров, так как потребуют много таблиц, по числу категорий товаров. Тут-то на помощь и приходит EAV.
ORM тут надо рассматривать во вторую очередь, так как нормальный ORM большинство этих паттернов поддерживает.
Сравниваем:
Плюсы EAV:
- в EAV новые свойства можно добавлять не меняя схему базы данных (не делая ALTER TABLE). Менеджер может делать это через админку, не привлекая программиста. В случае ORM, надо еще переделывать код при добавлении новых свойств.
- в схеме с single table (когда у нас есть одна таблица товара с кучей колонок), если свойств много, то колонок тоже будет очень много - сотни, и мы упремся в разные ограничения БД и потери производительности. В случае ORM, у нас еще будет гигантский класс с сотней полей, с которым неудобно работать.
- в single table, если свойств много, то большинство колонок будут хранить null и просто зря расходовать место
- в single table никак не определено, какие свойства могут быть у той или иной категории товара. В EAV это можно определить через связи.
- в single table для эффективного поиска надо создавать огромное число (десятки и сотни) индексов, что негативно скажется на производительности и требует кучу места
Минусы EAV:
- запросы будут с джойнами и в неумелых руках могут работать медленно
- вытягивание данных по одному или нескольким товарам может быть чуть медленнее
- поиск по нескольким условиям потребует нетривиальной комбинации джойнов (чем больше условий тем больше джойнов) и могут быть проблемы с производительностью.
Если появляются проблемы с поиском, то проще всего подключить поисковый демон вроде сфинкса, который будет держать внутри данные в денормализованном и удобном для поиска виде.
Если ты знаешь еще минусы, напиши. Но я смотрю на список плюсов/минусов и не понимаю, где выигрыш в использовании Single Table Inheritance.
> если у нас есть доп.таблица user_attributes(age, sex)
То не очень понятно, зачем она нужна и что мешает эти колонки сразу поместить в таблицу users. Не понятно, зачем вы городите EAV для таблицы пользователей, которые явно отличаются от товаров. Ради производительности?
> то мы сущности User (которая лежит в таблице users) можем задать поле $sex, которое по связи OneToOne будет ссылать на столбец sex из таблицы с аттрибутами.
Не можем. Мы не можем в одном классе замапить поле на колонку из другой таблицы. Мы можем только связать поле с другой сущностью (user_attributes).
> а если у таблицы структура users_attributes(param enum('age','sex'), value), то мы так сделать уже не можем.
Доктрина так не работает. Она мапит таблицы на классы так, что одна таблица обычно соответствует одному классу, а колонки в таблице - полям класса. Нельзя в один класс замапить колонки из разных таблиц.
Но это и не нужно. Ты в сущности User можешь получить атрибуты и найти в них то, что тебе нужно.
> можно было бы сказать, что так мы можем добавлять любое количество параметров без изменения таблицы, но это не так - все равно придется менять столбец param - добавлять в него разрешенные значения.
Это у вас не EAV. В EAV для разрешенных значений обычно делают таблицу.
> короче я не понимаю, в чем плюсы.
Скорее всего там у пользователя много атрибутов, большинство их не заполняет и им не хочется хранить NULL. Но вообще, почему так сделано, надо спрашивать у тех, кто это делал.
> Допустим, я подобрал для сотен тысяч форму слова, отбросив по три цифры с концов, а на деле число оказалось миллиардом. Остальные шесть цифр не переведутся же.
Если тебе нужно число тысяч (от 0 до 999) то ты сначала берешь 6 последних цифр числа, потом отбрасываешь 3 последние цифры. И остается ровно 3 цифры, больше 1000 там никогда не получится.
Если тебе нужно число единиц, ты опять же, берешь только 3 последние цифры и больше 999 там не получится.
Плюс, в условии задачи вроде стоит ограничение, что число меньше миллиарда. То есть оно разбивается на 3 группы по 3 цифры каждая. Миллионы, тысячи и единицы. Можешь для надежности сделать 4 группы - добавить миллиарды.
>>36720
АПИ это не твоя база данных и оно не позволит тебе быстро получать данные по тысячам пользователей. Сначала оно будет тормозить, а потом ты получишь бан за превышение квоты. Я бы советовал перенести информацию об аватарках в базу данных.
Иначе тебе придется делать полноценный планировщик запросов, который должен формировать SQL запросы, запросы к API и объединять их результаты. Попробуй написать выражение посложнее чем A AND B и ты увидишь, как там все запутанно.
Тебе надо формировать условие из того, что предлагает Query Builder, все эти $expr->equals(...).
>>36874
Какие именно символы? Вот, например, регулярка, которая ищет восклицательные и вопросительные знаки:
/[?!]/u
Это символьные классы: http://php.net/manual/ru/regexp.reference.character-classes.php
Или тебе надо искать "все символы из всех алфавитов мира"? для этого есть юникодные свойства: http://php.net/manual/ru/regexp.reference.unicode.php
> Допустим, я подобрал для сотен тысяч форму слова, отбросив по три цифры с концов, а на деле число оказалось миллиардом. Остальные шесть цифр не переведутся же.
Если тебе нужно число тысяч (от 0 до 999) то ты сначала берешь 6 последних цифр числа, потом отбрасываешь 3 последние цифры. И остается ровно 3 цифры, больше 1000 там никогда не получится.
Если тебе нужно число единиц, ты опять же, берешь только 3 последние цифры и больше 999 там не получится.
Плюс, в условии задачи вроде стоит ограничение, что число меньше миллиарда. То есть оно разбивается на 3 группы по 3 цифры каждая. Миллионы, тысячи и единицы. Можешь для надежности сделать 4 группы - добавить миллиарды.
>>36720
АПИ это не твоя база данных и оно не позволит тебе быстро получать данные по тысячам пользователей. Сначала оно будет тормозить, а потом ты получишь бан за превышение квоты. Я бы советовал перенести информацию об аватарках в базу данных.
Иначе тебе придется делать полноценный планировщик запросов, который должен формировать SQL запросы, запросы к API и объединять их результаты. Попробуй написать выражение посложнее чем A AND B и ты увидишь, как там все запутанно.
Тебе надо формировать условие из того, что предлагает Query Builder, все эти $expr->equals(...).
>>36874
Какие именно символы? Вот, например, регулярка, которая ищет восклицательные и вопросительные знаки:
/[?!]/u
Это символьные классы: http://php.net/manual/ru/regexp.reference.character-classes.php
Или тебе надо искать "все символы из всех алфавитов мира"? для этого есть юникодные свойства: http://php.net/manual/ru/regexp.reference.unicode.php
Сокеты тут зачем? Тут же не чат. Тут просто пользователь меняет параметры и у него должна обновиться картинка. Сокеты тут не нужны и только все осложнят. Хватит аякса. А может даже это все можно рендерить на стороне браузера не дергая сервер.
> с которыми шикарно работает РНР
Если ты про ReactPHP, то он на мой взгляд не шикарный. Работа с исключениями там сломана везде - в промисах, в потоках. Как и в ноде, впрочем.
Нужен ридми. Прочитай комментарии к задаче, там это написано: https://github.com/codedokode/pasta/blob/master/student-list.md#Публикация-проекта
А то открываешь, видишь кучу файлов и даже непонятно, что это.
Файлы примеров желательно удалить. Вот зачем нужен этот файл например? https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/tests/Feature/ExampleTest.php
Если ты не используешь тесты, то файлы от них не нужно добавлять.
А вообще, Докер стал популярен с развитием облачных платформ. Чтобы сделать приложение независимым от используемой платформы и чтобы его можно было легко развернуть.
Особенно если у тебя какое-то масштабируемое приложение и тебе надо автоматически добавлять новые сервера.
Проблемой докера еще называют сложности с обновлением - в том же докер хабе может быть куча старых образов с незакрытыми уязвимостями.
Ну и статью вот сегодня увидел про контейнеры: https://queue.acm.org/detail.cfm?id=3185224
Читать учебники - хватит. А вот можно ли туда поставить php/mysql - большой вопрос. Какой там процессор? Какая архитектура? Есть ли рут?
То, что там windows не значит, что приложения для десктопа там запустятся. Или все же запустятся?
спасибо! не знал про EAV, буду изучать.
я не могу назвать минусы EAV, так как только что о нем узнал. по минусам той таблицы, которую мне дал работодатель, я могу сказать, что там все равно менеджер не добавит без программиста новое поле, т.к. там названия полей добавлены в колонку с типом enum, ее все равно надо будет менять. но, как ты сказал, у тут не EAV.
>>37301
>придется делать полноценный планировщик запросов
ну это тестовое задание в одну контору, там таблицы уже даны и менять их нельзя. предполагается (видимо), что будет написан этот самый планировщик с приоритетами запросов, а обращение к тысячам пользователей неактуально.
>Попробуй написать выражение посложнее чем A AND B
да, там получаются пугающие конструкции
atom/vscode?
Львиная доля работы, у меня, проходила только в нотпаде. Его хватало с головой. А так, есть ещё Brackets, от Adobe. Сорта говен. Когда пд рукой тяжелые проекты, то потребуется какая-нибудь IDE, чтоб проводник в интерфейсе был, да и наглядность проекта не страдала.
Хватит конечно, даже меньше. Майскул будет потреблять столько, сколько ты ему пропишешь в конфиге, если база маленькая, то сотни Мб хватит. PHP скрипты обычно потребляют в районе 50 Мб, но композер с большим числом пакетов может иногда и гиг откушать - тут вся надежда на своп.
Что-то типа "СоздательКонтента", но не так по-уебански. Фантазия закончилась
лол, ты не поверишь, я пока так и назвал сам.
хотя это не совсем точно, он ведь его не делает, а добавляет - делает-то его твиттер.
но думаю, так тоже ок.
Хорошо, большое спасибо!
Большое спасибо, именно то, что мне хотелось прочитать!
ЗЫ редирект надо на то место на странице, откуда был произведен переход. Т.е. скроллю страницу, клацнул линк, перешел и что-то сделал, затем обратно.
Кун с тех вышкой, не ит
Да, шансы высоки.
Всё равно не работает!
будут большие шансы, что через неделю ты без вести пропадешь из треда
TweetLoader, TweetScraper.
>>37490
Берешь любой алгоритм поиска пути вроде https://ru.wikipedia.org/wiki/Алгоритм_Дейкстры и ищешь его реализации на нужном тебе языке.
>>37577
Не дам тебе ничего по сессиям, но редиректы и куки описаны в моем уроке по HTTP: https://github.com/codedokode/pasta/blob/master/network/http.md
>>37582
Это плохой вариант, плюс нет никакой проверки что в реферере, и есть ли он вообще, лучше явно указывать ?from=feed для указания, куда надо вернуться. Естественно, надо этот параметр тщательно проверять, чтобы не отправить юзера по какой-то плохой ссылке.
https://secure.php.net/manual/ru/function.str-getcsv.php
>enclosure
>Устанавливает символ ограничителя поля (только один символ).
Что такое ограничитель поля?
>escape
>Устанавливает экранирующий символ (только один символ). По умолчанию равен обратному слешу (\).
И от чего и что будет экранироваться?
Данные примерно в таком варианте
NAME
SOME_STRING = SOMEDATA
COLUMNS = something,another,somethinganother,...
1,135.02,135.09,133.25,133.47,33226223
2,135.51,136.27,134.62,135.52,35623100
3,135.345,135.9,134.8398,135.67,22584555
Нужно получить что-то вроде
[
"NAME",
"SOME_STRING" => "SOMEDATA",
"COLUMNS" => ["something", "another", "somethinganother", ...],
"DATA" => [[1, 135.02, 135.09, 133.25, 133.47, 33226223 ], [2, 135.51, 136.27, 134.62, 135.52, 35623100], [3, 135.345, 135.9, 134.8398, 135.67, 22584555]]
]
Текущих знаний мне хватает чтобы спарсить каждую строчку с помощью str_getcsv($s, "\n"), и затем вручную преобразовать массив с помощью регулярных выражений
Это лучший способ и данная функция не предусматривает лучших решений?
https://secure.php.net/manual/ru/function.str-getcsv.php
>enclosure
>Устанавливает символ ограничителя поля (только один символ).
Что такое ограничитель поля?
>escape
>Устанавливает экранирующий символ (только один символ). По умолчанию равен обратному слешу (\).
И от чего и что будет экранироваться?
Данные примерно в таком варианте
NAME
SOME_STRING = SOMEDATA
COLUMNS = something,another,somethinganother,...
1,135.02,135.09,133.25,133.47,33226223
2,135.51,136.27,134.62,135.52,35623100
3,135.345,135.9,134.8398,135.67,22584555
Нужно получить что-то вроде
[
"NAME",
"SOME_STRING" => "SOMEDATA",
"COLUMNS" => ["something", "another", "somethinganother", ...],
"DATA" => [[1, 135.02, 135.09, 133.25, 133.47, 33226223 ], [2, 135.51, 136.27, 134.62, 135.52, 35623100], [3, 135.345, 135.9, 134.8398, 135.67, 22584555]]
]
Текущих знаний мне хватает чтобы спарсить каждую строчку с помощью str_getcsv($s, "\n"), и затем вручную преобразовать массив с помощью регулярных выражений
Это лучший способ и данная функция не предусматривает лучших решений?
Заработало, спасибо.
dump(new \DateTime(1518441713));die;
выдает
DateTime @-8106433893 {#1894
date: 1713-02-12 15:18:44.0 Europe/Moscow (+02:30)
}
?
понял. он не понимает таймстамп, ему надо дату слать.
Глянь https://ru.wikipedia.org/wiki/CSV
Прочти это, там немного и на русском: http://tradeincome.ru/useful-content/RFC 4180 rus.pdf
Там определены 3 символа:
- разделитель полей (по ум. запятая)
- ограничитель поля, символ кавычки (то есть символ, в который можно заключать строки с пробелами и запятыми внутри)
- экранирующий символ (по ум. бекслеш). Он позволяет например вставить кавычку внутрь строки как \" Я не вижу его в RFC, может это какое-то дополнение. В RFC написано что кавычка вставляется как 2 кавычки и значит экранирующим символом должен быть не бекслеш, а кавычка.
> Что такое ограничитель поля?
Символ, в который можно заключить значение поля. По ум. двойная кавычка.
> И от чего и что будет экранироваться?
Если у тебя есть строка в кавычках "xxx" и тебе надо внутрь нее вставить кавычку, то можно писать "xx\"x" c использованием экранирующего символа. Я не вижу этой особенности в RFC, наверно это какое-то дополнение. В RFC экранирующий символ это кавычка и надо писать "xx""x"
> Это лучший способ
Вполне хороший способ.
Не знаю, это как-то само собой получается. Наверно учиться, читать документацию, ковырять код, расширять кругозор, читать хабр, news.ycombinator.com. Вот кстати, если ты все задачи из шапки решишь, думаю, получится неплохое начало.
Ну и я не так и много знаю - на Хаскелле написать программу не смогу и рассчитать нейронную сеть тоже вряд ли.
Также, не ограничивай себя одним языком, или только высокоуровневыми скриптовыми языками, изучай разные вещи.
define программист
vk это тоже spa
и они не использзуют ни ангуляров ни реактов, ничего, все на ваниле
так что дело лишь в твоих прямых руках
Счас бы вк написать.
>Таким образом, у тебя есть выбор из как минимум
>backbone + knockout angular 2 react + redux vue.js
ОП требует фреймворк!
И да, на ванилле я охуею писать все это, я не смогую.
Пиши на ваниле. Потихонечку захочется согласованности данных, инъекций зависимостей, реактивности и прочего. В результате через пару лет напишешь свой гуляр, только кривой.
Сложный он потому, что сложен из множества решений, которые необходимы для больших команд и длительной поддержки. А тебе они не очевидны потому, что у тебя таких потребностей не возникает пока.
>Счас бы вк написать.
Это как пример большого весьма сложно SPA, написанного без хайп-фреймворков. И работающий, заметь, быстрее чем те же фейсбук и инстаграм на реактах.
>Какие именно символы?
Я имел ввиду всё, кроме букв и цифр, но сейчас внезапно сам во всём разобрался
оказалось достаточно было написать \\D вместо \D
т.е.
class Tag
{
/
@var ArrayCollection
@ORM\ManyToMany(targetEntity="Article", mappedBy="tags")
/
private $articles;
пока придумал только так:
return $qb
->select('t')
->from('App:Tag', 't')
->addSelect('COUNT(a.id) as HIDDEN articles')
->join('t.articles', 'a')
->groupBy('t.id')
->orderBy('articles', 'DESC')
->getQuery()
->getResult();
есть какой-то более очевидный способ? задача-то, мне кажется, типовая
Вконтакте не SPA. Там используется штука вроде pajax, то есть оно перехватывает клики по ссылкам, отправляет аякс-запрос и обновляет DOM. По сути только экономит немного времени на перезагрузке страницы. Он не хранит данные локально, не работает в оффлайне, итд.
Не надо так писать. У нас к анонам нет требований, чтобы они знали английский. Изучать PHP можно и без его знания.
Но, конечно, когда ты показываешь код другому, этот транслит в именах переменных или функций бросается в глаза. Потому, что так сложилось, что переменные называют по-английски, и не нам эти правила менять. (хотя сам PHP позволяет использовать кириллицу в именах: $месяц = 1; например).
Потому стоит в таких случаях открывать translate.google.com и подбирать нужный перевод. Так. даже не зная английского, можно давать удачные имена переменным.
Ну и конечно, анону, если он не знает английский, стоило бы потихоньку начинать его осваивать. Наверняка на собеседовании про знание английского спросят, и знать какие-то основы лучше, чем ничего. Уроков для начинающих, я думаю, в интернете полно.
У тебя в условии цикла for стоит $mesyac <=0 то есть цикл выполняется только ПРИ УСЛОВИИ ЧТО месяц меньше или равен нулю. Это условие не выполняется и цикл потому не выполняется не разу.
fl.ru, upwork если на проект
с таким подходом денег и не будет много. какие блядь курсы? в инторнете что ли мало бесплатных ресурсов для изучения языка?
Есть две переменные: $query и $content.
В $query, например, лежит "foo bar", а в $content "bar baz baz foo".
Задача: заменить в $content каждое найденное слово на его же, окруженное в <i></i>. Я делаю это костыльно вот так:
$pattern = explode(' ', $query);
foreach ($pattern as $item) {
$content = preg_replace("~$item~", "<i>$item</i>", $content);
}
Но это говно, т.к. несколько раз выполняется preg_replace. Думал сделать как-то типа
$pattern = preg_replace(' ', '|', $query);
$content = preg_replace("~($item)~", "<i>$item</i>", $content);
Но каждый раз подставляется foo|bar. Как можно решить задачу, используя переменные рерулярок типа (?<item>.+?)?
>какие блядь курсы?
Alibra School например, в прошлом году хотел пойти туда, но денег нет (они простят 30к за 9 месяцев обучения).
В интернете тяжело учить, пробовал duolingo, но мотивации не хватило и обучение мне показалось сомнительным.
не знаю, я начинал с того, что смотрел симпсонов на английском, а щас вообще не употребляю русский контент (кроме двачей, конечно). правда я этой хуйней много лет занимаюсь
у меня просто пунктик такой, мол стыдно английский не знать. поэтому я всегда если незнакомое слово встречаю, не подаю вида, а потом бегу в словарь смотрю.
Хотел сделать задачку, а она не решается (ну скорее Я тупой).
Типо:
1 год :
10000руб. x 1.1 = 11000 руб.
2год:
11000 руб. x 1.1 = 12100 руб.
3год:
12100 руб. x 1.1 = 13310 руб.
и т.д.
Но что-то пошло не так.
Ну а хули тут сложного, анонче? Нужно css загружать, да, чтобы он заменял собой исходный?
Ну, я бы сделал так.
Написал бы форму, которая отправляла бы css на сервер и упаковывала его в отдельную папочку. Путь к этому новому файлику прописывался бы куда-нибудь (в базу, например).
В базе (опять же, например), указано какой из файлов является в данный момент активным.
Вместо пути к статическому файлу в ссылке можно указать ссыль на файл-обработчик, типа ttps://site.ru/getcss.php
Там файл бы отдавал нужный (активный) файл, указывая необходимые заголовки.
Ну или тупо заменять один файл другим, если старый не нужен.
Я не уверен, что правильно понял твою задачу, анон, но она, в любом случае, не сложная. Тут не гуглить нужно, а включать воображение. Решить можно разными способами.
Две части задачи: загрузка файла на сервер и изменение css
По первому куча примеров в гугле. По второму, в принципе, тоже. Изменение css - это что-то типа вот этого кода (вытащил со своего проекта, суть, думаю, понятна):
$('#overlay').fadeIn(400, function(){ $('#popup')
.css('display', 'block')
.animate({opacity: 1, top: '50%'}, 200);});
Бля, я тупой, кажется. Неправильно понял. Сорянъ.
>$('#overlay').fadeIn(400, function(){ $('#popup')
>.css('display', 'block')
>.animate({opacity: 1, top: '50%'}, 200);});
Как я понимаю это окошко для загрузки и правило его анимации. Я полный нуп, крайне сложно вникать в это все.
Я в своей cms-ке сделал настройку темы через GUI (ну там, размеры шрифтов, цвета основных элементов, отступы и пр.) самым тупым способом - все данные храняться в базе в одном поле, которое сериализовано (количество полей статично, поэтому undefined index не будет), но в html-ке вся эта залупа выводится в теге style после подключения основных css.
Ну что-то типа
<style>
<?php if( $theme["background-color"] ):?>
body {background-color: #<?php echo $theme["background-color"]; ?>}
<?php endif; ?>
...
</style>
Да, довольно нубски, но какая разница? Работате же.
В противном случае, может есть шанс при загрузке генерировать отдельный css для background-image? Дополнительный css для фонового изображения типа. Там тупо вставляешь строку, дополняя путем до новой имаги.
Я имел в виду, что таким же образом ты можешь работать и с другими свойствами css. Например, backround-color
Там анону нужно только фоновую картинку загружать. Вместо скрипта генерации CSS проще нужные стили вписать в <style>.
Попробуй Vue.js, он проще и совместим с jQuery
правда, это бед практис
И вообще SPA можно и на jQuery написать
Вопрос в тему, на чем лучше попробовать написать фронтенд для браузерной игры?
>>38224
В /fl есть годные гайды по изучению английского. В этом, как раз главное погружение, та что когда пишешь код представляй что ты флюент и используй только английский.
Нет, но стоит понимать что происходит и как делается на фронте.
Но все сейчас хотят фулстеков т.е. бек + фронт,
правда во фронт не всегда входит вёрстка
По умолчанию открывается доступ ко всему, но все, кроме статики (js, css, картинки и прочее) редиректится на /index.php, где уже будет парситься REQUEST_URI и выдаваться 404-ошибка как для несуществующих файлов, так и для запрещенных к просмотру.
Есть ли у такого подхода какие-нибудь изъяны по сравнению со стандартным, когда с помощью htaccess закрывается доступ к папкам и файлам?
Процент по-английски это percent
У тебя небольшая проблема в том, что за счет break мы выходим из цикла и надо бы после цикла поставить echo с выводом итога. Вот это важная вещь, не забывать, что требовалось найти в задаче и вывести ответ. Если ты забываешь, то после написания программы перечитай задачу и проверь, дает ли твоя программа нужный ответ. Перечитай внимательно условие задачи сейчас.
Также, если ты почитаешь урок, то там было написано, что действия вроде
a = a + b;
можно записывать короче с помощью оператора
a += b;
Это может тут пригодиться.
Также, если ты посмотришь, то в шапке цикла стоит условие $total <= 1000000. Раз оно есть, то if с break не очень-то и нужен. Единственное, в условии неточность - если у нас уже есть ровно миллион, то цикл продолжать не надо. Выполнять цикл надо только пока денег меньше чем миллион.
>>38892
Не надо замусоривать тред не имеющими пользы комментариями. У нас учебный тред, а не пикабушечка.
Вместо того, чтобы закрывать доступ к каким-то файлам, лучше его не открывать с самого начала. Выдели отдельную публичную папку, и сделай ее корневой для сервера (как именно, зависит от используемого веб-сервера, обычно это настраивается в конфиге) так, что за ее пределами файлы вообще не могут быть доступны.
Вот тут немного описано это: https://github.com/codedokode/pasta/blob/master/student-list.md#Выносим-код-за-корень-сервера
>>38698
Какие-то простые вещи сверстать или поправить существующую верстку - конечно. Кстати, в ОП посте есть набор задач по HTML/CSS, после прохождения которого как раз будет нужный уровень.
>>38215
Тебе нужен preg_replace_callback либо preg_replace с массивом слов и замен. Посмотри мануал по этим функциям.
>>38456
Давай посмотрим на код. Вот у меня ощущение, что ты там некоторые вещи писал не осознанно, а просто наугад, в надежде что заработает. Так не надо делать, сейчас ты учишься и у тебя главная цель не решить задачу как можно быстрее, а разобраться в материале.
Для начала можно попробовать написать алгоритм словами (используя только простые команды, не допускающие двойного толкования). Команд у нас в распоряжении всего несколько:
$x = ... - создает переменную или меняет значение существующей
echo ... - выводит строки и числа, в том числе переменные
if (условие) { действия } - выполняет действия, если выполняется условие
for (...) { ... } - выполняет одни и те же действия много раз в цикле
break - немедленно выходит из цикла
Если ты забыл эти команды, перечитай предыдущие уроки или мануал PHP.
Если мы посмотрим на твой код, то мы увидим там куски, которые не имеют никакого смысла, например:
($rubley < 1000000);
Эта строчка проверяет, меньше ли $rubley чем указанная сумма, но с результатом проверки ничего не делает - она не сохраняет результат в переменную и не использует его в конструкции if. То есть она бесполезна.
Далее, если мы посмотрим сюда, то увидим другую ошибку:
$rubley = ($seychas * $procent) + $rubley;
Здесь справа использована переменная $seychas, но на момент выполнения команды такой переменной еще не существует. Строчка, которая ее создает, расположена ниже.
Ну и непонятно вообще, зачем тут для обозначения суммы на счете используется 2 разных переменных.
То есть выглядит, увы, не как осознанно написанный код.
Вернемся к алгоритму. Как бы его записать, используя только перечисленные выше команды? Ну например, так:
------
пусть суммаНаСчету равна 10000;
пусть процент равен 1.1;
меняем возраст вкладчика от 16 до 108 лет с шагом 1 год, выполняя каждый год {
увеличить суммуНаСчету на процент;
если (на счету миллион или больше) {
выйти из цикла;
}
увеличить возраст вкладчика;
}
вывести ответ к задаче;
------
Ну а дальше надо переписать это с помощью команд выше.
Вообще, тут ключевое место алгоритма еще можно записать по-другому, более красиво:
пока (на счету меньше миллиона) {
увеличить сумму на счету;
увеличить возраст на 1;
}
Но как эту конструкцию "пока" перевести в код? Тут есть такой вариант:
for (; $sum < 1000000 ;) {
...
}
(если ты забыл,что это значит, перечитай урок про циклы внимательно). Мы не пишем в шапке цикла начальное действие и действие, которое выполняется после каждого шага, а оставили только условие продолжения. Но для таких случаев есть более короткая запись - цикл while:
while ($sum < 1000000) {
тело цикла выполняется до тех пор, пока условие вверху выполняется;
}
Подробнее: http://php.net/manual/ru/control-structures.while.php
Также, перечитай внимательно условие задачи и убедись, что твоя программа выводит все, что требуется.
Если что-то непонятно, задавай вопросы.
Вместо того, чтобы закрывать доступ к каким-то файлам, лучше его не открывать с самого начала. Выдели отдельную публичную папку, и сделай ее корневой для сервера (как именно, зависит от используемого веб-сервера, обычно это настраивается в конфиге) так, что за ее пределами файлы вообще не могут быть доступны.
Вот тут немного описано это: https://github.com/codedokode/pasta/blob/master/student-list.md#Выносим-код-за-корень-сервера
>>38698
Какие-то простые вещи сверстать или поправить существующую верстку - конечно. Кстати, в ОП посте есть набор задач по HTML/CSS, после прохождения которого как раз будет нужный уровень.
>>38215
Тебе нужен preg_replace_callback либо preg_replace с массивом слов и замен. Посмотри мануал по этим функциям.
>>38456
Давай посмотрим на код. Вот у меня ощущение, что ты там некоторые вещи писал не осознанно, а просто наугад, в надежде что заработает. Так не надо делать, сейчас ты учишься и у тебя главная цель не решить задачу как можно быстрее, а разобраться в материале.
Для начала можно попробовать написать алгоритм словами (используя только простые команды, не допускающие двойного толкования). Команд у нас в распоряжении всего несколько:
$x = ... - создает переменную или меняет значение существующей
echo ... - выводит строки и числа, в том числе переменные
if (условие) { действия } - выполняет действия, если выполняется условие
for (...) { ... } - выполняет одни и те же действия много раз в цикле
break - немедленно выходит из цикла
Если ты забыл эти команды, перечитай предыдущие уроки или мануал PHP.
Если мы посмотрим на твой код, то мы увидим там куски, которые не имеют никакого смысла, например:
($rubley < 1000000);
Эта строчка проверяет, меньше ли $rubley чем указанная сумма, но с результатом проверки ничего не делает - она не сохраняет результат в переменную и не использует его в конструкции if. То есть она бесполезна.
Далее, если мы посмотрим сюда, то увидим другую ошибку:
$rubley = ($seychas * $procent) + $rubley;
Здесь справа использована переменная $seychas, но на момент выполнения команды такой переменной еще не существует. Строчка, которая ее создает, расположена ниже.
Ну и непонятно вообще, зачем тут для обозначения суммы на счете используется 2 разных переменных.
То есть выглядит, увы, не как осознанно написанный код.
Вернемся к алгоритму. Как бы его записать, используя только перечисленные выше команды? Ну например, так:
------
пусть суммаНаСчету равна 10000;
пусть процент равен 1.1;
меняем возраст вкладчика от 16 до 108 лет с шагом 1 год, выполняя каждый год {
увеличить суммуНаСчету на процент;
если (на счету миллион или больше) {
выйти из цикла;
}
увеличить возраст вкладчика;
}
вывести ответ к задаче;
------
Ну а дальше надо переписать это с помощью команд выше.
Вообще, тут ключевое место алгоритма еще можно записать по-другому, более красиво:
пока (на счету меньше миллиона) {
увеличить сумму на счету;
увеличить возраст на 1;
}
Но как эту конструкцию "пока" перевести в код? Тут есть такой вариант:
for (; $sum < 1000000 ;) {
...
}
(если ты забыл,что это значит, перечитай урок про циклы внимательно). Мы не пишем в шапке цикла начальное действие и действие, которое выполняется после каждого шага, а оставили только условие продолжения. Но для таких случаев есть более короткая запись - цикл while:
while ($sum < 1000000) {
тело цикла выполняется до тех пор, пока условие вверху выполняется;
}
Подробнее: http://php.net/manual/ru/control-structures.while.php
Также, перечитай внимательно условие задачи и убедись, что твоя программа выводит все, что требуется.
Если что-то непонятно, задавай вопросы.
Пока еще не все, надо, чтобы выводился тот ответ, который требуется в задаче. А у тебя только какие-то отладочные данные, и непонятно, где окончательный ответ.
window.onload = function() {
btn.onclick = function() {
var test = document.getElementById('test'),
btn = document.getElementById('btn'),
my_img = document.createElement('img');
my_img.src = 'picture134.jpg';
test.appendChild(my_img);
что мне тут пофиксиить, чтобы появлялась только одна картинка и чтобы была пауза 5 секунд перед появлением.
Алсо добавь проверку, что картинка уже прикреплялась.
>Понял, спасибо, но не понял
Так ты понял или нет?
Не троллируй тутъ
по пхп нет хороших книг. их просто нет, прими это. зубри по мануалу. все твои вопросы (типы, функции для работы с массивами) там описаны.
алсо, на собеседованиях задают очень заковыристые вопросы, которые лучше искать в гугле по запросу "вопросы с собеседований".
Мне уже второй интервьюер (или как там их называют) втирает про то, что мне НАСТОЯТЕЛЬНО надо прочитать какую-нибудь книжку, потому что там "подробно разбирают сложные моменты" и "дают базу".
>"вопросы с собеседований".
Уже. Но там короткие ответы, а мне кроме них нужно потихоньку подтягивать "базу", чтобы отвечать более осмысленно.
Поле должно обрабатывать возраст спиногрызов.
Есть пример:
12
7 лет
1 год
4года
2,5
3 месяца
4 месяца
1.6
8 месяцев
1,5 года
1,7 года на время вылета
1год и 6месяцев
инфант
до 2х лет
6-7
Нужно как-то обрабатывать по формату число и его значение. Типа "9 лет", "8 месяцев" или "2 годика".
Я запилил свою:
'/[0-9месяцев\s]|[0-9года\s]|[0-9лет\s]*|[0-9]{1,2}/ui'
Но она почему-то пидорасит значения.
Спааааасибо, мил человек!
На простейших. Не помню html тег для нумерованного списка. Не помню название функций "переворачивания" массива и строки. Знаю, что они есть, но на память не помню. В общем, нужно именно зазубривание. Так-то уже начал с общей справочной информации, но в книгах ведь и правда более структурированный подход обычно.
Это нет смысла зубрить, это тупо.
Важно именно знать возможность наличия того или иного функционала в языке.
Обычно это приходит с практикой.
Я вот вообще плохо помню точные имена функций или тегов, всегда гуглю что бы перепроверить и всегда гуглю перед тем, как пилить какой либо свой велосипед.
По моему все книги это просто переписывание документации, ещё и пропущенной через автора, который сам мог многого не знать.
Можешь попробовать https://www.codewars.com,
это сборник задач, есть много базовых и 'классических',
как раз в том же PHP многие решает одна функция или так может показаться,
можно нарешать кучу задач и подтянуть эту базу.
>>39431
Копай в сторону preg_match_all
>>39419
Покажи код
>Это нет смысла зубрить, это тупо.
Согласен.
>Важно именно знать возможность наличия того или иного функционала в языке.
>Обычно это приходит с практикой.
Без пройденного собеседования нет практики. Я пилю свои проекты, но этого мало. Сегодня что-то использовал, а завтра уже забыл. Во всяком случае я забываю. Память плохая.
>в самом php-скрипте
Имеешь в виду, можно ли так исковеркать вводимые данные, чтобы выйти из строки и поменять логику скрипта? Нет.
Строка - это переменная, которая содержит последовательность байтов. И поебать вообще, что ты там напишешь. Проблемы начинаются, когда одна строка соединяется с другой. Для генерации SQL-запроса, например.
>в самом php-скрипте
Имеешь в виду, можно ли так исковеркать вводимые данные, чтобы выйти из строки и поменять логику скрипта? Нет.
Строка - это переменная, которая содержит последовательность байтов. И поебать вообще, что ты там напишешь. Проблемы начинаются, когда одна строка соединяется с другой. Для генерации SQL-запроса, например.
Што за долбоебизм? Невозможно помнить всё, да и не получится. Всё равно использовать 100% возможностей того или иного инструмента ты постоянно не будешь, что-то ты будешь помнить лучше, что-то хуже.
Знать, безусловно, нужно. Но знать нужно не названия функций, а возможности, которыми располагает тот или иной инструмент.
Я тоже не помню названий некоторых функций, но если мне понадобится, я за 15 секунд их найду, т.к. знаю что мне нужно.
Хороший интервьюрер будет проверять именно твое мышление, т.к. способность находить выход из трудных ситуаций, способность решать нестандартные задачи и пр. А не дрочить названия функций и тегов.
Они мне перезвонят.
По итогу у меня оффер на 40к. В ДС. Когда собеседовался на что-то повыше, каждый раз не проходил.
>Покажи код
Зачем?
Сам код здесь https://ideone.com/zQztaf , но я просто не видел смысла выкладывать его.
Но сразу кое-что скажу: это часть кода на 200 строк.
Я тогда его здесь выложу https://ideone.com/Lz5R9P .
Если не считать отсутствие PDO (мамой клянусь, на этой неделе исправлю это!), могут быть какие-то рекомендации по коду?
ind4:не пиши его больше
Ват? Это ж комменты, чтобы сам код был понятен! Что с ними не так-то?
Я бы советовал тебе сделать тесты. То есть сделать массив всех возможных фраз, и для каждой вписать правильный ответ. Затем в цикле брать каждую фразу, подавать ее на вход твоему коду и сравнивать ответ с правильным.
Так ты будешь всегда знать, насколько хорошо работает код, где он делает ошибки, улучшилось ли что-то после изменений.
скачать библиотеку в файле dll, положить в директорию c:\path\to\php\ext и прописать её в файле php.ini:
extension=php_yourlibrary.dll
Важный нюанс, что php.ini может находиться где угодно. Нужно найти все и прописать в каждый.
Узнать, где находится php.ini, можно вставив в скрипт phpinfo() и открыв его через браузер и веб-сервер.
Обратите внимание, что при запуске из командной строки может использоваться один php.ini, а из-под Апача - другой.
Допустим, у меня есть сайт с новостями, там на главной странице слева новости, а справа теги, допустим.
Я на ShowIndex() на ретурн подаю что-то типа
return this->render('index.html.twig', ['news' => $someNews, 'tags' => $popularTags]);
Далее у меня есть еще ShowArticle(), где в основной части страницы уже другая инфа - одна новость с комментами, а справа те же теги.
В итоге можно сделать так:
return this->render('article.html.twig', ['article' => $someArticle, 'tags' => $popularTags]);
но получается, если у меня 50 разных разделов, будет 50 раз дублироваться код получения тегов и код вставки этих тегов в шаблон. Более того, этот код может быть в разных контроллерах
Как принято избавляться от такого дублирования? Ведь на каждой странице может дублироваться инфа типа свойств аккаунта, всяких виджетов и еще кучи говна
Я пока придумал только что-то типа return this->render('article.html.twig', ['article' => $someArticle, 'tags' => $this->getPopularTags()]);
и наследовать контроллер от своего базового (который наследуется от симфоневского AbstractController) в котором в защищенные методы вынести эти обращения к доктрине. Есть еще варианты?
возможно интервьюер говорит тебе о книжках по программированию независимо от языка, а не про книжки на пхп.
не стремись вызубрить ответы на "вопросы с собеседований". стремить выучить сам язык и на практике попробовать как можно больше его возможностей. я перед первой работой зубрил про всякие статические переменные, передачу по ссылке и т.д., но не понимал зачем оно нужно и поэтому в момент стресса все забыл. сделай свой проект, дай местным анонам на проверку. пытаться выучить определения бессмысленно, тебя все равно спалят, поверь.
нормальных книг по пхп нет, забудь про них. тебе никто не разжует и не вложит в голову инфу как стать программистом с нуля. только всякие высеры котеровых с кодом типа
if($peremennaya = '2') echo '<b>'.$_GET['ADMIN'].' вы админ!</b>';
но есть пиздатый мануал по языку, читай его.
вот хорошие книги: https://github.com/jupeter/clean-code-php
http://www.phptherightway.com/
но они не "дают базу". "базу" ты соберешь по кусочкам потом, через год изучения. также есть много хороших книг по джаве, по ооп.
Просто, если ты про отступы - то там они на месте, кроме как на 82-ой строке.
Там же нет вложенных циклов/условий и прочего.
А не надо теги получать в контроллере. Должен быть сервис или репозиторий, который их находит.
Почитай где нибудь про Fat Ugly Conttollers.
братюнь, я читал. в контроллере получаю теги - это занчит обращаюсь к репозиторию, который занимается получением. тонкий контроллер как раз это и делает - обращается к модели за данными и отдает их представлению.
у меня контроллер из 5 строк состоит и тем не менее, там есть это дублирование.
Спсибо за ссылки.
Практика у меня уже была. Полтора года (даже год и 9 месяцев). А вот теорию знаю (вернее помню) слабо.
Также, если речь о данных для шапки, сайдбара, подвала, то есть того, что есть почти на каждой странице, то тут есть разные варианты:
- базовый контроллер, который выставляет глобальные переменные для твига (глобальные переменные конечно не очень хорошо): http://symfony.com/doc/current/templating/global_variables.html
- то же самое, но вызывающееся не через базовый контроллер, а через события kernel вроде before request или before controller. То есть перед вызовом контроллера вызывается твой код и что-то передает в твиг (опять же, глобальные переменные)
- специальный "хелпер", который передается в шаблон и из которого в нем берутся нужные данные (вроде {% set tags = pageHelper.getPopularTags() %})
- сделать функции получения данных как расширение к твигу и писать там {% set tags = getPopularTags() %}. Минус - эти функции скорее всего ничего не "знают" о запросе, непонятно как передавать в них какие-то параметры.
- заменить объект твига на расширенный, который дополняет переменные нужными данными
под практикой я имею в виду работу в нормальной конторе с аудитами, отгрузками и прочим. без битриксов с версткой и прокладываний витой пары.
ты под теорией что понимаешь?
Вот еще такой подход предлагают https://symfony.com/doc/current/templating/embedding_controllers.html
ОП, не знаю, говорили тебе тутошние антоны или нет, но большое тебе спасибо за всю информацию в этом тредике. Очень грамотно и развернуто
Ну зацени мой код четырехлетней давности
https://ideone.com/IiGQvQ
До сих пор работает как часики.
Одна проблема, понимаю в нем хоть что-то только я.
код:
https://pastebin.com/0zsCzrkQ
Вся страница завалена первым значением из массива.
> $menu_array = mysqli_fetch_assoc($menu_query)
Если переместить эту конструкцию в цикл то все работает. Не могу догнать, разве не одно и тоже записать в цикле $menu_array = mysqli_fetch_assoc($menu_query) и $menu_array ?
Намекаешь на for ?
Я комментирую строчку $date->modify("+{$matches[1]} day"), которая находиться в ложном условии, которая не должна выполниться, и к датам не добавляется астрономическое значение.
Вот копипаста этого кода: https://3v4l.org/uEeGP
Посоветуйте, как вообще делать такой алгоритм, где в одной функции вызывается много проверок
"2" не выполнится только если в ф-ции check будет выброшено исключение throw new Exeption() или где-нибудь там встретится ф-ция exit, die. Еще мог бы быть вариант, если ф-ция check() асинхронная, но в php такого нет, там все выполняется последовательно, даже запросы к удаленным серверам.
Починилось после того как каждой новой итерации создавалась новая дата. Но почему при первой, всё равно, выполнялось ложное условие, и добавлялось астрономическое число?
Да, анон. Когда вызывается функция, управление передается именно ей, а также в стек добавляется адрес возврата, там же существует локальная область памяти для данной функции. Функция выполняется, сохраняет данные в определенном месте, а затем управление передается вызывающей функции, которая получает адрес в памяти данных, которые вернула функция.
Но даже если функция ничего не возвращает, то в любом случае сначала полностью выполнится функция, затем выполнение пойдет дальше.
Об этом же вопрос был?
>Посоветуйте, как вообще делать такой алгоритм, где в одной функции вызывается много проверок
Я всегда делаю в таком йоба-стиле. Если нужно сделать множество проверок внутри какой-то функции, вместо кучи вложенностей, отбрасываю неудачные варианты. Хз красивое это решение или нет.
Лучше писать
$result= check();
if (!$result) {
...
}
Во-первых, не стоит совмещать 2 действия в 1 строке. Во-вторых, ты нарушаешь правило приоритетов операторов - !$result = ... эквивалентно (!$result) = ... и некорректно. Это просто в PHP стоят костыли, которые такое разрешают.
Это странная конструкция. Зачем проверять, существует ли переменная? Ты сам не видишь по коду выше, создавал ты ее или нет?
Спасибо, буду знать
Нужно подгрузить скрипт в зависимости от выбранной страницы. Скрипт для страницы/2/ отказывается работать. Как я понял — загвоздка скорее в wordpress, а не в пхп.
https://developer.wordpress.org/reference/functions/is_page/ — тут описывается подобный случай, но пхп я совсем не знаю. Если не сложно, помогите с кодом:
add_action('wp_enqueue_scripts', 'qg_enqueue');
function qg_enqueue() {
if (is_page( 'new-page-testing/2/' )) {
wp_enqueue_script(
'qgjs',
plugin_dir_url(__FILE__).'cae2.js'
);
} elseif (is_page( 'new-page-testing' )) {
wp_enqueue_script(
'qgjs',
plugin_dir_url(__FILE__).'cae1.js'
);
}
}
32 года, полтора года назад решил перекатиться из своей предыдущей профессии в ойти. начал учить пхп, прошел курсы, сделал несколько учебных проектов, через какое-то время пошел на свою первую работу в одну крупную контору. прокачки было дохуя, но там платили как бомжу (меньше 40к, контора в дс). отработал чуть меньше года и ушел. решил, что нужно учить фреймворк и работать конкретно по нему. начал учить симфони, там как раз подоспела четверка. параллельно фрилансил, учил базы данных, всякие редисы и прочее говно, коммитил в опенсорс. недавно решил потестить свои знания, по приколу нашел мидловские вакансии по удаленке, связанные с симфони, чтобы взять там тестовые задания. выполнил первое, потом мне сказали мол "давайте созвонимся попиздим с эйчаром и техническим директором", попиздели мне прислали оффер на удаленку 100к мидлом плюс пиздатый стек. пригодился и мой предыдущий опыт (задавали вопросы из серии "что вы будете делать, если", а я как раз решал эти вопросы на прошлой работе), и в меру наполненный активностью гитхаб.
пользуясь случаем, хочу сказать ОПу огромное спасибо за его пасту и подробные ответы на вопросы. я, к сожалению, не сделал ни одной его задачи (кроме вводных, когда начинал учиться), но надеюсь найти время и сделать, чтобы послушать его советы.
пусть я буду примером всяким вкатывальщикам, которые ссут и медлят. я, кстати, никогда не задавался вопросом "поздно ли, не поздно ли". мне кажется, если хочешь вкатиться, надо вкатываться, а не сомневаться и слушать чьи-то мнения.
алсо, могу сказать, что на работе по предыдущей специальности я получал больше, чем 100к, но в любом случае 100к больше, чем 40, лол.
конечно пока не заслуживаю. этапы карьеры не перескочить, очевидно, что сразу синьором не стать и я радуюсь каждому небольшому достижению. к чему призываю всех анонов.
если ты ждешь 500к в месяц, чтобы начать радоваться, мне тебя жаль. хотя я сомневаюсь, что у тебя в принципе есть реальный опыт работы.
Я вообще не понимаю тех кто переживает что им уже аж целых 30 лет. Вы в 30 лет на пенсию что ли выходите, или у вас руки в 30 лет отваливаются? Люди на заводе и в 30, и в 40, и в 50 бодро работают. Вот исполнится вам 50-60, тогда и можете жаловаться
да, "одна строка - одно действие". правда часто даже в современном "правильном" коде это правило не выполняется, например
return $this->someMethod();
$someVar = array_map($callback, array_values($result));
то есть считается корректным совмещать return и что-то иное, а также переменной присваивать последовательный результат выполнения каких-то типовых несложных (чаще встроенных) функций. и еще какие-то вещи, щас не вспомнить их, но это и не принципиально.
но в примере >>40793 в одной строке даже не 2, а 4 действия и все абсолютно разноплановые. налицо желание анона изобрести свой велосипед и всех наебать вместо того, чтобы открыть какой-то реальный код (из того же symfony) и посмотреть, как там сделано. тот же код можно посмотреть для ознакомления с такой штукой как PSR-1/PSR-2
Застрял на задании в строках с массивами и стихотворением.
Проблема следующая: я изначально делал задание не через array_rand (так же, как и предыдущие), потому что не понял как это в принципе работает. Мануал читал, в английский могу, но я не въехал, как сделать так, чтобы он выбирал случайное число и при этом выводил из массива его значение. В мануале же описано по сути перемешивание значений и вывод случайного через соотв. команду (echo $input[$rand_keys[1]]), или я что-то не так понимаю?
Короче, решал через mt_rand, нашел решение в гугле. Но если с предыдущими заданиями это прокатило, то тут первая и вторая строки (где значения из 1, 2 и 3 массива) получаются абсолютно идентичными. Подскажите плз, можно ли это решить таким путем, чтобы строки были разными или поясните за array_rand, или я вообще все не так делаю, и там нужно использовать что-то другое?
Я думаю эта функция возвращает элемент массива с ключом ['huita']
Я написал несколько классов-мапперов для сохранения и получения объектов из базы данных, а также мапперы для трансформации этих объектов в JSON объекты. Поскольку их нужно тестировать, я подумал что это хороший случай, чтобы разобраться с phpunit. И как всегда у меня есть несколько вопросов:
1. Что курить кроме Зандстры и доков phpunit?
2. С чего начать?
3. Как организовать тестирование мапперов для ДБ и JSON, чтобы в дальнейшем при добавлении новых связок "сущность-мапперДБ-мапперJSON" создание тестов не требовало много усилий?
>1. Что курить кроме Зандстры и доков phpunit?
Хабр
>2. С чего начать?
С написания тестов, очевидно же!
Для преобразования в JSON функции протестируй. Это не маппер как ты называешь, а сериализатор (php объект -> json обьект).
>>41356
>3. Как организовать тестирование мапперов для ДБ и JSON, чтобы в дальнейшем при добавлении новых связок "сущность-мапперДБ-мапперJSON" создание тестов не требовало много усилий?
Не нужно писать тесты на каждый свой пердёж. Тестируй только то что будешь переиспользовать. Добавление НОВЫХ сущностей вообще ничего не должно менять, это ведь тоже самое что и другие сущности, просто в них информация другая. А вот если ты добавил функционал в базовый класс, то этот функционал уже можно (по идее нужно) тестировать, чтобы эта йоба не ломалась при добавлении новой йобы.
Писать тесты заебывать пиздец, нудное и не интересное занятие.
Ещеесли напишешь кучу ебланских тестов, то их тоже придется ПРАВИТЬ, лол.
Для начала, а ты смотрел мою статью по тестированию? https://gist.github.com/codedokode/a455bde7d0748c0a351a
Дальше, ты должен решить, что и как ты будешь тестировать. Для этого мы берем каждый класс (или группу классов, работающих вместе) и определяем требования к ним. Что они должны уметь делать? Каждое требование будет проверяться тестом. Затем придумываем, как это требование проверить (тут может потребоваться смекалка) и пишем код тестов.
Кстати, самый просто тест - это просто вызвать ту или иную функцию. Это уже позволяет нам проверить, что код не падает на ровном месте и лучше чем ничего.
Но обычно сценарии тестов строятся по схеме "Дано - Если - То". Ну например, "ЕСТЬ пустая база данных, ЕСЛИ вызвать метод подсчета числа записей в ней, ТО он вернет ноль".
Сценарии бывают позитивные и негативные, позитивные проверяют, что при правильных входных данных функция работает, а негативные проверяют ее поведение при неправильных входных данных.
Не всегда конечно очевидно, как проверить то или иное требование, потому задача написания тестов может потребовать креативности, поиска неочевидных решений.
Рассмотрим пример составления сценария тестирования.
Например, у тебя есть класс для сохранения и получения объектов из БД. Какие к нему есть требования? Ну очевидно, первое что в голову приходит:
- маппер должен уметь сохранять объект в БД
- маппер должен уметь загружать объект из БД
дальше там могут быть дополнительные требования вроде "маппер должен присваивать id создаваемым объектам", "маппер должен уметь считать число объектов в БД", это ты должен наверно знать, из описания не ясно.
Как проверить требования выше? Тут могут быть разные идеи. Например:
- загрузить в базу данных дамп с известными сущностями
- попробовать загрузить одну из них
- проверить, что данные загруженные данные соответствуют ожидаемым
А можно чуть схитрить и проверить обе функции сразу:
- сделать пустую БД
- вызвать функцию вставки сущности в БД
- вызвать функцию загрузки сущности из БД
- проверить, что данные вернулись корректные
Как-то так.
Помни еще, что тесты должны быть независимы и не полагаться на очередность вызова, или на то, что другой тест вообще будет вызван.
Для начала, а ты смотрел мою статью по тестированию? https://gist.github.com/codedokode/a455bde7d0748c0a351a
Дальше, ты должен решить, что и как ты будешь тестировать. Для этого мы берем каждый класс (или группу классов, работающих вместе) и определяем требования к ним. Что они должны уметь делать? Каждое требование будет проверяться тестом. Затем придумываем, как это требование проверить (тут может потребоваться смекалка) и пишем код тестов.
Кстати, самый просто тест - это просто вызвать ту или иную функцию. Это уже позволяет нам проверить, что код не падает на ровном месте и лучше чем ничего.
Но обычно сценарии тестов строятся по схеме "Дано - Если - То". Ну например, "ЕСТЬ пустая база данных, ЕСЛИ вызвать метод подсчета числа записей в ней, ТО он вернет ноль".
Сценарии бывают позитивные и негативные, позитивные проверяют, что при правильных входных данных функция работает, а негативные проверяют ее поведение при неправильных входных данных.
Не всегда конечно очевидно, как проверить то или иное требование, потому задача написания тестов может потребовать креативности, поиска неочевидных решений.
Рассмотрим пример составления сценария тестирования.
Например, у тебя есть класс для сохранения и получения объектов из БД. Какие к нему есть требования? Ну очевидно, первое что в голову приходит:
- маппер должен уметь сохранять объект в БД
- маппер должен уметь загружать объект из БД
дальше там могут быть дополнительные требования вроде "маппер должен присваивать id создаваемым объектам", "маппер должен уметь считать число объектов в БД", это ты должен наверно знать, из описания не ясно.
Как проверить требования выше? Тут могут быть разные идеи. Например:
- загрузить в базу данных дамп с известными сущностями
- попробовать загрузить одну из них
- проверить, что данные загруженные данные соответствуют ожидаемым
А можно чуть схитрить и проверить обе функции сразу:
- сделать пустую БД
- вызвать функцию вставки сущности в БД
- вызвать функцию загрузки сущности из БД
- проверить, что данные вернулись корректные
Как-то так.
Помни еще, что тесты должны быть независимы и не полагаться на очередность вызова, или на то, что другой тест вообще будет вызван.
Может, есть какое-нибудь более лучшее решение? Буду благодарен.
Маппер - тоже подходящее название, не придирайся. Есть даже функция Map в функциональном программировании и она как раз обозначает отображение одного списка на другой: https://en.wikipedia.org/wiki/Map_(higher-order_function)
> Писать тесты заебывать пиздец, нудное и не интересное занятие.
Проверять руками ещё нуднее, особенно с ростом приложения. Верно, что править тесты нужно, если они слишком много знают о внутренностях тестируемого кода, тогда при изменении внутренностей нужно будет править тесты. Ещё хорошо юнит-тестируется только код с нормальными разделением ответственности, то есть появляется хоть какая-то объективная метрика хорошего кода - сложно написать тест, значит код скорее всего запутанный.
>>41364
На хабре старьё, читай доки PHPUnit и смотри как пишут тесты другие люди на гитхабе:
- https://github.com/slimphp/Slim/tree/3.x/tests
- https://github.com/silexphp/Pimple/tree/master/src/Pimple/Tests
- https://github.com/j0k3r/banditore/tree/master/tests/AppBundle
У тебя не написано, как выглядит схема БД. Альтернатива - сделать денормализацию и явно хранить связь между тредом и последними 3 постами.
Можно понадеяться, что он проверен, и ничего не делать.
Можно написать небольшие приемочные тесты, тестирующие его в целом.
Если это опен сурс, можно предложить разработчикам помощь в добавлении и написании тестов.
Все движки тестов, которые я видел, слишком занудные (слишком подробный синтаксис, слишком много времени уходит).
Вернее, называется "Алгоритмы. Вводный курс". Но я хз что там, ибо читал "Алгоритмы. Построение и анализ".
Тонко шутишь, фраерок
ну как вариант, но тоже достаточно занудно
Оно не работает! Оно не живо! Оно мертво!
https://ideone.com/9P02fe
Оно даже ошибок не выдаёт! Оно пусто! Что я не так сделал?
Очевидно же, что проблема в spellSmallNumber. Но где?
Я кусочек этой функции запускал отдельно, оно работало. Господи, горе мне!
А ещё PDO истязает мою и без того измученную душу.
Как в PDO заменить mysql_real_escape_string так, чтобы оно работало? Нужно при неверном наборе символов перенаправлять на другую страницу с помощью header. Без строки PDO:Quote, которую я пытался использовать, всё работает, но как только я её вставляю, оно не перестаёт переходить, а лишь перезагружает текущую страницу без вывода чего-либо. Отправившись на покорение просторов интернета, я попытался использовать и с try и с prepare, но это было неверным действием. Вот так. Я не понимаю, где моя ошибка?
На первых трёх пиках мои скверные письмена, на последнем, четвёртом, рабочий вариант, но с mysql.
>Есть даже функция Map в функциональном программировании и она как раз обозначает отображение одного списка на другой
Педагог и педофил - тоже одно и тоже?
Сравнить функцию высшего порядка с ООП термином это сильно блять.
Хорошо. Добавлю комменты и выложу.
Аноноимусы, что можете сказать о книге "php быстрый старт" ? стоит ее прочесть, чтобы быстро освоить основы языка и приступать к практике, которая есть в шапке? парочку яп я знаю, но вебом не занимался никогда
Кстати, что можете сказать про "php в подлиннике" ? Везде ее нахваливают, но объем ее меня очень отталкивает, так как печальный опыт чтения книг по яп на 1000+ страниц есть
В шапке и так все с "это называется переменная, а вот это - строка".
Никаких предварительных ласок не нужно.
Да, учебник из шапки я просматривал, поэтому и спрашиваю о альтернативах, в виде настоящих книг, хотелось бы поближе познакомится с ооп в пхп, связку с sql и так далее.
Чувак, я тебя не понимаю.
Если тебе просто не нравится оформление ОП-а, то можешь взять http://php720.com/ , например.
В общем, учебник ОП-а самодостаточен для первого этапа. "Настоящие" книги мне не нравятся из-за долгого вступления и всяких расшаркиваний, которые НАХУЙ не нужны нубасу, который впервые учится кодить на чем-то кроме ХТМЛ.
Тебе нужна книга ОПа и справочник Скляра и Трахтенберга. Больше почти нет годных книг, смирись@покайся.
На серваке у Абу. Это бэкенд и простой юзер не имеет к нему доступ.
книги про пхп учат говнокоду. потрать несколько месяцев на изучение, чтобы потом прийти на собеседование и понять, что надо переучиваться.
такой вот ларавел. зато быстро!
Лол, а я переживал, что хуево вкатываюсь, ибо вкатился в саппорт по PHP в 27, а сейчас макакой подрабатываю за 40 (ДС2).
я другой анон, но
1. процедурный код
2. mysql_query
3. пхп и html в одном файле, закрывающие теги ?>
4. глобальные переменные
ну и просто неуловимое ощущение, что попал во времена пхп4
А еще отсутствие какой-либо нормальной архитектуры.
спасибо!
>>42208
главное сразу учить то, что потребуется потом на нормальных работах - ооп, тестирование, фреймворки, бд, линукс и пр. чтобы через два года не оказаться с навыками, подходящими только для дизайн-студии какой-нибудь. все, что у ОПа есть в пасте, грубо говоря, надо выучить (кроме фронта и верстки, лол)
то, что читай PSR. конкретно смешение логики и представления нарушает современные стандарты: https://www.php-fig.org/psr/psr-1/#23-side-effects
с другой стороны ты не объявляешь функции, классы или константы в этом файле, так что формально ИМЕННО ЭТО не является нарушением именно этого пункта пср. но смешивать логику с представлением - плохая практика.
Покажешь, как согласно современным стандартам должен выглядеть этот код ?
я тебе так скажу, по этим самым стандартам нужно использовать например твиг с набором дополнительных расширений к нему (которые ты напишешь сам), которые будут заниматься всякой логикой типа получения путей для картинок и т.д. в твиге (или другом шаблонизаторе) можно легко выводить списки, таблички по три ячейки в столбце и т.д.
а в этом коде прям чувствуется, что подпихивали-подпихивали костылей по одному и в итоге все достаточно запутано.
В node.js можно прослушивать определенный порт и обрабатывать поступающие на него запросы. Как такое делается в php?
Я даун. Сори за тупой вопрос. Очень благодарен, братишка.
Apache сам это делает. Он же балансирует нагрузку и прибивает скрипты, когда они зациклились или отожрали слишком много памяти.
Километровые if?
Ну а если я захочу обрабатывать запросы php кодом без проксирующего сервера? Будут ли запросы в таком случае нормально обрабатываться?
Найн. Я реализовал через таблицы с атрибутами товаров и атрибутами категорий.
Есть категория, у неё есть десяток атрибутов. Эти атрибуты могут быть у товаров.
Далее на странице мы выводим все атрибуты в форме (с чекбоксами) и там уже просто ищем те товары, которые им соответствуют.
Ну у меня немного сложнее, т.к. присутствуют атрибуты разных типов (единичный чекбокс, множественный чекбокс, диапазон и т.д.)
Всё равно не перенаправляет.
То есть писать как-то так
$obj->method_name();
Я знаю, что в стандарте (PSR-1) указано, что использовать нужно camelCase, но с нижними подчеркиваниями выглядит аккуратнее имхо.
Ммм.
А можно на пальцах?
Допустим, создал я формочку, где есть чекбокс сортировки по цене или алфавиту.
Запросы в БД будут вида
order by name asc
order by name desc
или
order by price asc
order by price desc
Или ты предлагаешь сразу выгружать всю категорию? Но сортировать по условиям все равно придется - но уже массивы, в которые выгружена таблица.
Могу предложить урок по шаблонам, как раз про это: https://github.com/codedokode/pasta/blob/master/php/templates.md
Сокеты в PHP доступны, так что ты можешь открыть сокет и принимать коннекты. Но в 1 поток. Чтобы сделать асинхронность, как в node, нужны неблокирующие сокеты и библиотека вроде ReactPHP. Но скажу честно, что с ней не все работает асинхронно: тот же PDO синхронный и блокирующий.
Сортировка - это одно. Я говорил именно про выборку товаров.
Хорошо. Попробую рассказать подробно.
Смотри, у тебя есть категория "Мобильные телефоны". В админке у тебя есть возможность добавить атрибуты, которые присущи мобильным телефонам. Ну, пускай, например, это будет цвет, операционная система и ёмкость батареи.
Хорошо, админ это всё добавил. В этот момент в таблице attributes появилось три записи. Каждое из них содержит, как минимум свой айдишник, айди категории и название значения.
Теперь у нас есть товары. У каждого товара должны быть эти атрибуты (но это необязательно). Какие именно значения должны быть?
Допустим у нашего мобильного телефона значения такие: черный, iOS, 3200.
После того, как админ всё это добавил, у нас в таблице values появились три записи. Каждая из них содержит в себе как минимум четыре значения: айдишник свой, айди атрибута, айди товара и имя.
Разумеется, между таблицами лучше сделать связи.
Теперь поиск.
Открываем страницу, в которой у нас выпадают все товары из таблицы "Мобильные телефоны". Одновременно с этим подгружаем все атрибуты и, что не менее важно, значения атрибутов.
То есть мы загружаем все те значения, которые у нас есть в таблице и которые принадлежат каким-либо товарам, что исключает вероятность пустого поиска.
Теперь мы чекбоксами отмечаем необходимые значения и клацаем "отфильтровать".
У меня сделано через ajax, но в простейшем случае это можно сделать обычной формой. В сгенерированном URLe (мы отправили форму методом GET) содержаться айдишники значений.
Теперь дело за малым - найти те товары, у которых есть подобные значения атрибутов. И всё. Как реализовать последний шаг - думай сам. Я делаю так:
1. Подсчитываем количество значений в запросе (то есть количество чекбоксов, которые юзер отметил).
2. Далее делаем выборку товаров по данным чекбоксам и отсеиваем те, количество которых не совпадает с количеством чекбоксов.
Но это мой способ, никто не говорит, что всё так и нужно делать. Я пришел к такому решению, оно меня устраивает - работает быстро и надежно.
Сортировка - это одно. Я говорил именно про выборку товаров.
Хорошо. Попробую рассказать подробно.
Смотри, у тебя есть категория "Мобильные телефоны". В админке у тебя есть возможность добавить атрибуты, которые присущи мобильным телефонам. Ну, пускай, например, это будет цвет, операционная система и ёмкость батареи.
Хорошо, админ это всё добавил. В этот момент в таблице attributes появилось три записи. Каждое из них содержит, как минимум свой айдишник, айди категории и название значения.
Теперь у нас есть товары. У каждого товара должны быть эти атрибуты (но это необязательно). Какие именно значения должны быть?
Допустим у нашего мобильного телефона значения такие: черный, iOS, 3200.
После того, как админ всё это добавил, у нас в таблице values появились три записи. Каждая из них содержит в себе как минимум четыре значения: айдишник свой, айди атрибута, айди товара и имя.
Разумеется, между таблицами лучше сделать связи.
Теперь поиск.
Открываем страницу, в которой у нас выпадают все товары из таблицы "Мобильные телефоны". Одновременно с этим подгружаем все атрибуты и, что не менее важно, значения атрибутов.
То есть мы загружаем все те значения, которые у нас есть в таблице и которые принадлежат каким-либо товарам, что исключает вероятность пустого поиска.
Теперь мы чекбоксами отмечаем необходимые значения и клацаем "отфильтровать".
У меня сделано через ajax, но в простейшем случае это можно сделать обычной формой. В сгенерированном URLe (мы отправили форму методом GET) содержаться айдишники значений.
Теперь дело за малым - найти те товары, у которых есть подобные значения атрибутов. И всё. Как реализовать последний шаг - думай сам. Я делаю так:
1. Подсчитываем количество значений в запросе (то есть количество чекбоксов, которые юзер отметил).
2. Далее делаем выборку товаров по данным чекбоксам и отсеиваем те, количество которых не совпадает с количеством чекбоксов.
Но это мой способ, никто не говорит, что всё так и нужно делать. Я пришел к такому решению, оно меня устраивает - работает быстро и надежно.
Нет, не стоит писать как тебе вздумается, лучше использовать единый стандарт, для питона руководствоваться PEP, для PHP - PSR2
В любой нормальной конторе тебя будут просить писать так, как принято в коммьюнити.
>>42529
"имхо" - это дело привычки. Там по факту, как я понимаю, каких-то принципиальных плюсов и минусов нет, это просто дело вкуса. Чтобы бардака в коде не было, в PHP решили принять за основу взятый из Явы стиль с кемелкейсом. Если ты на него перейдешь, он тебе станет таким же привычным.
И не спеши огорчаться. Это ведь возможность получить новые навыки - навыки рефакторинга. В некоторых IDE есть функции рефакторинга, в том числе переименование методов (в идеале, при этом переименовываются все упоминания этого метода). С поддержкой IDE это все делается намного быстрее. Я думаю, это точно есть в PhpStorm (платный) и вроде как есть в Netbeans (бесплатный).
Если вдруг IDE не поддерживает такое, освоишь поиск/замену в файлах.
Зачем переписывать? Отрефакторь.
В PHP есть такая странная фича - если добавить в форму поле <input type="hidden" name="PHP_MAX_SIZE" value="кол-во байт">, то пхп сам проверит, умещается ли файл в эту цифру, иначе ошибка загрузки, как я понимаю. Конечно, это ни разу не безопасно, ведь число передать можно любое.
Есть хоть какие-то профиты от этой дырявой фичи? Например, может, пхп не будет грузить целый гиг, а сразу после 10мб - если лимит таков - выдаст ошибку?
Не нужно переписывать. Есть php-cs-fixer, который сам всё поправит, использовать через консольную команду php-cs-fixer fix path/to/project
Некоторые люди идут дальше - делают precommit hook - скрипт который срабатывает при попытке создать коммит - этот скрипт в автоматическом режиме фиксит кодстайл. Во многих библиотеках на гитхабе такое тоже используется, ещё там можно настроить бота (Style CI), который автоматически будет слать пулл-реквесты в репозиторий с кодстайл фиксами.
>>42549
Лучше просто на стороне PHP провалидировать файл и только после аплоадить. Пример как это можно делать в Symfony: https://symfony.com/doc/current/reference/constraints/File.html#options
Ты же можешь просто if'ом проверить.
>>42417
Загляни в исходники, это же микрофреймворк. Slim использует абстракцию для работы с HTTP: https://www.php-fig.org/psr/psr-7/
С объектами работать проще, чем с суперглобальными переменными, так как в коде становится видно зависимости, что облегчает юнит-тестирование и подмену таких зависимостей. И еcho ведь не всегда нужен, если я хочу просто отредиректить пользователя на другую страницу, то я выставлю HTTP заголовок 301 без тела HTTP ответа.
>>42393
> глобальные переменные
И че?
> php и html
И ЧЕ?
Блядь, вот я охуеваю. КТО СКАЗАЛ ЧТО ГЛОБАЛЬНЫЕ ПЛОХО? Кто-то пёрнул и ты тоже перди, мол, эта плохо, хотя всё на них и работает, блядь. Область видимости притащили, используй. Но кто-то со времён 2007го года тащит эту хуйню и оно идёт и едет.
Потом эти пидарасы, с шаблонизацией мозга. ЛОГИКА И ПРЕДСТАВЛЕНИЕ НЕ ДОЛЖНЫ СМЕШИВАТЬСЯ - на каждый чих твиги прикручивают, всякие тупорылые смарти и прочую хуйню. А шаблонизатор тоже предоставляет ЛОГИКУ и простые условия и прочую хуйню. Ну и нахуй мне логика в логике? Нахуй мне ещё пердолить какие-то тупорылые, блядь шаблонизаторы, когда в Yii всё работает адекватно и никто туда лезть не должен, сука. SaaS дохуя?
Из за таких пидарасов вкатываение становится проблемой. Припрутся, пёрнут, что всё плоха и всё. На пике кусочки кода, которым похуй на шаблонизацию. НЕТ, БЛЯДЬ. ДАВАЙ ПРО НЕЁ ПОПИЗДИМ. Уходи из треда и не возвращайся. Ты тут не поможешь ни чем, если будешь в таком же ключе отвечать людям и предлагать твиг вкорячивать.
>ооп
Это отдельная дисциплина?
>тестирование
Есть.
>фреймворки
С этим вот беда, лол.
>бд
Знаком.
>линукс
Достаточно хорошо знаю.
Спасибо за советы!
`print "Abu pidr";`
>куратор тхреда
Сука, я проиграл на весь дом.
Представил как куратор заставляет детишек писать на PHP, даёт задание запилить магазин, а потом в новостях его показываю как он заставил 2000 детей писать на PHP. Как же я проиграл
> заставляет детишек писать на PHP
Есть
>даёт задание запилить магазин
Есть, но только это файловый обменник
>а потом в новостях
Пока что нету, ждем на ньюсаче.
Скачай какой-нибудь фреймворк и смотри как он устроен. Со временем сам всё поймешь.
Ты еще банду 4х скажи почитать и скажи: "а там дальше разберешься". Это вопервых, во вторых в этих фремворках напихано оверхеда дохуя. Я читал и симфони и ларавель и юи. И теперь я могу тебе сделать говносимвони, шмаравель и хуюи, своим кодом, только это мне не помогло научится объектно что ли делать, хз как объяснить.
Иногда тебе надо применить ооп, на некой бизнес логике или каком либо сервисе, но тут уже попадаешь в тупик, так как это не скопировать просто структуру приложения от крутых дядек, а надо понимать самому, как сделать удобнее.
Поэтому я хоть и смотрел другие фреймворки, но все равно после этого не особо получается собрать все мысли в кучу, и написать что то более менее читабельное и понятное.
Дали задание: написать запрос к API и взять необходимые данные.
Сервак отвечает в JSON.
Вот мне и нужно записать код, чтобы при его запуске скрипт опрашивал сервак и забирал с него данные.
http://php.net/manual/en/function.file-get-contents.php
Я конешна ни куратор треда, но что то типа этого тебе должно помочь.
>КТО СКАЗАЛ ЧТО ГЛОБАЛЬНЫЕ ПЛОХО
много кто, лол. в том числе, ОП. почитай в инторнете, если интересно
>Но кто-то со времён 2007го года тащит эту хуйню и оно идёт и едет
кто-то на дельфи пишет и оно все едет
>шаблонизатор тоже предоставляет ЛОГИКУ
не нужно воспринимать буквально. под "логикой и представлением" имеется в виду "логика МОДЕЛИ и представление".
>когда в Yii всё работает адекватно
лол, codeigniter еще вспомни
>Ты тут не поможешь ни чем, если будешь в таком же ключе отвечать людям и предлагать твиг вкорячивать
не передергивай. я такого не предлагал. меня спросили "как согласно современным стандартам должен выглядеть этот код". а нужно ли приводить код к стандартам или нет - это вопрос, на который только тот анон знает ответ
каждому свое - кому прикручивать шаблоны к вордпрессу, а кому работать в современных проектах. если ты агитируешь вкатывальщиков за первый вариант, а я за второй, то почему я должен уходить, а не ты?
пиши дальше простыни кода с глобальными переменными, mysql_query и евалами, другим даже лучше. чем больше таких динозавров как ты, тем проще адекватным анонам устроиться на нормальную работу на нормальный фреймворк за приличную зп.
header (location:) офк
>твиги прикручивают, всякие тупорылые смарти
лол, слышал звон не знаю где он. твиг используют все, в т.ч. его часто используют на Yii2, а смарти - это мамонт из того же 2007, откуда и ты вылез.
ты поди и файлы на сервер по фтп заливаешь
Ну под бзню. Чтоб апачем как бох владеть.
очень жаль, потому что в шторме это делается одним кликом
а так можно коммитить в удаленный репозиторий и по сценарию сборки автоматом прогонять тесты и загружать их на сервер. но это достаточно заебно в настройке
Через netBeans тоже можно такое настроить. Я покурил гугл, вроде что-то нашел.
Но а как это делают вообще все нормальные белые люди, не использующие phpStorm?
>а так можно коммитить в удаленный репозиторий и по сценарию сборки автоматом прогонять тесты и загружать их на сервер. но это достаточно заебно в настройке
Так что ли?
опен сервер, винда 7
>Но а как это делают вообще все нормальные белые люди, не использующие phpStorm?
таких не существует лол
>Так что ли?
вообще это разные вещи. одна чисто деплой файлов, вторая это контроль версий и все увязано около него
обычно простой деплой файлов используется для работы с дев-сервером, где у разработчика своя папка и свой хост, а сценарии сборки применяются для деплоя на продакшн или всякие стейджы.
Порыскал на гите, есть отличные решения, но больно громоздкие для нескольких требующийся мне тэгов. Если что можно и на регулярках пописать в регулярки вообще не знаю, лол
Не всасываю
использовать FTP/SSH клиент. Например, CuteFTP. Но он будет перезаливать все файлы. Для выборочной заливки нужно поставить на сервер SVN и использовать svn-клиент на своем компе.
бiмп.
не надо пытаться впихнуть паттерны, потому что прочитал о них. открой код какого-нибудь компонента симфони (ОП рекомендует symfony form) и посмотри, как там сделано.
синглтон признан антипаттерном и вместо него следует использовать DI.
А как вообще лучше проектировать, Например у меня есть какое то стороннее апи отдающее жсон. И разные типы запросов и ответов.
Как спроектировать сервис на пхп? с какой стороны подойти?
Выделить объекты и установить связи между ними?
>ты поди и файлы на сервер по фтп заливаешь
А как их нужно заливать? просто интересно, другой анон
Демонстрируй давай
>вкатываение становится проблемой
Ну если ты будешь себя так вести и так писать код, то для тебя проблемой станет работа и собеседования.
И вообще, не тролируй.
Я готов кидать ОПу копеечку на Патреон, но у него нет Патреона...
ОП, не думал о таком?
Мне хочется тебя отблагодарить, за твои добрые дела.
Я плачу каждый день, потому что не знаю как отблагодарить его.
да легко, возьми существующую библиотеку для работы с АПИ, например google php api client и посмотри как там сделано.
ты иди от задачи, а не от того какие классы нужно написать. напиши сначала все в одном классе, а потом отрефакторь.
обычно нужно сделать классы, отвечающие непосредственно за коннект и работу с данными (сам Client, всякие коннекторы, менеджеры паролей и т.д.), условно Request, и классы, которые представляют сущности того АПИ, с которым ты хочешь работать, условно Entity. а дальше нахуярить еще много всяких вспомогательных. короче смотри реальный код из библиотек.
>>43105
по ssh конечно. фтп - небезопасный протокол.
почему же, это типичная позиция какого-нибудь битрикс-программиста. мол все эти твиги и прочую бесовщину используют только хипстеры из кремниевой долины лол, а настоящий код он такой, страшный но работающий, с глобальными переменными и на 5.3.
представляю какой шок его ждет, если он узнает, что существуют конторы, где покрывают код тестами.
С одной стороны, ты правильно делаешь, что пытаешься изучать разные готовые решения (паттерны). В веб-приложениях ничего нового изобретать не надо, все уже придумано до нас. Но с другой стороны, ты неправильно делаешь, что пытаешься обязательно использовать в коде какой-то паттерн. Это говорит о том, что ты в них не разобрался и не понял, для чего они нужны, когда их используют.
В программировании (как и в вообще в инженерных науках) для каждого решения есть обоснование. Почему мы хотим сделать так, а не иначе. Чаще даже есть не одно решение, а несколько, мы сравниваем плюсы и минусы и выбираем то, что лучше подходит. Вот например, если у тебя есть свободное время, ты можешь почитать отчет о разработке радиопередатчика для первого спутника (он длинный): http://russianspacesystems.ru/wp-content/uploads/2017/10/Otchet-o-razrabotke-bortovoy-radiostancii-pervogo-sputnika.pdf . В этом отчете формулируется задача, разбираются разные варианты ее решения, и каждый раз обосновывается, почему выбран тот или иной вариант. Например, почему были выбраны лампы, а не транзисторы. Вот в идеале у тебя в голове должен происходить такой же мыслительный процесс. Начинающему, может, это и сложно, но со временем надо к этому стремиться.
Если ты сомневаешься, то можно по умолчанию выбрать самое простое решение. Такое решение, которое требует минимум затрат времени и усилий. Не уверен, нужен ли тебе ORM? Ок, не используй. Но если потом ты заметишь, что пишешь много однотипных SQL запросов, то может быть стоит все же подумать про ORM.
Ну например, я могу для решения какой-то задачи написать просто скрипт на 200 строчек без ООП (и иногда даже без функций), а потом по мере надобности добавлять объекты, библиотеки, итд.
Есть хорошая статья по этой теме (как программисты пекли хлеб): https://habrahabr.ru/post/153225/ - обязательно прочти.
То есть должно быть так: возникает потребность в чем-то и ты применяешь какое-то решение. А не так, что просто подключаешь в проект библиотеку, потому что о ней написали на Хабре. И здесь, конечно, полезно умение замечать эту потребность, видеть, что в коде что-то не так. Ну вот например, ты замечаешь, что получается много однообразного кода и думаешь, как это исправить.
Также полезно, когда ты смотришь чужой код, думать, а почему тут сделано так, а не иначе. Какие еще были варианты? Это поможет тебе научиться инженерному мышлению.
> Простейшее мвс приложение могу построить с роутингом и мини орм, но код выглядит как то убого, не знаю как описать даже.
"выглядит убого" - это не критерий. Ты должен подумать и сформулировать, чем именно плох код. Если никаких мыслей нет, запости кусочек, может более опытные аноны что-нибудь подскажут.
> Тоесть я понимаю как работает синглтон, но когда его лучше использовать?
Когда надо сделать невозможным существование более одного экземпляра объекта ни при каких обстоятельствах. На практике это редко когда нужно, и это неудобно (например, при тестировании мы хотим создавать временные независимые объекты, а не менять свойства этого синглтона), мне так в голову ничего не приходит.
> Так же и с интерфейсами, фабриками.
Про интерфейсы есть урок - https://github.com/codedokode/pasta/blob/master/php/interfaces.md - там есть немного, но в общем интерфейсы мы используем, когда хотим дать возможность писать новые классы, с которыми сможет работать существующий код. Ну например, интерфейс логгера PSR-3 - мы используем в коде интерфейс, а не название конкретного логгера, и благодаря этому можем подключить любой логгер. Почитай про PSR-3 как пример использования интерфейсов, если не знаком с ним.
Фабрика - это класс, создающий объекты. Может использоваться в такой ситуации: есть какая-то библиотека, которая создает объекты. И мы хотим дать пользователю возможность влиять на создание этих объектов. Код библиотеки он править не может, потому мы выносим создание объектов в фабрику и разрешаем пользователю написать и передать библиотеке свою фабрику.
Из примеров использования фабрик я могу вспомнить разве что https://github.com/symfony/form - там есть класс FormFactory (он создает объекты форм и полей в формах - и те и другие там называются Form). Я, кстати, советовал бы тебе разбрать эту библиотеку, в том числе код, и нарисовать диаграмму классов в ней - там много интересного.
Но ты должен добавлять фабрики и интерфейсы только когда ты почуствуешь потребность в них. А не просто добавлять, чтобы были.
> Я напилил кучу интерфейсов
Зачем?
> Что бы все понятно было.
Да, так и должно быть.
> Когда пишешь объектно, код становится каким то неуклюжим, трудно изменяемым
Может ты не очень хорошо разобрался в ООП? По идее, применение ООП как раз позволяет упростить код, так как он разделяется на отдельные классы, каждый из которых решает свою задачу. Ну и почитай статью про хлеб выше, она как раз про это.
> Но в итоге ты углубляешься в код ради кода, а не ради решения задачи
Хорошо, что ты это понимаешь. Попробуй тогда использовать более простые подходы, может для твоей задачи хватит 10-20 функций без ООП? Или может быть не надо так много разных классов.
> помоги как мне быть.
Так как ты не описал свою задачу и не показал куски кода, которые тебе не нравятся, то я могу только дать общие советы.
С одной стороны, ты правильно делаешь, что пытаешься изучать разные готовые решения (паттерны). В веб-приложениях ничего нового изобретать не надо, все уже придумано до нас. Но с другой стороны, ты неправильно делаешь, что пытаешься обязательно использовать в коде какой-то паттерн. Это говорит о том, что ты в них не разобрался и не понял, для чего они нужны, когда их используют.
В программировании (как и в вообще в инженерных науках) для каждого решения есть обоснование. Почему мы хотим сделать так, а не иначе. Чаще даже есть не одно решение, а несколько, мы сравниваем плюсы и минусы и выбираем то, что лучше подходит. Вот например, если у тебя есть свободное время, ты можешь почитать отчет о разработке радиопередатчика для первого спутника (он длинный): http://russianspacesystems.ru/wp-content/uploads/2017/10/Otchet-o-razrabotke-bortovoy-radiostancii-pervogo-sputnika.pdf . В этом отчете формулируется задача, разбираются разные варианты ее решения, и каждый раз обосновывается, почему выбран тот или иной вариант. Например, почему были выбраны лампы, а не транзисторы. Вот в идеале у тебя в голове должен происходить такой же мыслительный процесс. Начинающему, может, это и сложно, но со временем надо к этому стремиться.
Если ты сомневаешься, то можно по умолчанию выбрать самое простое решение. Такое решение, которое требует минимум затрат времени и усилий. Не уверен, нужен ли тебе ORM? Ок, не используй. Но если потом ты заметишь, что пишешь много однотипных SQL запросов, то может быть стоит все же подумать про ORM.
Ну например, я могу для решения какой-то задачи написать просто скрипт на 200 строчек без ООП (и иногда даже без функций), а потом по мере надобности добавлять объекты, библиотеки, итд.
Есть хорошая статья по этой теме (как программисты пекли хлеб): https://habrahabr.ru/post/153225/ - обязательно прочти.
То есть должно быть так: возникает потребность в чем-то и ты применяешь какое-то решение. А не так, что просто подключаешь в проект библиотеку, потому что о ней написали на Хабре. И здесь, конечно, полезно умение замечать эту потребность, видеть, что в коде что-то не так. Ну вот например, ты замечаешь, что получается много однообразного кода и думаешь, как это исправить.
Также полезно, когда ты смотришь чужой код, думать, а почему тут сделано так, а не иначе. Какие еще были варианты? Это поможет тебе научиться инженерному мышлению.
> Простейшее мвс приложение могу построить с роутингом и мини орм, но код выглядит как то убого, не знаю как описать даже.
"выглядит убого" - это не критерий. Ты должен подумать и сформулировать, чем именно плох код. Если никаких мыслей нет, запости кусочек, может более опытные аноны что-нибудь подскажут.
> Тоесть я понимаю как работает синглтон, но когда его лучше использовать?
Когда надо сделать невозможным существование более одного экземпляра объекта ни при каких обстоятельствах. На практике это редко когда нужно, и это неудобно (например, при тестировании мы хотим создавать временные независимые объекты, а не менять свойства этого синглтона), мне так в голову ничего не приходит.
> Так же и с интерфейсами, фабриками.
Про интерфейсы есть урок - https://github.com/codedokode/pasta/blob/master/php/interfaces.md - там есть немного, но в общем интерфейсы мы используем, когда хотим дать возможность писать новые классы, с которыми сможет работать существующий код. Ну например, интерфейс логгера PSR-3 - мы используем в коде интерфейс, а не название конкретного логгера, и благодаря этому можем подключить любой логгер. Почитай про PSR-3 как пример использования интерфейсов, если не знаком с ним.
Фабрика - это класс, создающий объекты. Может использоваться в такой ситуации: есть какая-то библиотека, которая создает объекты. И мы хотим дать пользователю возможность влиять на создание этих объектов. Код библиотеки он править не может, потому мы выносим создание объектов в фабрику и разрешаем пользователю написать и передать библиотеке свою фабрику.
Из примеров использования фабрик я могу вспомнить разве что https://github.com/symfony/form - там есть класс FormFactory (он создает объекты форм и полей в формах - и те и другие там называются Form). Я, кстати, советовал бы тебе разбрать эту библиотеку, в том числе код, и нарисовать диаграмму классов в ней - там много интересного.
Но ты должен добавлять фабрики и интерфейсы только когда ты почуствуешь потребность в них. А не просто добавлять, чтобы были.
> Я напилил кучу интерфейсов
Зачем?
> Что бы все понятно было.
Да, так и должно быть.
> Когда пишешь объектно, код становится каким то неуклюжим, трудно изменяемым
Может ты не очень хорошо разобрался в ООП? По идее, применение ООП как раз позволяет упростить код, так как он разделяется на отдельные классы, каждый из которых решает свою задачу. Ну и почитай статью про хлеб выше, она как раз про это.
> Но в итоге ты углубляешься в код ради кода, а не ради решения задачи
Хорошо, что ты это понимаешь. Попробуй тогда использовать более простые подходы, может для твоей задачи хватит 10-20 функций без ООП? Или может быть не надо так много разных классов.
> помоги как мне быть.
Так как ты не описал свою задачу и не показал куски кода, которые тебе не нравятся, то я могу только дать общие советы.
Ты хочешь написать сервер API (раздавать данные всем), или клиент (получать данные из стороннего сервиса)?
Ты можешь попробовать "выделить объекты", но попытайся сначала сделать минимальный вариант, просто решающий задачу. Может для твоей задачи даже не нужны объекты, а хватит просто массивов (хотя сомневаюсь, что это удобно). Ну и наверняка для твоей задачи уже есть какие-то готовые библиотеки - для преобразования в JSON точно что-то должно быть.
>>43083
> синглтон признан антипаттерном и вместо него следует использовать DI.
Я бы лучше сказал так: использования синглтона вместо DI - это антипаттерн. Вполне возможно, что есть какие-то случаи, где полезен синглтон.
>>43105
>>42805
Это называется "деплой". Гуглится по словам вроде "автоматизация деплоя php", если нет результатов - то же самое по-англйиски. Вот ссылка на гугл, изучай: https://www.google.ru/search?q=автоматизация+деплоя+php&btnG=Поиск&newwindow=1&dcr=0&gbv=1
Можешь потом написать итоги своих поисков для других анонов.
FTP точно использовать не надо, так как он не защищен и позволяет атакаующему просматривать и подменять информацию. Как замена FTP, есть SCP и SFTP - они работают через SSH. Правда, не так много программ, которые их поддерживают.
Ну а вообще, я обычно стараюсь автоматизировать деплой. Глупо тратить время на выделение файлов, нажатие кнопок в GUI, когда можно написать скрипт. В простой ситуации - bash-скрипт (программа на языке bash) с использованием утилиты rsync (он поддерживает передачу файлов по SSH), в сложной - плейбук для ansible. Учти, что многое из этого плохо работает или вовсе не работает под Windows.
Есть еще вариант "деплой через git" - git позволяет выгружать коммиты в удаленный репозиторий на другом сервере.
Ну если тебе лень изучать утилиты linux, ты ведь программист, что тебе мешает написать программу копирования файлов на PHP? Или поискать готовую. Или как-то настроить программу, чтобы деплой делался одной кнопкой.
Хотя конечно скриптами автоматизировать такие вещи удобнее, на мой взгляд.
Ты хочешь написать сервер API (раздавать данные всем), или клиент (получать данные из стороннего сервиса)?
Ты можешь попробовать "выделить объекты", но попытайся сначала сделать минимальный вариант, просто решающий задачу. Может для твоей задачи даже не нужны объекты, а хватит просто массивов (хотя сомневаюсь, что это удобно). Ну и наверняка для твоей задачи уже есть какие-то готовые библиотеки - для преобразования в JSON точно что-то должно быть.
>>43083
> синглтон признан антипаттерном и вместо него следует использовать DI.
Я бы лучше сказал так: использования синглтона вместо DI - это антипаттерн. Вполне возможно, что есть какие-то случаи, где полезен синглтон.
>>43105
>>42805
Это называется "деплой". Гуглится по словам вроде "автоматизация деплоя php", если нет результатов - то же самое по-англйиски. Вот ссылка на гугл, изучай: https://www.google.ru/search?q=автоматизация+деплоя+php&btnG=Поиск&newwindow=1&dcr=0&gbv=1
Можешь потом написать итоги своих поисков для других анонов.
FTP точно использовать не надо, так как он не защищен и позволяет атакаующему просматривать и подменять информацию. Как замена FTP, есть SCP и SFTP - они работают через SSH. Правда, не так много программ, которые их поддерживают.
Ну а вообще, я обычно стараюсь автоматизировать деплой. Глупо тратить время на выделение файлов, нажатие кнопок в GUI, когда можно написать скрипт. В простой ситуации - bash-скрипт (программа на языке bash) с использованием утилиты rsync (он поддерживает передачу файлов по SSH), в сложной - плейбук для ansible. Учти, что многое из этого плохо работает или вовсе не работает под Windows.
Есть еще вариант "деплой через git" - git позволяет выгружать коммиты в удаленный репозиторий на другом сервере.
Ну если тебе лень изучать утилиты linux, ты ведь программист, что тебе мешает написать программу копирования файлов на PHP? Или поискать готовую. Или как-то настроить программу, чтобы деплой делался одной кнопкой.
Хотя конечно скриптами автоматизировать такие вещи удобнее, на мой взгляд.
Пока не думал, да и не уверен, что найдется много желающих что-то мне заплатить. Сейчас ОПу можно помочь, например, отвечая на те вопросы в треде, на которые ты знаешь ответ.
>>43063
Это не самый удачный вариант. curl требует указания разных опций, обработку ошибок и тд. Проще по моему взять библиотеку-HTTP клиент Guzzle.
>>42927
Во-первых, есть же документация. Ты ее внимательно изучил? Идем сюда
- http://php.net/manual/ru/bbcode.installation.php
отсюда идем по ссылке:
- http://php.net/manual/ru/install.pecl.php
И изучаем все, что написано. Обычно это работает так:
Если ты используешь дебиан, то сначала ищешь расширение в apt-get (менеджере пакетов Дебиана), если там его нет, то ставишь через pecl (pecl сам скачает исходники расширения, скомпилирует его и установит). Это просто и удобно, хотя, если будут какие-то ошибки, то конечно без понимания процесса сборки разобраться будет трудно.
Если ты используешь винду, то надо либо искать готовую dll-ку для твоей версии PHP на сайте pecl, либо собирать самому из исходников (это требует установить компилятор вроде Windows SDK или Visual Studio, качать исходники PHP, ставить их в нужную папку, возиться с командной строкой - в общем, будет больно. Описан процесс тут http://php.net/manual/ru/install.pecl.windows.php но без подробностей, а далее подробности надо искать тут https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2#building_pecl_extensions ).
Ты не написал, какой версии у тебя PHP. Тут вот https://pecl.php.net/package/bbcode есть ссылка DLL, и если перейти по ней https://pecl.php.net/package/bbcode/1.0.3b1/Windows то какие-то добрые люди уже собрали расширение для PHP5.3, 5.4, 5.5 и 5.6. Для PHP7 они конечно не подойдут.
Ну и судя по истории релизов, оканчивающейся в 2010 году, с PHP7 это расширение вряд ли совместимо.
Гугление по "bbcode php7" выдает проект - https://github.com/esminis/php_pecl_bbcode - но там нет сборок под винду, то есть там дан только исходный код и надо его самому собирать. В принципе, наверно, это было бы неплохим опытом для тебя, попробовать собрать расширение под виндой, но рассмотрим еще другие варианты.
В документации написано, что есть аналог расширения в виде библиотеки на PHP - http://pear.php.net/package/HTML_BBCodeParser . Он ставится через PEAR - это менеджер библиотек, который умеет их скачивать и устанавливать, но сначала придется научиться им пользоваться, например, найти статью про него или изучить документацию. Но это точно проще, чем компилировать.
Также, есть еще другие разметки, кроме BBCode. Берешь список тут https://en.wikipedia.org/wiki/Lightweight_markup_language изучаешь каждую и проверяешь, есть ли для данной разметки php-библиотека. Например, поиском в packagist.org (репозиторий библиотек для композера).
Пока не думал, да и не уверен, что найдется много желающих что-то мне заплатить. Сейчас ОПу можно помочь, например, отвечая на те вопросы в треде, на которые ты знаешь ответ.
>>43063
Это не самый удачный вариант. curl требует указания разных опций, обработку ошибок и тд. Проще по моему взять библиотеку-HTTP клиент Guzzle.
>>42927
Во-первых, есть же документация. Ты ее внимательно изучил? Идем сюда
- http://php.net/manual/ru/bbcode.installation.php
отсюда идем по ссылке:
- http://php.net/manual/ru/install.pecl.php
И изучаем все, что написано. Обычно это работает так:
Если ты используешь дебиан, то сначала ищешь расширение в apt-get (менеджере пакетов Дебиана), если там его нет, то ставишь через pecl (pecl сам скачает исходники расширения, скомпилирует его и установит). Это просто и удобно, хотя, если будут какие-то ошибки, то конечно без понимания процесса сборки разобраться будет трудно.
Если ты используешь винду, то надо либо искать готовую dll-ку для твоей версии PHP на сайте pecl, либо собирать самому из исходников (это требует установить компилятор вроде Windows SDK или Visual Studio, качать исходники PHP, ставить их в нужную папку, возиться с командной строкой - в общем, будет больно. Описан процесс тут http://php.net/manual/ru/install.pecl.windows.php но без подробностей, а далее подробности надо искать тут https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2#building_pecl_extensions ).
Ты не написал, какой версии у тебя PHP. Тут вот https://pecl.php.net/package/bbcode есть ссылка DLL, и если перейти по ней https://pecl.php.net/package/bbcode/1.0.3b1/Windows то какие-то добрые люди уже собрали расширение для PHP5.3, 5.4, 5.5 и 5.6. Для PHP7 они конечно не подойдут.
Ну и судя по истории релизов, оканчивающейся в 2010 году, с PHP7 это расширение вряд ли совместимо.
Гугление по "bbcode php7" выдает проект - https://github.com/esminis/php_pecl_bbcode - но там нет сборок под винду, то есть там дан только исходный код и надо его самому собирать. В принципе, наверно, это было бы неплохим опытом для тебя, попробовать собрать расширение под виндой, но рассмотрим еще другие варианты.
В документации написано, что есть аналог расширения в виде библиотеки на PHP - http://pear.php.net/package/HTML_BBCodeParser . Он ставится через PEAR - это менеджер библиотек, который умеет их скачивать и устанавливать, но сначала придется научиться им пользоваться, например, найти статью про него или изучить документацию. Но это точно проще, чем компилировать.
Также, есть еще другие разметки, кроме BBCode. Берешь список тут https://en.wikipedia.org/wiki/Lightweight_markup_language изучаешь каждую и проверяешь, есть ли для данной разметки php-библиотека. Например, поиском в packagist.org (репозиторий библиотек для композера).
Библиотека на регулярках создает риск XSS - злоумышленник сможет вставлять произвольный HTML или JS код в страницу.
>>42738
Изучи linux, bash, основные утилиты. По PHP - от админа требуется только умение его установить и может чуть подправить php.ini (почитав мануал), по MySQL - установить и настроить, и на сайте MySQL есть 2 раздела специально для администраторов:
- https://dev.mysql.com/doc/refman/5.7/en/installing.html
- https://dev.mysql.com/doc/refman/5.7/en/server-administration.html
Если же ты хочешь еще научиться программировать на PHP, то изучай первый пост в треде.
>>42733
Может у тебя отключен их вывод через опцию display_errors в php.ini? Или включено их игнорирование через error_reporting? Проверь настройки (с помощью phpinfo()) и изучи логи, может там есть ошибка.
>>42719
Открой в браузере инструменты разработчика на вкладке Network и изучи, какие заголовки отдает твой скрипт. Так не сказать.
>>42686
Я выше расписал, что лучше всего начинать с самого простого решения и добавлять какие-то усложнения по мере надобности. Почитай статью про выпечку хлеба.
А еще, если вдруг ты не очень уверен в ООП, то у меня еще есть пара задач - про Гостиницу и Агенство - не хочешь хотя бы глянуть? https://phpclub.tech/pr/chain/1108694/
> во вторых в этих фреймворках напихано оверхеда дохуя.
А ты не думал, что это может быть сделано по какой-то причине? Вряд ли у них есть цель просто так увеличивать объем кода.
Библиотека на регулярках создает риск XSS - злоумышленник сможет вставлять произвольный HTML или JS код в страницу.
>>42738
Изучи linux, bash, основные утилиты. По PHP - от админа требуется только умение его установить и может чуть подправить php.ini (почитав мануал), по MySQL - установить и настроить, и на сайте MySQL есть 2 раздела специально для администраторов:
- https://dev.mysql.com/doc/refman/5.7/en/installing.html
- https://dev.mysql.com/doc/refman/5.7/en/server-administration.html
Если же ты хочешь еще научиться программировать на PHP, то изучай первый пост в треде.
>>42733
Может у тебя отключен их вывод через опцию display_errors в php.ini? Или включено их игнорирование через error_reporting? Проверь настройки (с помощью phpinfo()) и изучи логи, может там есть ошибка.
>>42719
Открой в браузере инструменты разработчика на вкладке Network и изучи, какие заголовки отдает твой скрипт. Так не сказать.
>>42686
Я выше расписал, что лучше всего начинать с самого простого решения и добавлять какие-то усложнения по мере надобности. Почитай статью про выпечку хлеба.
А еще, если вдруг ты не очень уверен в ООП, то у меня еще есть пара задач - про Гостиницу и Агенство - не хочешь хотя бы глянуть? https://phpclub.tech/pr/chain/1108694/
> во вторых в этих фреймворках напихано оверхеда дохуя.
А ты не думал, что это может быть сделано по какой-то причине? Вряд ли у них есть цель просто так увеличивать объем кода.
Что такое "легкие потоки"? LWP? Если тебе хочется использовать треды, то наверно можно найти какую-нибудь библиотеку под линукс и взять потокобезопасную версию PHP. Но подозреваю, там будут подводные камни, так как я не слышал, чтобы кто-то это использовал.
>>42591
> КТО СКАЗАЛ ЧТО ГЛОБАЛЬНЫЕ ПЛОХО?
Вот ты бы разобрался сначала. Конечно, глобальные переменные плохо, если у тебя скрипт больше 200 строчек. Потому что их можно изменять из любой точки кода и понять, что в них находится в тот или иной момент времени, не изучая весь код, сложно. Более подробно про них ты можешь прочесть кусочек в пасте про DI: https://github.com/codedokode/pasta/blob/master/arch/di.md#Чем-плохи-глобальные-переменные
В реальных проектах могут быть тысячи файлов и миллионы строк кода, и в таком объеме конечно с глобальными переменными работать невозможно. Так как тебе надо перерыть весь миллион строк, чтобы попытаться понять, кто и что туда пишет и когда. Это нереально.
> Область видимости притащили, используй
Так у глобальных переменных глобальная область видимости - они доступны везде (внутри функций импортируются через global) - что ты хотел сказать-то?
> ЛОГИКА И ПРЕДСТАВЛЕНИЕ НЕ ДОЛЖНЫ СМЕШИВАТЬСЯ
Конечно, не должны. Тяжело же читать код, когда идет 5 строк HTML кода, потом SQL запрос на 10 строк, потом разбор результатов этого запроса, потом еще 10 строк HTML и так далее. Удобнее в одном файле получать данные, а в другом выводить их на страницу. Особенно когда у тебя сложные страницы, содержащие много разных блоков и сложная логика получения данных. Почитай урок про шаблоны https://github.com/codedokode/pasta/blob/master/php/templates.md
> твиги прикручивают
Чем твиг лучше встроенного в PHP шаблона, подробно и доходчиво объясняется на главной странице сайта твига: https://twig.symfony.com/ - пробовал почитать?
> А шаблонизатор тоже предоставляет ЛОГИКУ
Логику представления, а не получения данных.
> вкатываение становится проблемой.
Проблема скорее всего в тебе и твоем восприятии. Заходи чаще в наш тред, проходи задачи из ОП-поста и может быть, ты все же сможешь разобраться, зачем нужна та или иная библиотека. У нас тебе всегда этого готовы объяснить.
Что такое "легкие потоки"? LWP? Если тебе хочется использовать треды, то наверно можно найти какую-нибудь библиотеку под линукс и взять потокобезопасную версию PHP. Но подозреваю, там будут подводные камни, так как я не слышал, чтобы кто-то это использовал.
>>42591
> КТО СКАЗАЛ ЧТО ГЛОБАЛЬНЫЕ ПЛОХО?
Вот ты бы разобрался сначала. Конечно, глобальные переменные плохо, если у тебя скрипт больше 200 строчек. Потому что их можно изменять из любой точки кода и понять, что в них находится в тот или иной момент времени, не изучая весь код, сложно. Более подробно про них ты можешь прочесть кусочек в пасте про DI: https://github.com/codedokode/pasta/blob/master/arch/di.md#Чем-плохи-глобальные-переменные
В реальных проектах могут быть тысячи файлов и миллионы строк кода, и в таком объеме конечно с глобальными переменными работать невозможно. Так как тебе надо перерыть весь миллион строк, чтобы попытаться понять, кто и что туда пишет и когда. Это нереально.
> Область видимости притащили, используй
Так у глобальных переменных глобальная область видимости - они доступны везде (внутри функций импортируются через global) - что ты хотел сказать-то?
> ЛОГИКА И ПРЕДСТАВЛЕНИЕ НЕ ДОЛЖНЫ СМЕШИВАТЬСЯ
Конечно, не должны. Тяжело же читать код, когда идет 5 строк HTML кода, потом SQL запрос на 10 строк, потом разбор результатов этого запроса, потом еще 10 строк HTML и так далее. Удобнее в одном файле получать данные, а в другом выводить их на страницу. Особенно когда у тебя сложные страницы, содержащие много разных блоков и сложная логика получения данных. Почитай урок про шаблоны https://github.com/codedokode/pasta/blob/master/php/templates.md
> твиги прикручивают
Чем твиг лучше встроенного в PHP шаблона, подробно и доходчиво объясняется на главной странице сайта твига: https://twig.symfony.com/ - пробовал почитать?
> А шаблонизатор тоже предоставляет ЛОГИКУ
Логику представления, а не получения данных.
> вкатываение становится проблемой.
Проблема скорее всего в тебе и твоем восприятии. Заходи чаще в наш тред, проходи задачи из ОП-поста и может быть, ты все же сможешь разобраться, зачем нужна та или иная библиотека. У нас тебе всегда этого готовы объяснить.
"вкатиться" это значит "устроиться на работу"? В шапке же написано, ищешь вакансии на сайте вакансий, отправляешь отклик, проходишь собеседование и тд. Или тебя что-то конкретное интересует?
Если вопрос "что изучать", то опять же, надо изучить почти всю шапку - серверный язык программирования, SQL, итд.
>>42553
> И тут я понял что я нихера не понимаю как это реализовать в mysql.
Есть 3 паттерна наследования: Single Table Inheritance, Concrete Table Inheritance, Class table inheritance - погугли их для начала и потом задай вопрос, если непонятно.
Учти, что не все паттерны могут поддерживаться в Доктрине, потому глянь еще ее документацию.
>>42549
Не стоит на нее полагаться, но добавить инпут можно. Что касается защиты от загрузки больших файлов, во-первых, есть опции в php.ini вроде post_max_size ( http://php.net/manual/ru/ini.core.php ), во-вторых, опции в конфиге веб-сервера, например в nginx https://nginx.ru/ru/docs/http/ngx_http_core_module.html#client_max_body_size
Также для удобства пользователя можно добавить код на JS, выдающий предупреждение при превышении размера, чтобы пользователь не тратил время и трафик на загрузку файла зря.
Тут объяснение https://phpclub.ru/talk/threads/Зачем-нужно-указывать-в-форме-max_file_size.76276/
Если построение SQL запроса, то использовать можно query biulder. Также, удобно сделать объект для представления фильтра.
Если товаров много, может понадобиться подключать демон поиска вроде sphinx, если SQL база будет тупить.
>>42417
В документации чуть-чуть упомянуто: https://www.slimframework.com/docs/v3/objects/router.html#route-callbacks
В Слиме используется подход, когда "контроллер" получает на вход объекты Запроса и пустой Ответ, и должен заполнить этот Ответ данными (кодом статуса, телом страницы, заголовками, и всем, что HTTP позволяет возвращать в ответе). Есть еще немного другой подход - в Симфони контроллер получает на вход HTTP-Запрос и должен создать и вернуть HTTP-Ответ.
Зачем? Ну, тут есть несколько причин:
- логичность. Теперь у нас контроллер не создает какие-то побочные эффекты (что-то выводит, создает заголовки, куки), а возвращает на выходе результат свой работы - HTTP-Ответ. Логично же, получаем Запрос, обрабатываем и возвращает Ответ
- взаимодействие с middleware. В Слиме есть middleware - обертки, которые могут модифицировать Запрос до его получения контроллером и модифицировать Ответ после того, как он создан, но до того, как он отдан в браузер пользователя. Очевидно, что для этого контроллер должен именно возвращать Ответ. Вывод через echo можно конечно перехватить (и он перехватывается), а вот выставленные через функцию header() заголовки перехватить нельзя и middleware их не получит и не сможет с ними ничего сделать.
- тестирование. Мы можем в тесте создать Запрос, вызвать контроллер, получить Ответ и проверить его правильность. Опять же, в случае использования echo/header напрямую, это невозможно.
- многоразововость. Мы можем в ходе работы скрипта вызвать контроллер(ы) несколько раз и получить несколько Ответов, и что-то с ними делать, как-то их использовать. Можно например сделать несколько контроллеров, каждый из которых отвечает за свою часть страницы.
Аноны, а вы не хотите это перевести на англ и законтрибутить в документацию Слима? А то мы пошлем человека читать документацию, а объяснения там нет.
>>41976
В ОП посте упомянуты книги Зандстры и Шлосснейла(?). Единственный недостаток - староватые, но зато учат в правильном направлении. Ну и php the right way.
>>42591
Ты вбросил в тред код - получил ожидаемую критику. Такие правила этого треда. Но, конечно, важно писать о недостатках корректно. Наша цель ведь не доказать, кто умнее, а обучить.
Если построение SQL запроса, то использовать можно query biulder. Также, удобно сделать объект для представления фильтра.
Если товаров много, может понадобиться подключать демон поиска вроде sphinx, если SQL база будет тупить.
>>42417
В документации чуть-чуть упомянуто: https://www.slimframework.com/docs/v3/objects/router.html#route-callbacks
В Слиме используется подход, когда "контроллер" получает на вход объекты Запроса и пустой Ответ, и должен заполнить этот Ответ данными (кодом статуса, телом страницы, заголовками, и всем, что HTTP позволяет возвращать в ответе). Есть еще немного другой подход - в Симфони контроллер получает на вход HTTP-Запрос и должен создать и вернуть HTTP-Ответ.
Зачем? Ну, тут есть несколько причин:
- логичность. Теперь у нас контроллер не создает какие-то побочные эффекты (что-то выводит, создает заголовки, куки), а возвращает на выходе результат свой работы - HTTP-Ответ. Логично же, получаем Запрос, обрабатываем и возвращает Ответ
- взаимодействие с middleware. В Слиме есть middleware - обертки, которые могут модифицировать Запрос до его получения контроллером и модифицировать Ответ после того, как он создан, но до того, как он отдан в браузер пользователя. Очевидно, что для этого контроллер должен именно возвращать Ответ. Вывод через echo можно конечно перехватить (и он перехватывается), а вот выставленные через функцию header() заголовки перехватить нельзя и middleware их не получит и не сможет с ними ничего сделать.
- тестирование. Мы можем в тесте создать Запрос, вызвать контроллер, получить Ответ и проверить его правильность. Опять же, в случае использования echo/header напрямую, это невозможно.
- многоразововость. Мы можем в ходе работы скрипта вызвать контроллер(ы) несколько раз и получить несколько Ответов, и что-то с ними делать, как-то их использовать. Можно например сделать несколько контроллеров, каждый из которых отвечает за свою часть страницы.
Аноны, а вы не хотите это перевести на англ и законтрибутить в документацию Слима? А то мы пошлем человека читать документацию, а объяснения там нет.
>>41976
В ОП посте упомянуты книги Зандстры и Шлосснейла(?). Единственный недостаток - староватые, но зато учат в правильном направлении. Ну и php the right way.
>>42591
Ты вбросил в тред код - получил ожидаемую критику. Такие правила этого треда. Но, конечно, важно писать о недостатках корректно. Наша цель ведь не доказать, кто умнее, а обучить.
> Очевидно же, что проблема в spellSmallNumber. Но где?
Плюс кода с функциями в том, что мы можем вызывать каждую по отдельности и проверять, правильно ли она работает (дать ей какие-то значения на вход и вывести, что она вернет). Ты можешь как раз это сделать. Заодно натыкать echo в исследуемую функцию, чтобы видеть значения всех переменных в ней. Попробуешь протестировать все свои функции по отдельности? Ты хотя бы найди примерно где проблема, а дальше я могу подсказать, если непонятно.
> Как в PDO заменить mysql_real_escape_string так, чтобы оно работало?
Оно там не нужно, используй плейсхолдеры для вставки значений в запрос. Прочти ты уже любую статью про PDO, где объясняются плейсхолдеры.
По другим картинкам - я бы советовал шаблоны выносить в отдельный файл. И прочитать мой урок про шаблоны с гитхаба.
По работе с формами - не надо использовать сессии для ошибок, есть алгоритм гораздо лучше: https://github.com/codedokode/pasta/blob/master/forms.md
В коде есть и просто ошибки, например, бессмысленная строка
$dateTime;
Далее, quote() в первом примере испоьзован неверно.
strlen тоже использован неверно, почитай урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
По поводу архитектуры - я бы советовал прочесть урок про MVC ( https://github.com/codedokode/pasta/blob/master/arch/mvc.md ), заметь что он не требует ООП и ты можешь получить его, просто вынеся часть кода (например, получение данных из БД) в отдельные функции. Это, например, облегчит повторное использование кода (сейчас у тебя код получения данных вплавлен в шаблон и его нельзя вызвать из другого места) и тестирование.
В четвертом примере у тебя SQL инъекция: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Код у тебя правда плохой, видимо ты учился по какому-то устаревшему учебнику.
Призывать использовать ООП или переходить на фреймворки я тут не буду, не нужно этого делать, пока ты сам не почуствуешь потребность в этом. А вот уязвимости оставлять недопустимо.
>>41811
Вот такой вот у них подход. В Руби он рейлс, которым они вдохновляются, так же. Мне тоже интересно было бы почитать аргументацию за/против, если кому-то еще интересно, нагуглите и напишите тут.
Может они так пытаются упростить код, избавившись от DI? Так там внутри вроде как есть DI конейнер, просто эти статические "фасады" скрывают его наличие.
> Очевидно же, что проблема в spellSmallNumber. Но где?
Плюс кода с функциями в том, что мы можем вызывать каждую по отдельности и проверять, правильно ли она работает (дать ей какие-то значения на вход и вывести, что она вернет). Ты можешь как раз это сделать. Заодно натыкать echo в исследуемую функцию, чтобы видеть значения всех переменных в ней. Попробуешь протестировать все свои функции по отдельности? Ты хотя бы найди примерно где проблема, а дальше я могу подсказать, если непонятно.
> Как в PDO заменить mysql_real_escape_string так, чтобы оно работало?
Оно там не нужно, используй плейсхолдеры для вставки значений в запрос. Прочти ты уже любую статью про PDO, где объясняются плейсхолдеры.
По другим картинкам - я бы советовал шаблоны выносить в отдельный файл. И прочитать мой урок про шаблоны с гитхаба.
По работе с формами - не надо использовать сессии для ошибок, есть алгоритм гораздо лучше: https://github.com/codedokode/pasta/blob/master/forms.md
В коде есть и просто ошибки, например, бессмысленная строка
$dateTime;
Далее, quote() в первом примере испоьзован неверно.
strlen тоже использован неверно, почитай урок https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
По поводу архитектуры - я бы советовал прочесть урок про MVC ( https://github.com/codedokode/pasta/blob/master/arch/mvc.md ), заметь что он не требует ООП и ты можешь получить его, просто вынеся часть кода (например, получение данных из БД) в отдельные функции. Это, например, облегчит повторное использование кода (сейчас у тебя код получения данных вплавлен в шаблон и его нельзя вызвать из другого места) и тестирование.
В четвертом примере у тебя SQL инъекция: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Код у тебя правда плохой, видимо ты учился по какому-то устаревшему учебнику.
Призывать использовать ООП или переходить на фреймворки я тут не буду, не нужно этого делать, пока ты сам не почуствуешь потребность в этом. А вот уязвимости оставлять недопустимо.
>>41811
Вот такой вот у них подход. В Руби он рейлс, которым они вдохновляются, так же. Мне тоже интересно было бы почитать аргументацию за/против, если кому-то еще интересно, нагуглите и напишите тут.
Может они так пытаются упростить код, избавившись от DI? Так там внутри вроде как есть DI конейнер, просто эти статические "фасады" скрывают его наличие.
Какие именно тесты? Юнит-тест например можно просто написать руками. Ну допустим, протестируем функцию mb_strlen:
$len = mb_strlen("Привет");
if ($len != 6) {
throw new TestFailedException("Expected 6, got $len instead");
}
Дальше ты можешь сделать какие-то вспомогательные функции. А потом ты обнаружишь что написал слабый и кривой аналог phpunit.
>>41528
Есть хороший учебник на примере Питона http://aliev.me/runestone/
Самый подробный учебник - это многотомник Кнута (ты скорее умрешь, чем его осилишь).
Ключевые слова для поиска - "алгоритмы и структуры данных".
Также, если ты не понял какой-то алгоритм, можно поискать его название в других источниках - даже в википедии иногда бывает понятно описано.
>>41492
Как я написал выше, либо юнион, либо денормализация с добавлением таблицы, хранящей ссылки на 3 последних поста для каждого треда.
>>41330
> Мануал читал, в английский могу, но я не въехал, как сделать так, чтобы он выбирал случайное число и при этом выводил из массива его значение.
Тут есть 2 момента, на которые ты видимо не обратил внимание:
- array_rand возвращает не значения элементов, а их ключи. Тебе надо самому получить значение из массива по ключу (подсказка: для этого есть квадратные скобки: $value = $array[$key]).
- если попросить 1 ключ, array_rand вернет его. А если 2 или больше - то вернет массив ключей. (это плохой подход, возвращать результат в разных форматах, не делай так). Потому в мануале там использованы квадратные скобки.
> то тут первая и вторая строки (где значения из 1, 2 и 3 массива) получаются абсолютно идентичными.
А это потому что у тебя код в стиле:
- взять случайное слово и записать его в переменную $rand1
- вывести в первой строке $rand1
- вывести во второй строке $rand1
Очевидно, что строки будут одинаковые. Тебе нужны разные переменные для первой и второй строк. Либо же использовать цикл из 2 шагов (на каждом шаге генерируем и выводим одну строку).
Какие именно тесты? Юнит-тест например можно просто написать руками. Ну допустим, протестируем функцию mb_strlen:
$len = mb_strlen("Привет");
if ($len != 6) {
throw new TestFailedException("Expected 6, got $len instead");
}
Дальше ты можешь сделать какие-то вспомогательные функции. А потом ты обнаружишь что написал слабый и кривой аналог phpunit.
>>41528
Есть хороший учебник на примере Питона http://aliev.me/runestone/
Самый подробный учебник - это многотомник Кнута (ты скорее умрешь, чем его осилишь).
Ключевые слова для поиска - "алгоритмы и структуры данных".
Также, если ты не понял какой-то алгоритм, можно поискать его название в других источниках - даже в википедии иногда бывает понятно описано.
>>41492
Как я написал выше, либо юнион, либо денормализация с добавлением таблицы, хранящей ссылки на 3 последних поста для каждого треда.
>>41330
> Мануал читал, в английский могу, но я не въехал, как сделать так, чтобы он выбирал случайное число и при этом выводил из массива его значение.
Тут есть 2 момента, на которые ты видимо не обратил внимание:
- array_rand возвращает не значения элементов, а их ключи. Тебе надо самому получить значение из массива по ключу (подсказка: для этого есть квадратные скобки: $value = $array[$key]).
- если попросить 1 ключ, array_rand вернет его. А если 2 или больше - то вернет массив ключей. (это плохой подход, возвращать результат в разных форматах, не делай так). Потому в мануале там использованы квадратные скобки.
> то тут первая и вторая строки (где значения из 1, 2 и 3 массива) получаются абсолютно идентичными.
А это потому что у тебя код в стиле:
- взять случайное слово и записать его в переменную $rand1
- вывести в первой строке $rand1
- вывести во второй строке $rand1
Очевидно, что строки будут одинаковые. Тебе нужны разные переменные для первой и второй строк. Либо же использовать цикл из 2 шагов (на каждом шаге генерируем и выводим одну строку).
Спасибо большое, отпишусь. Я делал на PHP клонирование части логики с одного сервера на другой, когда выстраивал систему обновления сайта. Там по одной кнопочке запаковывался архив с .php файлами, отправлялся просто по https, далее там уже распаковывался и всё такое.
Разумеется, все с использованием хеша от (данные + секретный ключ), так как с этим нужно осторожнее быть.
Но я отказался от этой системы, т.к. боюсь, она не слишком надежная.
>>42805 анон
и еще пара вопросов
1. подскажите обязательно ли заключать переменные находящиеся в echo внутрь скобок {}, пробовал без них все работает. Зачем они нужны?
2. Что выделено на пике является дурным тоном в написании кода? html так вставлять нельзя, как я понял.
>>42711
ЯСНА ВСЁ. Не передёргивай, говорит, а сам передёргивает. Смарти ему из 2007го... а условий, операторы и прочее в твиг не завезли, да? Ладно, ты уточнил на счёт отделение "логики". Но ведь её и отделяют. Модели и пр. Какая, нахуй, разница - видишь ли хтымыло вместе с пшп, или видишь свой ебучий твиг?
> пиши дальше простыни кода с глобальными переменными, mysql_query и евалами
Ниче ты ПЕРЕДЁРГИВАЕШЬ
>>43114
>>43220
Я насмотрелся уже на хипстеров, которые работая над одним говносайтом, накручивают на него твиги и ебашат его через ГИТ, просто потомушто модно. А если туда надо прикрутить пару процедурок, которые он ниасилил в ходе понимания seo, то ОБЯЗАТИЛЬНА ДАВАЙ ЧЕРЕЗ ГИТ, МНЕ ВАЖНА, НИКТО НИРАБОТАИТ С МАИМ САЙТАМ, НО Я ПАСТАЯННА ГИТПУШУ И ГИТАПДЕЙТЮ И ТЫ ТАК ДЕЛАЙ, НА ХАБРЕ ТАК СКОЗАЛИ.
Про читаемость они мне будут тереть. Научите тут лучше людей классы писать, вызывать всё это, а свои советы про твиги уносите. Принесут догматы про глобалы, твиги, ТЕСТЫ... в тред начинающих, гиты свои прилепят, со словами ТАК НАДА, и рады, ёпт.
это с простыми именами переменных всё нормально
Если будешь выводишь массивы или объекты (не уверен на счет них), то уже не будет работать так просто.
https://ideone.com/YKEYEP
Ты можешь делать так, как тебе больше нравится, просто знай что можно делать, а что нельзя.
А вот тебе спасибо, пишешь лучше.
>>41452
>>41859
Думаю превращение экземпляра класса PHP в JSONAPI объект нельзя назвать просто сериализацией, т.к. мы не только сериализуем класс, когда получаем JSON объект, но предварительно трансформируем класс в объект JSONAPI, например resourceObject, который в свою очередь имеет определенную структуру с обязательными свойствами. И обратная трансформация в большинстве случаев невозможна, т.к. resourceObject не содержит методов класса.
>>Мапирование (иногда маппинг, маппирование, мэппинг, но не путать с маппингом игровых уровней) — определение соответствия данных между потенциально различными семантиками одного объекта или разных объектов. Термин понимается очень широко от отображения одной последовательности элементов на другую последовательность до банальной конвертации файлов.
Мапер / мапирование норм слово для этого случая.
Понял, брат. Здоровья тебе.
Я тут пришел джуниором в реальный проект с хайлоадом, и тут дохера чего в базе лежит джсоном. Например, если брать прикрепление файлов к посту. По методичке тебе нужна таблица files, где каждая строка хранит id поста. У нас же в таком случае просто в таблице posts будет поле files, а в нем json с массивом файлов. Это норм?
Тоесть они хранят в базе, формат передачи данных для JS?
>У нас же в таком случае просто в таблице posts будет поле files, а в нем json с массивом файлов.
Это даже не говнокод, это уже клиника.
JSON - это форматы передачи данных между приложениями. Он основан на JS, но может быть использован где угодно.
Если не будет поиска по имени файлов или еще каким-то их параметрам, не нужно будет mysql с ними работать, вывести и все,
тогда норм.
Иначе избыточно получается.
Я знаю что такое JSON.
Только фишка в том, что он предназначен для формирования из БД. ПРи хранении его в самой бд ты теряешь всю суть JSON, надо получить немного другие данные - хрен, надо изменить выборку - хрен, надо провести другой запрос отличный от задачи - хрен. Надо улучшить бд - хрен, надо решить новую задачу и добавить полей к базе - заново перелопачивать каждое поле.
А потом все стоят и кумекают почему это хайлоап забивает 99% процессора, когда там всего-то неиндексированные имена файлов. Поэтому. Я вот удивляюсь кто в команду берёт людей на архитектуру приложений без знаний даже начальных по БД. И причём смысл то непонятен. Ну вот убрал он ID, а взамен что получил? Ничего же. Где профит то?
>условий, операторы и прочее в твиг не завезли, да?
все завезли
>видишь ли хтымыло вместе с пшп, или видишь свой ебучий твиг?
если у тебя шаблоны в твиге, ты можешь отдать их на редактирование верстальщику, дизайнеру менеджеру или уборщику, не боясь что он 1. обосрется от сложности пхп (а для них он сложный), 2. положит тебе сайт, изменив твои любимые глобальные переменные, например.
и опять же я не предлагаю вводить новые ("новые" лол) технологии только ради того чтобы они были.
про гит же такого вопроса нет, если даже один человек работает над проектом. а тем более если их два. плюсов у гита миллиард, минусов нет. в гите видна история изменений построчно, можно откатиться до рабочего коммита, легко искать баги, делать форки фич, можно автоматизировать деплой и т.д. но я вижу у тебя какой-то особый взгляд на вещи, фундаментально-консервативный, достаточно странный для программиста, но ладно. видимо какие-то причины есть.
>Научите тут лучше людей классы писать
одно другому не мешает. изучение технологий - это такая же часть обучения, как изучение ООП
>работая над одним говносайтом
тут сидят не только те, для которых работа программистом - это работа с говносайтами
>в тред начинающих
и не только начинающие
>накручивают на него твиги и ебашат его через ГИТ, просто потомушто модно
это реально же смешно, это как бабка из того видоса "нам инторнет ваш нахуй не нужон!"
>Плохо ли хранить JSON в SQL и если да, почему?
Если нет выборки по содержимому JSON, то хорошо, если есть такая выборка - то плохо. Потому что индексация.
А если нет выборки, зачем вобще JSON в БД хранить? Можно запилить папку где всё это складировать и получить эдакую документоориентированную СУБД простейшую.
Спасибо
это сложный вопрос. возможно в вашем случае это экономит ресурсы. если, например, вы точно знаете, что никогда не нужно будет переформатировать этот жсон, добавлять туда что-то и т.д. тут лучше спросить у начальника, наверняка он знает причины.
субд то какая?
>У нас же в таком случае просто в таблице posts будет поле files, а в нем json с массивом файлов. Это норм?
возможно, это денормализация (второй вариант - просто всем похуй, что вряд ли в хайлоаде). ее применяют, если запрос в рамках соответствия 3нф выполняется слишком долго (большие объемы данных и/или много джоинов).
>>43441
это тебя на такую мысль сподвиг анон любитель глобальных переменных?
зачем его хранить в бд - а зачем данные типа "текст" хранить в бд? странный вопрос. если они у тебя в базе, ты можешь:
1. подрубить к ним сфинкс в случае необходимости
2. перекатиться на другую субд
3. раскатать данные по разным шардам
4. обращаться к ним в рамках одного запроса к базе, без костылей. если ты используешь ОРМ, то вообще без вариантов
5. ограничивать права (это можно сделать и ограничением прав на папку, но там есть лазейки)
6. делать бэкапы теми же средствами, которыми ты бэкапишь бд
это первое что в голову пришло. а какие плюсы у твоего решения?
На проверку.
https://ideone.com/Ex02H6
https://ideone.com/SkhAgb
https://ideone.com/hyhfDi
https://ideone.com/MTPdrc
https://ideone.com/g5S7HB
https://ideone.com/GA0QeW
https://ideone.com/sgoWlo
https://ideone.com/DjYdhn
https://ideone.com/a81rh0
https://ideone.com/NCaes9
https://ideone.com/W7k6HB
https://ideone.com/c6Lwqo (на айфоне не открывать, на маке тоже, хз как они отреагируют).
Ну опять же всё перечисленное можно сделать и без БД.
>6. делать бэкапы теми же средствами, которыми ты бэкапишь бд
Делать бэкапы вообще любыми средствами.
Ну хз я вообще не вижу преимужеств хранений JSON в БД. Какое-то извращение по моему.
Обычно это бывает когда кто-то слишком "Хорошо" оптимизирует БД. И после этого простое приложение превращается в хайлоад.
>>43559
Блин, я вообще сложно себе представляю именно запрос по которому нужно получить JSON именно из БД. Я привык к логике когда запос обрабатывается в бэке и потом бэк формирует JSON. А тут походу они получают миллиард JSON, или мудрят очень навороченные запросы чтобы получить что-то определённое. Опять же всё это даёт довольно большую нагрузку на сервер, на СУБД, на саму обработку запроса. Но при этом на формирование JSON сервер не тратит ресурсов. Или они просто отдают с десяток мегабайт JSON клиенту, а тот сам всё обрабатывает на своей стороне.
Вот хоть убей не вижу профитов такой схемы.
А в >>43559 ну хорошо, вот только опять же просто в полях хранить данные хранить проще же, и обслуживать проще, и редактировать. Я уже представляю как неверный запрос редактирования случайно редактирует пару сотен лишних ячеек. Короче какая-то странная архитектура если это не документо ориентированная БД.
Вообще, такое иногда бывает нужно. Например, в файлообменнике мы собираем информацию о файле, которая бывает разная в зависимости от типа файла (длительность видео, битрейт, кодек, параметры кодека и тд). Ее удобно хранить как JSON, альтернатива - использовать EAV. Поля под нее делать неудобно, так как свойств может быть много, они сами по себе могут содержать массивы и тд.
Я думаю, дело тут не в хайлоаде, а просто в лени. Из недостатков - поиск по имени файла сделать почти невозможно (в postgresql впрочем можно сделать индекс по отдельному полю JSON документа). Какие-то запросы (вроде найти посты с большим числом файлов) делать неудобно.
А как потом собирать эту информацию? Ну вот например мне нужны все файлы MKV весом больше 5 метров и меньше 250. Я вижу тут только запрос через LIKE. И тут же я понимаю что это ведь довольно сильно даст нагрузки по СУБД. Или вот. Надо все JPG разрешением больше 4к, пережать. Как в таком случае редактировать уже занесённые данные?
Вообще, в Postgres и в новой MySQL есть функции для разбора JSON, а postgres даже позволяет делать индексы по произвольным выражениям, в том числе по полю в JSON.
>Ну опять же всё перечисленное можно сделать и без БД
только с костылями
>я вообще не вижу преимужеств хранений JSON в БД
если ты имеешь в виду "в сравнении с хранением их в файлах", то я тебе назвал шесть. а если про саму идею хранения данных сразу в json, то я согласен.
>>43581
>просто в полях хранить данные хранить проще же
я и не защищаю такую хуйню, просто пытаюсь восстановить логику событий
Тут есть недостатки:
- отсутствие транзакций и блокировок, есть например риск что 2 процесса будут писать в один и тот же файл , или кто-то будет читать не до конца записанный файл
- отсутствие внешних ключей и проверок целостности
- база может быть на отдельном сервере, в случае с файлами тебе придется как-то это самому решать
- в базе есть индексы для ускорения поиска
- база позволяет получить какие-то данные через SQL. В случае с самодельной БД ты это не можешь сделать.
То есть я вообще плюсов не вижу. В чем они? Если тебе хочется хранить данные в файле, есть встраиваемая СУБД sqlite, которая именно это делает.
Пока просто ощущение, что анон думает, что написать свою БД будет быстрее, чем разобраться в уже написанной.
допустим, у тебя есть локальный дев-сервер, приватный "главный" репозиторий на битбакете, куда ты пушишь изменения. какие средства используешь?
бамп
>
>Выше же было про деплой >>43223
я читал, поэтому и стало интересно, что именно ты используешь. я конечно имею в виду уже существующие решения. искал, нашел вот что:
https://deployer.org/docs/getting-started
как раз вариант простого скрипта, о котором ты говоришь. он занимается вопросами типа установки пакетов композера, нпм и т.д., блокировки проекта на момент обновления, но не решает (насколько я понял) с АВТОМАТИЧЕСКИМ обновлением, т.е. ты запушил - он спуллил.
https://www.phing.info/
тут честно говоря черт ногу сломит, но я так понимаю он умеет все
знаю еще есть варианты с teamcity и еще travis, но тимсити жрет ресурсы сервера, т.к. он там сидит в бэкграунде, а если ты снимаешь впс за 5 баксов, то это проблема, а травис платный для не опенсорс проектов.
>>Заходишь по ssh на сервер и выполняешь этот скрипт
вот этот процесс и хотелось бы автоматизировать (не заходить и не запускать каждый раз)
Пихаешь в крон, ну сириосли, что за вопросы.
Какой такой серьезный проект, требующий автоматического деплоя можно пилить не зная о кронах?
П.С Если влом курить баш (что зря), напиши ПХП скрипт.
Ты можешь сделать репозиторий на том же сервере и настроить хуки, чтобы при пуше в него запускался деплой. Также можно установить какой-нибудь Jenkins и попробовать там настроить запуск деплоя при коммите.
я чот сомневаюсь, что это типичный флоу - использовать крон вместо того, чтобы просто ловить вебхук, который шлет гит-сервер.
я перефразирую вопрос (хотя думал, что он достаточно понятно сформулирован): какими КОНКРЕТНО решениями пользуются аноны и почему?
>Открой в браузере инструменты разработчика на вкладке Network и изучи, какие заголовки отдает твой скрипт. Так не сказать.
Да там примитив. Год назад работало, сейчас откопал и решил скопировать схему авторизации - а нихрена.
Код вида
extract($_POST);
if(isset($login) && isset($password)) {
if($login == 'условие' && $password == 'условие') {
header("Location:адрес.страницы");
setcookie("имя_кука", "true", time() + 3600247, "/", null, false, false);
}
else {
setcookie("имя_кука", "false");
header("Location:адрес_другой.страницы");
}
}
1. Почему количество коффе,которое задается в условии для каждой профессии не является свойством? (так написано в подсказках)
2. Зачем нужно свойство "профессия" (так написано в подсказках)?
я только началл ООП и сильно плаваю не стукайте
Только ли через if/else это можно сделать?
<?php
/
Общий интерфейс пула одиночек
/
abstract class FactoryAbstract
{
/
@var array
/
protected static $instances = array();
/
Возвращает экземпляр класса, из которого вызван
@return static
/
public static function getInstance()
{
$className = static::getClassName();
if (!(self::$instances[$className] instanceof $className)) {
self::$instances[$className] = new $className();
}
return self::$instances[$className];
}
/
Удаляет экземпляр класса, из которого вызван
@return void
/
public static function removeInstance()
{
$className = static::getClassName();
if (array_key_exists($className, self::$instances)) {
unset(self::$instances[$className]);
}
}
/
Возвращает имя экземпляра класса
@return string
/
final protected static function getClassName()
{
return get_called_class();
}
/
Конструктор закрыт
/
protected function __construct()
{
}
/
Клонирование запрещено
/
final protected function __clone()
{
}
/
Сериализация запрещена
/
final protected function __sleep()
{
}
/
Десериализация запрещена
/
final protected function __wakeup()
{
}
}
/
Интерфейс пула одиночек
/
abstract class Factory extends FactoryAbstract
{
/
Возвращает экземпляр класса, из которого вызван
@return static
/
final public static function getInstance()
{
return parent::getInstance();
}
/
Удаляет экземпляр класса, из которого вызван
@return void
/
final public static function removeInstance()
{
parent::removeInstance();
}
}
/
=====================================
USING OF MULTITON
=====================================
/
/
Первый одиночка
/
class FirstProduct extends Factory
{
public $a = [];
}
/
Второй одиночка
*/
class SecondProduct extends FirstProduct
{
}
// Заполняем свойства одиночек
FirstProduct::getInstance()->a[] = 1;
SecondProduct::getInstance()->a[] = 2;
FirstProduct::getInstance()->a[] = 3;
SecondProduct::getInstance()->a[] = 4;
print_r(FirstProduct::getInstance()->a);
// array(1, 3)
print_r(SecondProduct::getInstance()->a);
// array(2, 4)
<?php
/
Общий интерфейс пула одиночек
/
abstract class FactoryAbstract
{
/
@var array
/
protected static $instances = array();
/
Возвращает экземпляр класса, из которого вызван
@return static
/
public static function getInstance()
{
$className = static::getClassName();
if (!(self::$instances[$className] instanceof $className)) {
self::$instances[$className] = new $className();
}
return self::$instances[$className];
}
/
Удаляет экземпляр класса, из которого вызван
@return void
/
public static function removeInstance()
{
$className = static::getClassName();
if (array_key_exists($className, self::$instances)) {
unset(self::$instances[$className]);
}
}
/
Возвращает имя экземпляра класса
@return string
/
final protected static function getClassName()
{
return get_called_class();
}
/
Конструктор закрыт
/
protected function __construct()
{
}
/
Клонирование запрещено
/
final protected function __clone()
{
}
/
Сериализация запрещена
/
final protected function __sleep()
{
}
/
Десериализация запрещена
/
final protected function __wakeup()
{
}
}
/
Интерфейс пула одиночек
/
abstract class Factory extends FactoryAbstract
{
/
Возвращает экземпляр класса, из которого вызван
@return static
/
final public static function getInstance()
{
return parent::getInstance();
}
/
Удаляет экземпляр класса, из которого вызван
@return void
/
final public static function removeInstance()
{
parent::removeInstance();
}
}
/
=====================================
USING OF MULTITON
=====================================
/
/
Первый одиночка
/
class FirstProduct extends Factory
{
public $a = [];
}
/
Второй одиночка
*/
class SecondProduct extends FirstProduct
{
}
// Заполняем свойства одиночек
FirstProduct::getInstance()->a[] = 1;
SecondProduct::getInstance()->a[] = 2;
FirstProduct::getInstance()->a[] = 3;
SecondProduct::getInstance()->a[] = 4;
print_r(FirstProduct::getInstance()->a);
// array(1, 3)
print_r(SecondProduct::getInstance()->a);
// array(2, 4)
>Есть 3 паттерна наследования: Single Table Inheritance, Concrete Table Inheritance, Class table inheritance - погугли их для начала и потом задай вопрос, если непонятно.
В общем почитал я про них, как я понял единого верного варианта нет. Я могу просто прикинуть что расширяющих файл сущностей у меня будет точно не много (изображение, аудио, видео), и использовать одну общую таблицу. Хотя более логичным мне кажется использовать паттерн одна сущность - одна таблица без явных связей с другими таблицами(Concrete Table Inheritance), ведь объект полностью имеет поля своего предка, и раз в бд нельзя провернуть наследование, то может оно и не нужно? Хотя говорю я это без опыта работы с любыми орм и паттернами бд, на практике хз как выйдет.
И у меня еще вопрос по поводу хранения файлов. Я правильно понимаю что в бд я записываю путь к файлу, который лежит на диске, а потом при отправке пишу нужные заголовки и вставляю туда же путь к файлуу слима вроде обёртка есть для переменной _FILES,
но я в подробности не вникал, и он оп и отправился?
Друзья, вопрос...
Есть верстка сайта школы стилистов. На одной из страниц выводятся все курсы с кнопкой "Узнать подробнее", при нажатии на которую, открывается страница с подробной информацией об этом курсе.
Нужно сделать такую админ панель, где будет страница с полями "Название курса", "Дата", "Изображение курса" и т.п. Человек заполняет все нужные поля и нажимает на кнопку добавить. И на страничке курсов появляется этот курс. Можно как-то по-другому это реализовать, но главное чтобы сократить работу с кодом к минимуму.
Первый опыт с сайтом, не знаю куда двигаться.
Конечно, я могу наклепать таблицы, написать PHP код, сверстать быстренько админ панель. Но я боюсь это делать, потому что опыта то нет.. Будут проблемы с безопасностью, как-то криво будет работать..
Сейчас взялся за ModX, как я понимаю, с помощью него я смогу все это реализовать. Но возможно есть более лучшее решение этой ситуации для новичка?
Спасибо, очень жду ответа, потому что время поджимает...
Работу не найти по симфоне. На битрикс дофига вакансий. А если с английским разговорным плохо, то вообще не найти симфони.
лол, подставляешь в качестве ключа, название роута, а в качестве значения, либо функцию которая открывает тебе твой контроллер, либо другой массив с ключами других роутов.
Коллега устроился на 15к на первый месяц наработал стаж - год и ушел из этой конторы в другую на 50к. Вышки у него нет.
Такое только до 2010 прокатывало. Сейчас такого простого вката нету, только битрикс, край вп.
Если по твоему это так просто, то почему статей нет, почему все пишут на регулярках? А на деревьях знаешь как сделать?
Это в каких-таких Мухосрансках нет симфони?
Симфони ща в любой дырке затычка:
Ларавель - юзает библиотеки Симфони
Друпал 8 - юзает компоненты Симфони
Тем более Симфони, это автоматически юзание композера.. Со знанием Композера заехать в тот же YII2 вообще на изи.
Даже в моей ебучей провинции 3-4 ваканчии в пару месяцев появляется. Какой нахой Битрикс.
Битрикс программист вообще не программист а собиратель говна и палок, чтобы клеить костыли.
Нм одна блять здравая контора не возьмет Битрикс как основу для проекта выше обычного.
Интеграция с Адинэс из коробки (единственный плюс Битрикса) не является сколь либо сложно задачей для имея на руках библиотеку уровня Симфони/ЮаЙаЙ
https://phpclub.tech/pr/chain/1108694/
Тут просто надо методы прописать и параметры объектов? Или надо еще указать как взаимодействуют объекты между собой? Надо ли подключить базу и как то настроить все?
Какая разница кто что юзает, причем тут композиры?
Вопрос в другом, каких контор больше, битрикс клепальщиков или симфони ковыряльщиков и куда вкатиться проще.
На симфони почти в любой конторе нужны только синьеры, максимум на что согласятся, мидлы с 1-3 годами опыта. При этом еще покажи им исходники проектов и все такое.
В битрикс вкатываешься стажером и все. Хотя постепенно битрикс тоже переходит такую модель, как брать только опытных с 1-3 года опыта. Становится труднее вкатится, но все еще можно.
>Битрикс программист вообще не программист а собиратель говна и палок, чтобы клеить костыли.
Зависит от тебя, если ты собираешь говно и палки, то это не проблема битрикса, там много чего приходится дописывать, никто же не заставляет говнокодить, но ты же не можешь не говнокодить без симфониларавель, да?
>Нм одна блять здравая контора не возьмет Битрикс как основу для проекта выше обычного.
Кекаю с наркомана. Берут как миленькие. Тебя что в интернет не пускают?
Ты в какой провинции живешь? Квебек? В провинция ойти вообще нету. Одни 1с и битриксоиды. А если и появляется то надо чтоб в мухосрани ты откуда то получил опыт в 3 - 5 лет чтобы взяли.
Насмешил меня, спасибо.
>Какая разница кто что юзает, причем тут композиры?
>Вопрос в другом, каких контор больше, битрикс клепальщиков или симфони ковыряльщиков и куда вкатиться проще.
Вопрос в том что вкатиться ты вкатишься, а вот выкатиться из этого говна будет проблематично.
Лучше сразу вкатываться где прямые руки писали, чем потом переучиваться в пряморукий кодинг.
>В битрикс вкатываешься стажером и все. Хотя постепенно битрикс тоже переходит такую модель, как брать только опытных с 1-3 года опыта. Становится труднее вкатится, но все еще можно.
В крупных компаниях есть Trainee, есть фриланцы и т.д. было бы желание
>Зависит от тебя, если ты собираешь говно и палки, то это не проблема битрикса, там много чего приходится дописывать, никто же не заставляет говнокодить, но ты же не можешь не говнокодить без симфониларавель, да?
Предпочитаю не забивать гвозди утюгом. А вы?
>Ты в какой провинции живешь? Квебек? В провинция ойти вообще нету. Одни 1с и битриксоиды. А если и появляется то надо чтоб в мухосрани ты откуда то получил опыт в 3 - 5 лет чтобы взяли.
Хохлостанская южная мухосрань. У нас тут около 15 компаний в городе. Есть такие же битрикс-клепальщики, есть малые стартапы за доширак и опыт, если филиалы крупных компаний типа ДатаАрта. Короче на любой вкус.
Плюс опять же никто не отменял удаленку.
На серьезных щщах реально втирать что Битрикс тру - ну это пиздец. Есть задачи, для которых он хорош (тот же 1С), и дядя доволен что сайт быстро заработал и за десять тыщь - но в целом это тупиковая ветка если есть желание уйти куда в хай лоад или биг дату со временем.
>Хохлостанская
Ну я так и понял. Ты вообще не вкурсе, что тут происходит. О чем с тобой говорить.
>мухосрань
>15 компаний
Ну ну, мухосрань, конечно.
Трени и прочие стажировки в дсах, в ваших хохломухосранях оно понятно что всяким датаартам негде брать стажеров.
Удаленка и срилансы, как я уже выше писал нужен разговорный язык нормальный, помимо языка тебе нужно будет показать опыт и портфолио, чего ты в мухосрани не наработаешь.
>Предпочитаю не забивать гвозди утюгом. А вы?
К чему это сказано? Тебе наверное непонятен смысл этой фразы. Битрикс очень даже по назначению применяют, как ты ниже сам заметил. А то что тебе придется писать, какой либо сервис для интеграции с каким либо апи или бизнес логику клиента, так оно тебе и на симфони придется писать.
>На серьезных щщах реально втирать что Битрикс тру - ну это пиздец.
>Есть задачи, для которых он хорош (тот же 1С), и дядя доволен что сайт быстро заработал и за десять тыщь
Ты либо трусы одень, либо крестик сними.
Смысл бесполезного хейта битрикса? Тебе говорят как есть, причем в другой стране, ты говоришь да как такто, у нас же все так. Никто не спорит, что есть у него свои недостатки. Но нету выбора, по описаным выше причинам.
Добавлю, что если и вкатываетесь, начиная с битрикса, то лучше, когда вы будете работать над проектом в команде, а не в одиночку.
работу на битриксе не найти. в макдаке дофига вакансий.
а если с английским плохо, нужно подучить. ты же пхп выучил как-то. я не представляю как вообще можно гуглить без знания английского.
когда я последний раз смотрел работу на хх, там было 300 вакансий со словом "симфони" и из них 50 по удаленке. это меньше, чем на битриксе, но и специалистов меньше.
>>44144
>Зависит от тебя, если ты собираешь говно и палки, то это не проблема битрикса
какой "зависит от тебя". битрикс это позволяет и поощрает. если ты работаешь на симфони, ты по крайней мере пишешь тесты, т.к. это практикуется в конторе. а на битриксе ты глушишь все нотисы и ворнинги, которые он генерит.
плюс ты наверное видел много битрикс-кода и знаешь, что там нормальная практика писать sql-запросы прямо в шаблоне (или как он у вас называется).
https://habrahabr.ru/post/282333/ вот есть статья, объясняющая, почему говнокод в битриксе - это проблема битрикса.
>В провинция ойти вообще нету. Одни 1с и битриксоиды.
я в дс работаю на симфони (на удаленке), у нас удаленные же сотрудники из разных городов, в т.ч. из такой жопы, до которой лететь 6 часов.
>>44163
>Но нету выбора, по описаным выше причинам.
по причинам "незнания разговорного английского" лол?
я тебе очень рекомендую подучить язык и перекатиться в будущем. поверь, ты прям задышишь по-другому. работать на битриксе это как работать инженером в советском нии. ты себя ненавидишь, все друг друга ненавидят, бедность и депрессия.
>>44154
>это тупиковая ветка если есть желание уйти куда в хай лоад или биг дату со временем
я работал в конторе, которая начинала с битрикса и потом продукт стал хайлоадом. это боль, конечно.
работу на битриксе не найти. в макдаке дофига вакансий.
а если с английским плохо, нужно подучить. ты же пхп выучил как-то. я не представляю как вообще можно гуглить без знания английского.
когда я последний раз смотрел работу на хх, там было 300 вакансий со словом "симфони" и из них 50 по удаленке. это меньше, чем на битриксе, но и специалистов меньше.
>>44144
>Зависит от тебя, если ты собираешь говно и палки, то это не проблема битрикса
какой "зависит от тебя". битрикс это позволяет и поощрает. если ты работаешь на симфони, ты по крайней мере пишешь тесты, т.к. это практикуется в конторе. а на битриксе ты глушишь все нотисы и ворнинги, которые он генерит.
плюс ты наверное видел много битрикс-кода и знаешь, что там нормальная практика писать sql-запросы прямо в шаблоне (или как он у вас называется).
https://habrahabr.ru/post/282333/ вот есть статья, объясняющая, почему говнокод в битриксе - это проблема битрикса.
>В провинция ойти вообще нету. Одни 1с и битриксоиды.
я в дс работаю на симфони (на удаленке), у нас удаленные же сотрудники из разных городов, в т.ч. из такой жопы, до которой лететь 6 часов.
>>44163
>Но нету выбора, по описаным выше причинам.
по причинам "незнания разговорного английского" лол?
я тебе очень рекомендую подучить язык и перекатиться в будущем. поверь, ты прям задышишь по-другому. работать на битриксе это как работать инженером в советском нии. ты себя ненавидишь, все друг друга ненавидят, бедность и депрессия.
>>44154
>это тупиковая ветка если есть желание уйти куда в хай лоад или биг дату со временем
я работал в конторе, которая начинала с битрикса и потом продукт стал хайлоадом. это боль, конечно.
global $DB, $USER;
бррр
>Смысл бесполезного хейта битрикса?
смысл защищать битрикс? если перестанешь его защищать и станешь ненавидеть как все, то со временем перекатишься на нормальный фреймворк. необязательно симфони, хоть на yii. на yii дохера работы в провинциях же.
на друпал обрати внимание.
вообще, это достаточно объемная задача, если ты раньше такого не делал. человек, который этим уже занимался и владеет инструментами, сделает такую задачу за рабочий день спокойно. а если ты не делал, это может занять от дня до нескольких недель.
у тебя три варианта:
1. написать все с нуля на голом пхп. это не варик для продакшна, так делают только в учебных целях
2. взять фреймворк, тот же Симфони и там уже есть необходимые решения - doctrine, security, easyadminbundle. но нужна какая-то база, чтобы те же сущности ОРМ правильно выстроить.
3. взять CMS: drupal, wodrpress или любой другой. думаю, для тебя это самый быстрый путь, но там тоже придется покопаться.
вот еще есть http://cmf.symfony.com/ но я не могу его рекомендовать, т.к. сам не пользовался. по презентации http://cmf.symfony.com/slides/why_symfony_cmf.html понял, что это что-то среднее между друпалом и симфони. может другие аноны подскажут по нему
Мне недавно прилетел заказ на 500 рублей (мой первый заказ лол), допилить форму продажи, допилить загрузку фоток, и сделать им превьюшки. В общем до этого ковырялся я в пхп пару месяцев и буквально на базовом уровне знал html и css, ну думаю ща тут все раскидаю на изи. Открываю я этот битрикс, нихуя не понимаю, какая-то статистика скорости сайта, предлагают прям там пройти какие-то тесты блять, десять тыщь папок, шаблоны страниц в одной папке, заголовки и футеры в другой, стили в третей, оче сложная навигация, потом оказалось что у чувака сайт сверстан на таблицах, я об этом только читал на самом деле, а сейчас сам столкнулся, ну я не растерялся и ебанул таблицу в таблицу(так нужно было). Потом я еще пол дня ебался с джаваскриптом, так как до этого его не трогал вообще, но в итоге всё сделал, все довольны, лол. Пхп так и не трогал. Короче ковыряться в этом говне не вызвало у меня никаких положительных эмоций. Буду дальше пинать фреймворки и созидать.
Дело не в защите, плохому програмисту, всегда другие программисты мешают. Это актуально и для фреймворков.
> если перестанешь его защищать и станешь ненавидеть как все, то со временем перекатишься на нормальный фреймворк.
Вуду магия какая то.
>нихуя не понимаю
А если бы прилетел ларавели, ну или на друпале или вукомерце, ты бы сразу познал дзен?
В случае Гостиницы - написать классы целиком. И можно кусочек кода, который их использует (создает гостиницу, заселяет туда несколько человек, выводит статистику).
В случае Агенства - достаточно просто написать названия классов, полей и методов в них. Весь код писать не надо, проверяются только навыки проектирования.
>Дело не в защите, плохому програмисту, всегда другие программисты мешают. Это актуально и для фреймворков.
не понял твою мысль. если ты имеешь в виду, что человек, отказывающийся работать с говном типа битрикса и на фреймворках не сможет что-то сделать, то это не так. и на моем примере, и на примере коллег.
бытует мнение что мол программист должен к любым продуктам, с которыми работает, относиться одинаково и не иметь предпочтений типа это всего лишь инструменты. мол пишу на симфони, но предложат на битриксе поработать - соглашусь. для бизнеса это может
и корректно, но для специалиста ошибочно. можно по рынку труда посмотреть, что специализация рулит.
это как таксист будет говорить "мне похуй на чем бомбить, на камри или на классике - это всего лишь инструменты".
то не взял бы такой заказ, лол
>не понял твою мысль
Имел ввиду, что хороший специалист, даже сбитриксом напишет нормальный код, не ухудшающий приложение в целом.
Так и плохой спец взяв фреймворк, все равно будет лепить код как может, сделав практически непригодным для дальнейшей поддержки без глобального рефакторинга.
Про специализацию, это само собой. Я сейчас про вкатывальщиков и начинающих, у которых в мухосрани просто нет выбора. Да и в дсах, можно прождать вакансию для вкатывающегося от года и больше.
Дело не только в коде, битрикс может вести себя непредсказуемо и это бесит. Второе: из коробки в битриcке есть много всего, но используется из этого далеко не все. Вот нахуя мне столько полей в инфоблоке? Это как пример. Я не работал с современным фреймворком, но мне кажется, что используя фреймворк ты используешь только те компоненты, которые тебе действительно нужны.
Как может код вести себя непредсказуемо? Или в фреймворках, какой то пхп, что там все предсказуемо?
В фреймворках тоже всего много, например различия ларавель или слим. Мне тоже много всего ларавельного не надо. Это не основание говорить, что это плохой фреймворк.
Мне кажется ты можешь использовать те поля, которые действительно тебе нужны?
Помню, как не мог понять, почему 404 при переходе на страницу новости. Дело было в том, что нужно было в настройке компонента убрать галочку и поставить ее снова. Два клика мышью у одного и того же чекбокса. Ебля с кэшированием. Разворот локальной версии - access denied, ок, поменял в базе имя хоста на локальный.
>Мне кажется ты можешь использовать те поля, которые действительно тебе нужны?
А потом заказчик спрашивает, почему все так тормозит
с битриксом наверное можно написать хороший код, но это сложно по трем причинам:
1. битрикс не способствует быстрому профессиональному росту
2. битрикс поощрает плохие практики
3. (самое главное) в конторах, где используют битрикс, обычно на хороший код кладут хер. думаю, ты с этим сам согласишься
>Так и плохой спец взяв фреймворк, все равно будет лепить код как может
конечно. но тут скорее важно не то, что он плохой специалист, а то что есть много программистов, которым вообще срать на качество кода. типа работает и ладно. а сама экосистема фреймворка и контор, которые его используют, обычно такого не терпит.
>у которых в мухосрани просто нет выбора
вменяемые курсы, фриланс, релокацию ты за вариант не считаешь. тогда да
>Да и в дсах, можно прождать вакансию для вкатывающегося от года и больше
ну нет конечно. в дс1 можно сегодня устроиться, а завтра выйти на 30к. я даже могу подсказать места, лол
Отвечаешь ему честно, причем тут ты то? Алсо, при отсутствии каких либо особых хотелок, кэш вполне вытягивает. Так что попробуй еще.
>используя фреймворк ты используешь только те компоненты, которые тебе действительно нужны
если он компонентный, то да
>>44291
>Мне тоже много всего ларавельного не надо
в симфони 4 ты ставишь symfony/skeleton и там по дефолту только самый минимум компонентов. нет ни профайлера, ни твига, ничего. все ставишь по желанию
Ну не понимание, как работает система, с которой ты работаешь, конечно же затрудняет работу.
Да и отсутствие настроенного деплоя, так же мешает.
Тут уж надо самом с этим что то делать.
Битрикс хоть и предлагает свою систему развертывания, никто ей не пользуется, так как быстрее самому сделать.
>в симфони 4
А заказчик хочит ларавель, поэтому что эта модна.
То есть теперь мне надо начать ненавидеть ларавель, чтобы перейти на "нормальный фреймворк"?
ну нет, не надо его ненавидеть. ларавел тоже пиздатый, просто я его плохо знаю, чтобы что-то в нем советовать
Все сказанное про битрикс верно, если ты попал в плохую контору, где нету хороших спецов. Актуально так же для любого другого фреймворка языка. Я как то давно легаси на кодигнайтере поддерживал. Контроллер или модель на 5-7к строк, вполне имело место быть.
Отличие от битрикса было лишь в том, что битрикс со своими компонентами на 5к строк, а тут контроллеры на столько же.
Да обычно вебстудии с битриксом имеют тенденцию хороший код не писать. Но есть и конторы, которые поддерживают один два проекта на битриксе, вполне способны тебе дать основы, возможно хуже чем если бы ты начал в хорошей конторе с фреймворком, но в целом для начала вполне неплохо.
Я бы сказал, что не стоит выбирать галеры, отдавай предпочтения конторе, которая строит бизнес вокруг своего сайта, для нее критически важно иметь высокий уровень.
>вменяемые курсы
Например? В мухосрани потом приди и скажи, что курсы прошел. Над тобой посмеются дружно всем офисом.
>фриланс
С нуля во фриланс, это самоубийство, даже хуже чем в битрикс вкатываться. Если тебе повезло и ты опытный, можно на удаленку попробовать, но это не для всех.
>релокацию
Кому вкатывальщик без опыта нужен?
Да и с опытом, переехать в другой город, помогают не так уж и много компаний. Если ты средний спец, вряд ли стоит ожидать. Был бы опытным и топовым спецом, давно бы уже пробовал за границу уехать.
Ключи ведь привязаны к конкретным юзерам но в документации я не нашел ничего о том, как сгенерировать ключ юзера через API. Такое впечатление, что их API это чисто для юзеров с доступом в админку
>если ты попал в плохую контору, где нету хороших спецов
битрикс - это низший сегмент рынка по баблу. поэтому в общем случае там экономят на качестве и хороших спецов меньше. если есть битрикс-конторы с хорошим кодом, то заебись. лично я не встречал (а я работал в двух, лол)
>отдавай предпочтения конторе, которая строит бизнес вокруг своего сайта
это 100%
>Например? В мухосрани потом приди и скажи, что курсы прошел
profit, например. при желании можно их и в торрентах найти. необязательно говорить про курсы, можно показать знания, свои проекты, коммиты в какие-то библиотеки.
>С нуля во фриланс, это самоубийство
ну мб
>Кому вкатывальщик без опыта нужен?
опять же после некоторых курсов могут предложить стажировку за три рубля, а после стажировки релокацию. ну то есть оффер, а ты сам эту релокацию проводишь.
Короче надо поправить форму обратной связи на лендосе и захотелось это сделать на локальном серве. Какая сейчас прога есть для этого или онлайн песочница чтобы по быстрому скормить этому всем html-css-js-php файлы и оно фурычило? Может какой-то аналог codepen jsfidle?
Алсо на компе стоит Денвер но я его год где-то не трогал, лол. Может что-то попроще есть для такой просто задачи?
Ты по какому мануалу делаешь? В подсказках предлагают сделать профессии классами
Можно на любой СУБД. Я бы советовал брать ту, с которой раньше не работал - чтобы расширить кругозор. Если ни с одной не работал, то можно взять postgres.
Гайды выглядят очень годно и подписка вроде не дорогая. Не понимаю правда что мешает мне за месяц скачать все курсы.
https://www.codecourse.com/lessons/build-your-own-realtime-php-server/2223
Человеку сделал "фронтендер" на WPBakery Page Builder сайт для крипто-валют без оптимизации, на половину кривой. а я его второй день правлю и ахуеваю.
В конце спрошу сколько он "фронтендеру" отдал чтобы еще раз ахуеть.
>А как потом собирать эту информацию?
Если требуется только показывать её юзеру, то и не надо ничего собирать. А жсон в этом случае используется для удобства обработки жаваскриптом, например. Если когда-нибудь потребуется выборка, тогда и изменят схему БД и распихают жсон по табличкам, это не проблема.
А причем тут вп? Это же какой то бакерибулдер, и фронтендер сделали. Считай ты ему полсайта сделал.
С action="register.php" пробовал, так же бесполезно.
бамп
А что ты делаешь? Я просто виду на скриншоте точку останова (или что значит красный кружок) и пытаюсь понять, что ты делал.
Да то я случайно тыкнул.
Я пытаюсь отправить пост запрос на эту же страницу.
В хроме просто ничего не происходит, в фаерфоксе после отправки (значит, пост запрос все таки отправляет?) вот такая вот херня
ну у тебя где этот register.php лежит?
у тебя форма должна слать запрос этому файлу именно.
если у тебя обработчик лежит в /htdocs/shop/register.php
то и в форме напиши action="/htdocs/shop/register.php"
Ну вот так и надо было писать:
- открываю такую-то страницу с таким-то URL
- ввожу в форму то-то и то-то
- жму такую-то кнопку
- вижу ошибку 404 и такой-то URL
А ты можешь сравнить URL в адресной строке, когда ты просто открываешь форму в браузере и она видна, и URL при отправке формы?
Я помню, что несколько месяцев назад анон писал про такую же проблему. и мне кажется, что дело может быть в шторме. У тебя наверно установлен PHP, ты не мог бы попробовать запустить встроенный в него сервер и открыть в браузере страницу через него? Это описано тут и потребует немного возни с командной строкой: https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Встроенный-в-php-сервер
Пока моя версия - у встроенного в Шторм веб-сервера какие-то проблемы с обработкой POST запросов.
Тут пишут что $_POST приходит пустым. https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000097930-Can-not-use-POST-method-in-PhpStorm
Тут пишут ( https://stackoverflow.com/questions/34785913/phpstorm-10-0-3-error-502-bad-gateway-due-to-javavm/34787827#34787827 ), что можно проверить логи phpstorm ( PHPstorm/Help/Show Log in Explorer ) - попробуй глянуть, что там?
Я корректно понимаю принцип работы на проде? Мы запускаем cache:clear (создается папка prod от имени нашего пользователя, права 755) и далее не позволяем системе создавать свои скомпилированные файлы в эту папку (она этого все равно сделать не сможет, т.к. пользователь у нее www-data), а создаем их сами, прогревая кеш? Тогда они создаются от имени нашего пользователя и все заебись.
То есть вопрос в том, что правильно ли я понимаю, что без прогрева не надо вообще на проде ничего менять?
>Ну вот так и надо было писать:
Сорри, туплю :-(
>ты можешь сравнить URL в адресной строке, когда ты просто открываешь форму в браузере и она видна, и URL при отправке формы?
Пикрелейтед оно?
>попробуй глянуть, что там?
2018-02-23 00:12:31,898 [30225280] INFO - ide.actions.ShowFilePathAction -
Exit code 1
>Это описано тут и потребует немного возни с командной строкой
Сейчас попробую
вот тут http://symfony.com/doc/current/setup/file_permissions.html написано:
>If you decide to store log files on disk, you will need to make sure your logs directory (e.g. var/log/) is writable by your web server user and terminal user. One way this can be done is by using chmod -R 777 var/log/. Just be aware that your logs are readable by any user on your production system.
То есть один способ такой (топорный), а какие есть еще?
Я пока придумал только дать на папку права допустим 770, в кач-ве владельца поставить нашего terminal user и включить пользователя www-data в группу terminal user. Или создать им какую-то общую группу и поставить ее в кач-ве группы для этой папки.
Может есть какие-то еще более изящные варианты?
>ока моя версия - у встроенного в Шторм веб-сервера какие-то проблемы с обработкой POST запросов
Да, ты прав.
Вышел из шторма, запустил через хампп - и все заработало.
Столько времени и нервов убил, печаль :-/
Спасибо большое.
Не уверен. По задумке да, на проде кеш генерируется из cli при деплое. Но я гарантировать, что симфони не захочет что-то записать в кеш, не могу. Ну например, там есть кеш для результата разбора DQL запросов (в доктрине) - по умолчанию вроде используется apcu, но кто знает, какие у тебя могут быть настройки. И какие там еще могут быть кеши.
Так что могу лишь посоветовать проверить экспериментально и понаблюдать.
>>44595
Если URL одинаковый (а это вроде так), то проблема в встроенном в шторм сервере, он не работает с POST запрросами. Нужно освоить встроенный в PHP сервер (проще всего), либо Апач, либо nginx + php-fpm.
Простой вариант - запускать веб-сервер от того же юзера, что и используется в cli. Но тут минус: что, если разработчиков больше одного? Да и не хочется серверу давать доступ к своим файлам.
Можно тогда попробовать взять всех разработчиков + создать пользователя-веб-сервера и объединить их в группу. Сделать ее основной для пользователя-веб-сервера (чтобы создаваемые им файлы получали ее). Сделать chown на эту группу для всех файлов. Дать полный доступ к файлам участникам группы.
Подвох: если у кого-то из разработчиков эта группа не основная, то у создаваемых им файлов будет другая группа и веб-сервер и другие разработчики не получат к ней доступ.
Другой подвох: если есть несколько сайтов, у каждого своя группа то в любом случае у разработчика какая-то группа будет не основной.
Подвох: по умолчанию umask = 022 и надо его поменять на 002 иначе создаваемые файлы и папки будут иметь права rx для группы, а не rwx.
В этом случае остается только использовать ACL вместо ограниченной системы unix прав из 3 циферок. Там можно будет всех поместить в группу и дать доступ пользователям этой группы, даже если она у них не основная. ACL вроде умеют наследоваться с папки на вложенные папки и файлы по умолчанию. Но это надо уточнить.
То есть, если подытожить:
- либо использовать всем одного пользователя
- либо сделать группу
- либо сделать группу и использовать ACL для гибкой настройки.
> Я пока придумал только дать на папку права допустим 770, в кач-ве владельца поставить нашего terminal user и включить пользователя www-data в группу terminal user.
Надо еще выставить корректный umask (почитай что это) иначе сервер будет создавать файлы и папки с правами rx без w для группы. То же касается и твоего пользователя.
Погугли по теме phpstorm builtin server POST - много информации про плохую поддержку встроенным в PhpStorm сервером метода POST. Скорее всего дело в этом.
>>44610
Дело было в шторме, через апач все корректно работает.
Ты вопрос то читал вообще?
>и не надо ничего собирать
Ага, симс легит. Просто отдал юзеру пару миллиардов JSON записей. Это ты имел ввиду?
Предварительно всё это завернув в массив. Который завернул в JSON. И закешировал запрос. А потом сохранил его в БД. Не проиндексировав. Или вообще создал новую БД под каждый запрос. Каеф.
Я тут с 1 треда и до сих пор не смог сделать задачу про айфон в кредит.
ОП мне стоит вообще продолжать пытаться в программирование?
какой альтернативный язык программирования посоветуешь? PHP пока сложноват для меня. Планирую начать с чего-то более фундаментального.
Что-то более фундаментальное - это машина Тьюринга, алгоритмы Маркова, Си, Scheme.
CS50 пройди для начала. Там даже для таких даунов как я было всё понятно.
реально? он де устарел давно. нам его в универе давали на 1 курсе 5 лет назад. он уже тогда был древним
Он может не подходить для некоторых сфер, но устарела в языке C++ только часть.
>нам его в универе давали
Вам его в универе давали в виде Си с классами версии 98 года.
>нам его в универе давали на 1 курсе 5 лет назад.
Это показатель какой-то? Или что? Ну вон пиши на расте тогда. Ему около года всего. Правда область применения мизерная и вакансий 15 на весь мир.
>PHP сложноват
>начать с чего-то более фундаментального
смотри, обычно фундаментальный = более сложный
Сложный в использовании но простой в понимании. Мне важно понимать то, что я использую.
т. другой анон
Всегда python как первый язык. С ним ты сможешь пощупать 90% программирования кроме серьёзной графики разве что
питон. но он не проще
Еще лучше если мы говорим о просто Си. Но 98 на мой взгляд - необходимое зло. Везде где юзаюся фичи 11 + стандартов разумнее использовать другой язык
С переносом данных из JSON в таблицы скорее всего будут сложности, так как никто к тому моменту не будет помнить схему JSON данных (какие в них есть поля и для чего) и придется все это мучительно выяснять анализом кода.
>>44724
До C++ надо выучить Си.
>>44720
В каком смысле фундаментального? Если тебе интересны низкоуровневые детали, то надо почитать как устроен процессор и учить ассемблер (только не учи древний 16-битный досовский - учи хотя бы 32-, а лучше 64-битный). Скорее всего, на ассемблере тебе писать ничего не придется, но ты будешь понимать, как программа выполняется на процессоре.
А затем можно переходить к Си. А потом к более высокоуровневым языкам.
Но это не проще PHP. Это будет сложнее. И потребует время. И зарабатывать этим ты вряд ли сможешь.
PHP по моему один из самых простых языков в освоении. Ну еще Питон есть, он может чуть проще. Можешь его попробовать учить.
>>44727
Машина Тьюринга - это модель для математических доказательств и в изучении программирования не поможет.
>>44730
Его используют там, где нужна высокая производительность, а также в десктопных программах с окошечками. Хром, Openoffice на нем написаны например.
Просьба ввести имя, потом возраст. После чего на экран выведется "Привет аноннейм, тебе 12 лет".
Разобрался вроде. Но может кто пояснить, что происходит если я ввожу не латиницу? Почему оно второй раз не просит ввода второй раз(возраст)? А после имени сразу вываливает последний echo с пустыми значениями в переменных $name и $age
Что происходит при вводе "нелатинницы" зависит от используемых ОС, настроек ОС и кодировки скрипта.
В линуксе и маке по умолчанию консоль передает программе и отображает на экране данные в кодировке utf-8. Если скрипт написан в utf-8, то он будет работать с любыми символами любых алфавитов. Если не в utf-8 - то надписи из скрипта будут выводиться криво. Подробнее
- https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
- совсем подробно, объясняя с нуля https://github.com/codedokode/pasta/blob/master/cs/strings.md
Если ты используешь винду, то придется страдать. Виндовая консоль в русской версии использует по умолчанию 8-битную кодировку cp1251, и значит ты должен либо писать скрипт в cp1251 (плохо, плюс не все функции ее будут поддерживать), либо кириллица не будет отображаться.
Винда + cygwin кстати иногда умеет отображать utf-8 в консоли.
Еще один вариант, если ты под виндой, то можно писать программу в utf-8, но конвертировать все вводимые и выводимые данные в/из cp1251.
Причем обрати внимание, что cp1251 используется в консоли только в русской версии винды. Если твою программу запустить на другой версии винды, то кирилица не будет отображаться.
А, я ошибся. В винде в консоли по умолчанию может еще быть cp866. Не знаю, от чего это зависит, есть консольная команда chcp для ее переключения. На utf-8 переключить нельзя.
Проверить кодировку можно, набрав например такую команду
php -r "echo chr(253); echo '\n';"
Она выводит символ с кодом 253. Затем взять в википедии таблицы кодировок cp866 и cp1251 и посмотреть в них символ с таким же кодом 253 и сделать вывод о кодировке.
Вспоминается в паскале было
read();
readln();
которые позволяли считывать пользовательский ввод, есть в пхп что-то аналогичное?
fgest возвращает строку с символом перевода строки (от нажатия enter).
Удалить его можно с помощью rtrim(), смотри мануал.
fgest(STDIN) это и есть что-то вроде read.
Сygwin и использую. Кстати, попробовал запустить на убунте - действительно с русским проблем нет. Но вопрос не в этом, я понимаю что с utf8 могут быть проблемы, вопрос в том, почему введя первый раз имя на русском оно не просит у меня ввести возраст, а сразу выводит последний echo? Т.е. пропускает заполнение переменной $age
Че там в 8й версии планируют запилить? Когда планируют выпустить?
Делаю запросы:
BEGIN
INSERT в 1 таблицу
получаю ->insert_id
INSERT в 2 таблицу SET last_base_id=$insert_id
COMMIT
Где-то раз в 100 тысяч таких срабатываний скриптов получается такое (при одновременной запущенных нескольких скриптов):
У меня в 1 и 2 таблице AUTO_INCREMENT стоит и должно записываться:
1 таблица:
id=999
id=1000
2 таблица:
id=999, last_base_id=999
id=1000, last_base_id=1000
Но вместо этого изредка получается во второй таблице:
id=999, last_base_id=1000
id=1000, last_base_id=999
Без транзакции в ->insert_id вообще какие-то левые данные.
MyISAM не поддерживает транзакции и BEGIN/COMMIT ничего не делают. И еще много чего не поддерживают. Погугли сравнение MyISAM с InnoDB.
https://wiki.php.net/rfc тут сморти планы, они не по 8 версии конечно. не кто не знает, сколько будет минорных у седьмой.
перевел таблицы на InnoDB и охуел с тормозов из-за транзакций. Использую транзакции чтоб вместо по-очередной вставки данных вставился сразу блок - какие-то ключи и картинка в другой таблице. Потом выбираю это все объединяя таблицы.
Тормозить стали почему-то и другие скрипты, где транзакциями и не пахнет и должны выполняться моментально.
В общем, надо как-то настраивать, но лень разбираться.
Эх, не быть мне программистом. Просто вернусь на старый тип таблиц и не буду использовать ->insert_id.
1) список владельцев с полями, по id животного
2) список животных с полями, по id владельца
3) информацию по владельцу(ам), по некоторой известной инфе о животном (клеймо, микрочип)
Лол, спасибо за идею с третьей таблицей связывающей. Это придаст моему проекту более понятный вид. Можно хоть тормознутые транзакции откинуть
Тоже жду ответов. Главное чтоб быстро выбирало крупные данные и без лишних полей.
Что бы входящий файл не был troyan_ot_vasyana.php например, и что бы злоумышленник потом пройдя по ссылке
tvoy.sait/upload/images/troyan_ot_vasyana.php не получил полный доступ к твоему сайту.
благодарю за ответ. я остановился на CMF ModX, думаю все получится.
в будущем конечно буду учить фреймворки.. это мне сейчас просто заказ подкинули спонтанно, ну и я взялся блин, без опыта :)
Часть функции из задачи на банк.
Сия функция должна принимать на вход три числа и переводить их в текст, но почему она глючит с цифрами типа, начинающимися на 0, типа 056 или 038. Указывает неправильные числа, например, вместо "пятьдесят шесть" пишет "сорок шесть"
Я по калькулятору проверял, всё должно быть верно.
Решил, что проблема в отсутствии сотен, решил сделать так https://ideone.com/6U4CQx
где если нет сотен, то он сразу брал номер, не отбрасывая первую цифру, но такой номер он не видит в массиве и выдавал ошибки.
Однако в конечном варианте задачи ещё не до конца готовым https://ideone.com/hDcpnO
такой ошибки нет.
Вот ещё более конечный, но не готовый вариант.
https://ideone.com/aMgtBb
С женским родом слова 1 тысяча я ничего лучше не придумал.
Я тут погуглил, наверное самое эффективное решение это выдавать ссылки на файл в публичной папке, а в этой папке отключить обработку скриптов. Я изначально хотел сделать папку не публичной, на практике это будет не слишком хорошо работать даже с каким-то йоба заголовком x-sendfile или еще хуже считыванием прямо пхпхой в озу.
У меня есть один вопрос к анонам. Каким образом в реальном мире производятся фоновые задачи? По наводке из статьи опа прочитал про gearman, мало что понял, есть еще какой-то крон. Вот как например ютуб конвертирует видео? Я загружаю видео на сайт, где-то внутри логика запускает эту фоновую задачу конвертации(представим что это консольная команда ffmpeg), она каким-то образом еще отдает ответ логике о прогрессе. Может создается какая-то временная запись в бд о файле и статус типа обрабатывается, завершил обратку этц. В общем сложна.
И еще есть один подводный камень с джепегом и внедренным внутрь пхп. Если я буду в превьюхе указывать сорс на оригинальную картинку, то будет ли выполняться пхп код? Я тестил на рандомном файлообменнике, там везде, даже в микро превьюшках 15x15 сохраняется пхп код, то есть чуваки не чистят метаданные, и у них ничего не ломается. Ргост кстати отказывается грузить такую картинку вообще, лол.
а ты думал тебе сразу через неделю предложат работу 100к в месяц и 3 гладковыбритые бляди на выбор?
дальше все экспоненциально сложнее
Привет, анон.
Где-нибудь написано за куки? Нужны ли они? Я думал в куки передаются данные откуда перешел человек и всё такое, а в мануалах везде передают одну и ту же хуйню в виде простой строки
Я сделал уже почти
Почему при цифре 02020200 он выводит: "На вашем счету пятьсот тридцать две тысячи шестьсот восемь рублей
(532608)"?
Откуда это взялось, как?
Если добавить amount8, то он вообще его пропускает.
Почему он так реагирует на цифры с нулём в начале?
>Машина Тьюринга - это модель для математических доказательств и в изучении программирования не поможет.
Описание машины Тьюринга - это самый элементарный язык. Тебе не поможет, зато мне помог.
>Почему он так реагирует на цифры с нулём в начале?
Это у меня проблемы или компилятор глючит?
https://ideone.com/QljIj0
Я везде, где только можно добавил условие if != 0, поэтому он просто должен подобные пропускать.
Или он числа с 0 в начале воспринимает, как десятые части? https://ideone.com/Lh0Ch5
Немного про куки есть в уроке по HTTP: https://github.com/codedokode/pasta/blob/master/network/http.md#Куки (возможно, придется еще прочесть информацию выше).
Кука это просто текстовая строка, которую сервер может сохранить в браузере и получать вместе с следующими запросами на этот сервер в виде заголовков.
Учите алгоритмы, господа, теорию программирования. Тогда язык станет просто инструментом, где важно просто знать синтаксис и какие-нибудь специфические особенности.
Не, это я знаю. Я имею ввиду можно ли примеры как например с помощью куки запоминаются пароли, действия на сайте, подгрузка видосов, картинок, сохранение действий. Как это всё делается
http2 это же просто протокол, какое отношение он имеет к php?
Но я очевидно не об этом
Короче подумал что мой вариант это простая фабрика, которой передается тип/название класса, и она с помощью кейсов создает и возвращает что нужно. Потом у какого-то индуса почитал что так делать нельзя и это нарушает какой-то там йоба принцип, можно только расширять сущности, изменять их не стоит. Мол в будущем я захочу новых типов, полезу дополнять кейс и ВСЁ СЛОМАЕТСЯ. Альтернативой он предложил ФакториМетод, где каждый кейс это отдельный класс. Но мою проблему это не решает, теперь мне придется пилить кейсы сразу в каком-то контроллере, и вызывать нужные классы. Или я тупой и ничего не понял, или это всё говно из жопы. жопа горит
Ваще эти паторны хуита какая то узкоспецилазированная, тебе нужно сделать йобу, а они тебя сука ограничивают, шо нихуя не получается. Походу вообще хуй надо на них забить.
Начинаю себе голову какой-то фигней забивать о том, что вот если бы у нас был очень большой мир с очень большим количеством объектов, то например будут такие проблемы:
Допустим животные хранят в себе своё положение в мире. Стало быть нельзя просто взять и спросить у мира кто рядом с нами? (а было бы удобно просто спросить кто стоит в радиусе 4х клеток от x,y через простой вложенный цикл например), и придется для этого все объекты опрашивать, на предмет их координат, что бы понять о том, где они и не находится ли кто-то из них рядом с нашей текущей мшкой/кошкой.
Кароче у меня прям бомбит от своей тупости и не понимания того что делать тут. Как просто и по полочкам съехать в это примитивное казалось бы ООП с самыми что ни на есть кошечками и собачками :(
Этоn тред еще живой?
Есть вот такой говнокод: https://pastebin.com/UwKriche
Посоветуйте, как мне лучше его переписать, чтобы он выглядел более менее разборчивым? Может как-то разобрать всё в разные функции? Как это делать, и как понять, когда нужно переносить код в функцию, а когда оставить как есть? Особо сильно не вижу смысла создавать дохуя функций однострочников, так ведь только больше места уходит. Если не прав, переубедите меня.
Где вообще читать об этом?
Еще мне порой очень сильно не хватает фантазии на то, чтобы придумать название переменной. Это уже проблемы из-за того, что пишу говнокод?
Вообще, желал бы перейти на функциональный и процедурный код. Отговорите меня, или наоборот, убедите использовать всего сразу, но по чуть-чуть и только в подходящих местах. Где?
В этом проекте использую Slim и Doctrine.
$huita_name |=$default_value
В общем мне нужно, что если $huit_name - определена, то нихуя не делать, а если не определена взять значение default_value. Спс, аноны.
Посоветуйте, пожалуйста, хороший видеокурс для начинающего, который можно было бы стянуть с торрентов. На английском или русском - без разницы. В PHP я полный ноль, но имеются некоторые знания в сфере HTML/CSS/JS.
Я твоего вопроса тоже не понял. Что у тебя там не так то? Ожидал увидеть тупую стену текста, но увидел класс для незнакомого фреймворка. Или знакомого?
бесконечные $this->ci как бе намекают на codeigniter, но в общем хз что у тебя за мешанина там.
Ты в коде как используешь его?
$test= new ImageUpdate($ci);
$test->command();
как-то так и на этом всё?
Ты можешь пояснить что в итоге твои 2 метода конкретно делают?
И зачем ты хочешь их оптимизировать? Если это до тебя писали и просто работает - проще ведь не лезть.
Если дали таск оптимизировать чужой код, что бы учился и разбирался, то хз.
Можешь попробовать например разбить на 2 функции это дело.
Первая будет искать какой-то там твой $diff и складывать его в
$this->diff в самом объекте.
А в другой метод запихнуть то, что у тебя внитри форича дергается. Что это этому методу передавать этот самый $diff уже, или даже лучше каждый отдельный элемент.
а комманд например переписать уже так:
{
$this->diff = $this->addImages();
foreach ($this->diff as $image) {
$image->doSomethingWithImage();
}
...
//аналогично для самбнейлов
}
Можешь еще сделать так, что бы у тебя не всё подряд printf'алось, а только ошибки. Поле под это дело добавить, которое будешь в конструктор передавать или прямо в коде править когда надо дампить или не дампить, или вообще что бы оно из конфига сайта на этапе конструктора класса подсасывалось
Могу полный бред писать, сам полунубас, не воспринимай меня как гуру но с аналогичным говнокодом на другом фреймворке работал, прост сижу маюсь не могу вот задачи начать решать оповские, где нужно разобраться в том, как с 0 нахуярить микрофреймворк и на нем писать студентов и прочее уже :(
Я твоего вопроса тоже не понял. Что у тебя там не так то? Ожидал увидеть тупую стену текста, но увидел класс для незнакомого фреймворка. Или знакомого?
бесконечные $this->ci как бе намекают на codeigniter, но в общем хз что у тебя за мешанина там.
Ты в коде как используешь его?
$test= new ImageUpdate($ci);
$test->command();
как-то так и на этом всё?
Ты можешь пояснить что в итоге твои 2 метода конкретно делают?
И зачем ты хочешь их оптимизировать? Если это до тебя писали и просто работает - проще ведь не лезть.
Если дали таск оптимизировать чужой код, что бы учился и разбирался, то хз.
Можешь попробовать например разбить на 2 функции это дело.
Первая будет искать какой-то там твой $diff и складывать его в
$this->diff в самом объекте.
А в другой метод запихнуть то, что у тебя внитри форича дергается. Что это этому методу передавать этот самый $diff уже, или даже лучше каждый отдельный элемент.
а комманд например переписать уже так:
{
$this->diff = $this->addImages();
foreach ($this->diff as $image) {
$image->doSomethingWithImage();
}
...
//аналогично для самбнейлов
}
Можешь еще сделать так, что бы у тебя не всё подряд printf'алось, а только ошибки. Поле под это дело добавить, которое будешь в конструктор передавать или прямо в коде править когда надо дампить или не дампить, или вообще что бы оно из конфига сайта на этапе конструктора класса подсасывалось
Могу полный бред писать, сам полунубас, не воспринимай меня как гуру но с аналогичным говнокодом на другом фреймворке работал, прост сижу маюсь не могу вот задачи начать решать оповские, где нужно разобраться в том, как с 0 нахуярить микрофреймворк и на нем писать студентов и прочее уже :(
Фреймворк использую Slim, точнее микрофреймворк.
Конкретно этот код мой.
$this->ci это Container Interface, который подхватывается при совпадении правила route и выполнении функции в Slim. В этой функции находятся много связанного с самим фреймворком.
>Если дали таск оптимизировать чужой код, что бы учился и разбирался, то хз.
Нет, это я исключительно со своим вожусь, страдаю перфекционизмом. Всё никак не могу остановится на одном варианте, постоянно не устраивает.
>Ты можешь пояснить что в итоге твои 2 метода конкретно делают?
Вообще, забыл, что всё это действительно выглядит очень странно, без объяснения. Этот класс у меня запускается из командной строки, сделано так чтобы вызывалось из крона.
Рекурсивно ищет изображения в директорих, берёт местанахождение, sha512 файоа и заполняет эту информацию в базу данных, с помощью Doctrine, попутно генерирует для всех этих изображений превьюшки в заданных размерах через imagemagick.
Вот еще есть вот такой вариант https://pastebin.com/ceAYHjZ3 , но я не знаю, лучше ли он, чем то, что было до этого. Пытался в функциональное программирование. Как видно, выжимал из функций array_* максимум, что они могут. Почему мне кажется, что это крайне плохая затея, программировать так в классах, и тем более в PHP. От того и захотелось переписать всё это на процедурный код. Сейчас пытаюсь вернуться к здравому смыслу и обратился ИТТ.
У него вроде за 2017 уже давно есть или хз за какой но поновее 2015. Самые годные уроки
Четыре скалярных типа:
boolean
integer
float (число с плавающей точкой, также известное как double)
string
Я тут недавно немного боли с int integer в php7 принял. Конечно, мне нужно лучше знать язык, но хотелось бы какой-нибудь последовательности.
Вот чочешь ты например написать для PHP функцию для своего сайта. Например сгенерировать новую 3d модель голой бабы. А в PHP такой функции нет. Вот тут на помощь приходить CGI, пишешь на другом языке это вот всё и потом к PHP подключаешь это всё. Вот это называется CGI.
Гуглил?
https://ru.wikipedia.org/wiki/CGI
http://lectureswww.readthedocs.io/5.web.server/cgi.html
CGI это что-то вроде набора правил, которые определяют, как веб-сервер может вызывать внешнюю программу для обработки HTTP-запроса.
Если тебе не знакомы понятия "веб-сервер" или "HTTP запрос", прочти введение тут https://github.com/codedokode/pasta/blob/master/network/http.md
В unix/linux часто используется принцип разделения ответственности, когда каждая программа отвечает за свою часть работы. В соответствие с этим принципом, веб-сервер (nginx, apache итд) занимается только взаимодействием с клиентом по протоколу HTTP и отдачей статических файлов. Он не умеет при поступлении запроса загружать и выполнять программы на каких-то языках программирования. А это часто необходимо - когда мы хотим, чтобы страницы генерировались бы на "лету", динамически.
Для решения этой проблемы и придуман CGI - набор правил, позволяющих серверу вызывать внешнюю программу на любом языке программирования для обработки запроса. Например, любой веб-сервер, поддерживающий CGI, может таким образом запускать PHP-скрипт при поступлении запроса от пользователя.
Можно настроить веб-сервер так, чтобы он при определенных запросах запускал бы внешнюю программу, а то, что она выведет, отдавал бы назад клиенту в качестве ответа на запрос. CGI и есть набор правил, в которых определено, как веб-сервер передает программе информацию о запросе, и как программа может передавать данные веб-серверу. как они взаимодействуют.
CGI, если ты почитаешь, очень простой и не требует каких-то специальных библиотек. Можно использовать хоть скрипт на bash из 5 строчек, а также, разумеется, программу на любом другом языке программирования. Это его плюс. Ну например, можно сделать bash скрипт, выводящий количество свободного места на дисках, и настроить сервер так, чтобы при заходе на определенную страницу показывалась бы эта информация.
Вот пример такого скрипта (работает только под Мак и Линукс), допустим с именем /var/www/disks.sh:
#!/bin/bash
echo "Content-Type: text\plain; charset=utf-8"
echo
df # выводит информацию о дисках
В линуксе bash-скрипты являются исполняемыми программами и их можно запускать напрямую.
Вот пример части конфига, который указывает Апачу (он поддерживает CGI) запускать этот скрипт при обращении по URL http://127.0.0.1/disks :
LoadModule cgid_module modules/mod_cgid.so
ScriptAlias /disks /var/www/disks.sh
Как видим, добавив всего несколько строчек, мы можем смотреть результат выполнения команды df через браузер. Этот пример показывает, насколько прост CGI.
Мануал
- http://httpd.apache.org/docs/current/howto/cgi.html
- https://httpd.apache.org/docs/trunk/mod/mod_alias.html#scriptalias
PHP поддерживает взаимодействие с сервером в соответствие с спецификацией CGI.
Минус в том, что запускать внешнюю программу на каждый запрос довольно неэффективно, так как основное время может уходить на запуск/завершение программы, а не на выполнение полезной работы. Потому для нагруженных серверов придуманы новые интефейсы вроде FastCGI где программа запускается один раз и может обработать много запросов от веб-сервера не завершаясь. PHP поддерживает FastCGI с помощью php-fpm.
Ну и другое, не такое удчаное решение - это mod_php, PHP может работать внутрни процесса apache, взаимодействуя с ним через внутренние API Апача.
Веб-сервер nginx не поддерживает CGI, а только FastCGI. Для запуска CGI программ из-под него нужно использовать вспомогательную программу вроде https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/ которая будет принимать FastCGI запросы и запускать внешние программы через CGI.
Гуглил?
https://ru.wikipedia.org/wiki/CGI
http://lectureswww.readthedocs.io/5.web.server/cgi.html
CGI это что-то вроде набора правил, которые определяют, как веб-сервер может вызывать внешнюю программу для обработки HTTP-запроса.
Если тебе не знакомы понятия "веб-сервер" или "HTTP запрос", прочти введение тут https://github.com/codedokode/pasta/blob/master/network/http.md
В unix/linux часто используется принцип разделения ответственности, когда каждая программа отвечает за свою часть работы. В соответствие с этим принципом, веб-сервер (nginx, apache итд) занимается только взаимодействием с клиентом по протоколу HTTP и отдачей статических файлов. Он не умеет при поступлении запроса загружать и выполнять программы на каких-то языках программирования. А это часто необходимо - когда мы хотим, чтобы страницы генерировались бы на "лету", динамически.
Для решения этой проблемы и придуман CGI - набор правил, позволяющих серверу вызывать внешнюю программу на любом языке программирования для обработки запроса. Например, любой веб-сервер, поддерживающий CGI, может таким образом запускать PHP-скрипт при поступлении запроса от пользователя.
Можно настроить веб-сервер так, чтобы он при определенных запросах запускал бы внешнюю программу, а то, что она выведет, отдавал бы назад клиенту в качестве ответа на запрос. CGI и есть набор правил, в которых определено, как веб-сервер передает программе информацию о запросе, и как программа может передавать данные веб-серверу. как они взаимодействуют.
CGI, если ты почитаешь, очень простой и не требует каких-то специальных библиотек. Можно использовать хоть скрипт на bash из 5 строчек, а также, разумеется, программу на любом другом языке программирования. Это его плюс. Ну например, можно сделать bash скрипт, выводящий количество свободного места на дисках, и настроить сервер так, чтобы при заходе на определенную страницу показывалась бы эта информация.
Вот пример такого скрипта (работает только под Мак и Линукс), допустим с именем /var/www/disks.sh:
#!/bin/bash
echo "Content-Type: text\plain; charset=utf-8"
echo
df # выводит информацию о дисках
В линуксе bash-скрипты являются исполняемыми программами и их можно запускать напрямую.
Вот пример части конфига, который указывает Апачу (он поддерживает CGI) запускать этот скрипт при обращении по URL http://127.0.0.1/disks :
LoadModule cgid_module modules/mod_cgid.so
ScriptAlias /disks /var/www/disks.sh
Как видим, добавив всего несколько строчек, мы можем смотреть результат выполнения команды df через браузер. Этот пример показывает, насколько прост CGI.
Мануал
- http://httpd.apache.org/docs/current/howto/cgi.html
- https://httpd.apache.org/docs/trunk/mod/mod_alias.html#scriptalias
PHP поддерживает взаимодействие с сервером в соответствие с спецификацией CGI.
Минус в том, что запускать внешнюю программу на каждый запрос довольно неэффективно, так как основное время может уходить на запуск/завершение программы, а не на выполнение полезной работы. Потому для нагруженных серверов придуманы новые интефейсы вроде FastCGI где программа запускается один раз и может обработать много запросов от веб-сервера не завершаясь. PHP поддерживает FastCGI с помощью php-fpm.
Ну и другое, не такое удчаное решение - это mod_php, PHP может работать внутрни процесса apache, взаимодействуя с ним через внутренние API Апача.
Веб-сервер nginx не поддерживает CGI, а только FastCGI. Для запуска CGI программ из-под него нужно использовать вспомогательную программу вроде https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/ которая будет принимать FastCGI запросы и запускать внешние программы через CGI.
Нет. CGI это протокол взаимодействия между веб-сервером и внешней программой-обработчиком, а не между PHP и внешней программой.
Что значит "получить инфу от CGI"? CGI это правила взаимодействия двух программ, от самого CGI получить ничего нельзя, можно только с использованием правил CGI вызвать другую программу и получить что-то от нее.
Великовозрастное быдло?
Тоже поймал себя на мысле, что все современные новшества - это хуита без содержания.
Сидишь, пытаешься понять, читаешь доку - где же потаенный смысл? В итоге оказывается, что ты ожидал от какойто хуйни больше, чем она есть на самом деле. Зато пафоса нагоняют яебу, термины придумывают и пр. Причем специально преподносят инфу об этом в таком сложном виде, чтобы создать иллюзию, что они знают что-то мега сложное
Мне расписали так, что это на выходе - роутер.
хттп адрес вызывает программу, которая генерирует мне страницу, что не так?
>хттп адрес вызывает программу, которая генерирует мне страницу, что не так?
Всё не так. Перечитывай.
Перечитал
>Можно настроить веб-сервер так, чтобы он при определенных запросах запускал бы внешнюю программу, а то, что она выведет, отдавал бы назад клиенту в качестве ответа на запрос
Везде так написано. CGI - это запрос, который возвращает результат работы программы
Роутер - запросы роутит
Ты пишешь ему hui\pizda\igor а он тебе по заросу страницу скидывает
А CGI тебе делеает внутренние расчёты на компе, внешней прогой. Тоесть тут тоже запрос идёт, но это не роут блядь запрос. Это запрос к программе, который тоже через роутер можно сделать. Как вообще эти вещи перепутать можно, я не понимаю?
Роутер также. Делаю запрос, внешняя программа на пхп делает внутренние расчеты и отдает результат
Я не виноват, что тебя трисет, гуманитарий. Хочешь общаться и не рваться - научись излагать мысли исчерпывающе.
http://www.php.su/learnphp/cgi/?interface
>Подобным образом можно передавать и html-документы, в таком случае они могут формироваться программой динамически и передаваться браузерам пользователей в ответ на их запросы.
Нахуй ты вообще в треде вопросы задеёшь дебил? Если тебе 5 раз сказали нет, это не роутер, а у тебя всё равно один роутер блядь на уме. Ну и иди нахуй тошда со своим роутером, еблана кусок. Не еби людям мозг. Всё равно ты необучаемый и тупой как полено. Выучил одно слово и теперь считаешь что это всё роутер. Тебе написали что нет, всё равно пытаешься что-то там доказать, зачем только непонятно.
В треде все тебя одманывают анон. Это всё на самом деле роутер. И весь PHP - это роутер. И JS это роутер. Даже CSS это роутер. Ты раскусил заговор против тебя. Не оборачивайся.
Если это не роутер, тогда зачем ты и другие источники, поясняя за cgi, дают определение роутера?
1. Роутер (PHP)
2. Роутер (HTML5)
3. Роутер (TP-LINK TL-WR841N)
?
Тише. Понимаю, хотел умное спиздануть и обосрался принародно, мой совет - не бегай роняя кал, тихонько ретируйся потом подучишь, может столкнешься на практике и второй раз может получиться не обосраться
>CGI является одним из наиболее распространённых средств создания динамических сайтов.
это же совсем разные вещи, верно?
Потому что ты изобретаешь колесо. Есть тысячи библиотек для работы с DOM'ом, используя которые шанс ошибиться намного меньше, чем при попытке написать регексп.
>>46629
Ну смотри. Веб-сервер возвращает статичный контент. Нужна динамика? Дергай скрипт. Как дёрнуть скрипт? Через cgi. Вот и всё. Хотя в той же джаве не или го нет такого разделения на веб-сервер/прикладной код, но мы же тут за пехапе общаемся.
Стоит ли для вкатывания в php начинать проходит курс от И.О.Борисова?
Каков он как преподаватель или преподаёт ли он нужную информацию для изучения?
Повторю еще раз. Когда ты переходишь по какой-то ссылке или вводишь адрес в браузер, браузер как HTTP-клиент связывается в HTTP-сервером и отправляет ему HTTP-запрос. По умолчанию сервер просто в ответ на запрос отдает файл с диска. Это может быть HTML-страница, картинка или что-то еще. Но такой подход позволяет отдавать только статические, то есть неизменные страницы. А часто требуется генерировать страницы динамически с помощью программы на каком-то языке.
Сам веб-сервер не умеет выполнять программы, потому были придуманы интерфейсы/протоколы (правила взаимодействия) веб-сервера с внешними программами - CGI и позже FastCGI. В конфиге веб-сервера мы настраиваем, какую программу и в каком случае надо вызывать.
CGI очень простой и понятный, но медленный - на каждый запрос программа запускается заново. На реальных сайтах используют FastCGI - в этом случае мы запускаем отдельно веб-сервер, отдельно FastCGI процесс, и затем веб-сервер начинает передавать этому процессу запросы, которые тот обрабатывает по очереди, не перезапускаясь. В случае языка PHP, программа php-fpm принимает от веб-сервера FastCGI запросы на выполнение PHP скриптов, выполняет их и возвращает серверу результат выполнения скрипта. То есть веб-сервер "просит" php-fpm выполнить PHP-скрипт, тот выполняет его и передает веб-серверу результат выполнения (что вывел скрипт с помощью echo, какие заголовки выставил с помощью header).
Эти протоколы (как CGI, так и fastCGI) позволяют веб-серверу взаимодействовать с программами на любом языке программирования. Веб-сервер не привязан к какому-то одному языку. Веб-серверу не надо "знать", как выполнить ту или иную программу. Также, они добавляют надежности - если во внешней программе (в интерпретаторе PHP например) произойдет ошибка, и она аварийно завершится, процесс веб-сервера это не заденет и он продолжит работать.
Также, важно то, что CGI-программа не привязана к какому-то конкретному веб-серверу - его можно заменить на другой и все должно работать так же, как и раньше.
Насчет роутера - "роутером" обычно называют часть приложения, которая занимается разбором запроса. То есть это функция, которая получает на вход URL и на выходе дает например название контроллера, который надо выполнить. CGI это не функция, а протокол (набор правил) и уже поэтому нельзя говорить, что "CGI это роутер". Тем более, CGI не занимается вообще разбором URL. Это набор правил, который говорит о том, как веб-севрер передает внешней программе информацию о запросе (через переменные окружения и поток stdin) и как программа возвращает заголовки и тело HTTP-ответа. Почитайте спецификацию CGI, например https://tools.ietf.org/html/rfc3875 (увы, на русском адекватного перевода не нашел) и найдите там что-то похожее на роутер.
>>46629
> CGI является одним из наиболее распространённых средств создания динамических сайтов.
Это не точно. Во-первых, CGI сам по себе не позволяет создавать никакие сайты, а лишь позволяет веб-серверу вызвать внешнюю программу в случае поступления HTTP-запроса. Потому называть его "средством создания сайтов" неправильно. Во-вторых, как я писал выше, он простой, но медленный и сейчас используют FastCGI.
>>46645
> Хотя в той же джаве не или го нет такого разделения на веб-сервер/прикладной код
Они просто общаются с веб-сервером по HTTP вместо CGI/FastCGI. В сравнении с CGI это усложняет приложение (ты вряд ли напишешь полноценный HTTP сервер на bash, а с CGI можно работать хоть из bash скрипта), приводит к дублированию функционала (разбором HTTP мог бы заниматься только веб-сервер). Есть конечно и плюсы - они могут работать как-то ограниченно даже без веб-сервера.
Повторю еще раз. Когда ты переходишь по какой-то ссылке или вводишь адрес в браузер, браузер как HTTP-клиент связывается в HTTP-сервером и отправляет ему HTTP-запрос. По умолчанию сервер просто в ответ на запрос отдает файл с диска. Это может быть HTML-страница, картинка или что-то еще. Но такой подход позволяет отдавать только статические, то есть неизменные страницы. А часто требуется генерировать страницы динамически с помощью программы на каком-то языке.
Сам веб-сервер не умеет выполнять программы, потому были придуманы интерфейсы/протоколы (правила взаимодействия) веб-сервера с внешними программами - CGI и позже FastCGI. В конфиге веб-сервера мы настраиваем, какую программу и в каком случае надо вызывать.
CGI очень простой и понятный, но медленный - на каждый запрос программа запускается заново. На реальных сайтах используют FastCGI - в этом случае мы запускаем отдельно веб-сервер, отдельно FastCGI процесс, и затем веб-сервер начинает передавать этому процессу запросы, которые тот обрабатывает по очереди, не перезапускаясь. В случае языка PHP, программа php-fpm принимает от веб-сервера FastCGI запросы на выполнение PHP скриптов, выполняет их и возвращает серверу результат выполнения скрипта. То есть веб-сервер "просит" php-fpm выполнить PHP-скрипт, тот выполняет его и передает веб-серверу результат выполнения (что вывел скрипт с помощью echo, какие заголовки выставил с помощью header).
Эти протоколы (как CGI, так и fastCGI) позволяют веб-серверу взаимодействовать с программами на любом языке программирования. Веб-сервер не привязан к какому-то одному языку. Веб-серверу не надо "знать", как выполнить ту или иную программу. Также, они добавляют надежности - если во внешней программе (в интерпретаторе PHP например) произойдет ошибка, и она аварийно завершится, процесс веб-сервера это не заденет и он продолжит работать.
Также, важно то, что CGI-программа не привязана к какому-то конкретному веб-серверу - его можно заменить на другой и все должно работать так же, как и раньше.
Насчет роутера - "роутером" обычно называют часть приложения, которая занимается разбором запроса. То есть это функция, которая получает на вход URL и на выходе дает например название контроллера, который надо выполнить. CGI это не функция, а протокол (набор правил) и уже поэтому нельзя говорить, что "CGI это роутер". Тем более, CGI не занимается вообще разбором URL. Это набор правил, который говорит о том, как веб-севрер передает внешней программе информацию о запросе (через переменные окружения и поток stdin) и как программа возвращает заголовки и тело HTTP-ответа. Почитайте спецификацию CGI, например https://tools.ietf.org/html/rfc3875 (увы, на русском адекватного перевода не нашел) и найдите там что-то похожее на роутер.
>>46629
> CGI является одним из наиболее распространённых средств создания динамических сайтов.
Это не точно. Во-первых, CGI сам по себе не позволяет создавать никакие сайты, а лишь позволяет веб-серверу вызвать внешнюю программу в случае поступления HTTP-запроса. Потому называть его "средством создания сайтов" неправильно. Во-вторых, как я писал выше, он простой, но медленный и сейчас используют FastCGI.
>>46645
> Хотя в той же джаве не или го нет такого разделения на веб-сервер/прикладной код
Они просто общаются с веб-сервером по HTTP вместо CGI/FastCGI. В сравнении с CGI это усложняет приложение (ты вряд ли напишешь полноценный HTTP сервер на bash, а с CGI можно работать хоть из bash скрипта), приводит к дублированию функционала (разбором HTTP мог бы заниматься только веб-сервер). Есть конечно и плюсы - они могут работать как-то ограниченно даже без веб-сервера.
Неудобно.
>>46593
Не надо так писать. Иди самоутверждайся в каком-то другом треде или просто пройди мимо.
>>46603
Это надо спрашивать у этих источников, а не у нас.
>>46588
В той статье (по ощущениям, она старая или это перевод очень старой статьи) в самом начале ведь написано:
> Термин CGI ... обозначает набор соглашений...
Тут же черным по синему написано: CGI - это набор соглашений. А роутер это часть программы, функция или класс.
>>Подобным образом можно передавать и html-документы,
А роутер-то тут при чем? Роутер не занимается передачей HTML-документов, а лишь разбором URL.
По статье - неточность:
> Фактически, до недавнего времени все Web-программирование представляло собой программирование CGI-приложений
"до недавнего времени" - где-то до 2000 года, так как спецификация FastCGI появилась в 1996.
>>46572
CGI - это не "запрос", а набор правил о том, как веб-сервер взаимодействует с внешней программой, как передает ей данные и что она возвращает ему.
>>46583
Если не можешь спокойно объяснить, то лучше не объяснять вообще.
>>46558
> хттп адрес вызывает программу,
Не так. Веб-сервер при поступлении HTTP-запроса страницы с определенным URL может вызвать внешнюю программу с использованием соглашения CGI, если в его настройках так указано.
"хттп адрес" (URL видимо) это просто строка, и она ничего не может вызвать.
Неудобно.
>>46593
Не надо так писать. Иди самоутверждайся в каком-то другом треде или просто пройди мимо.
>>46603
Это надо спрашивать у этих источников, а не у нас.
>>46588
В той статье (по ощущениям, она старая или это перевод очень старой статьи) в самом начале ведь написано:
> Термин CGI ... обозначает набор соглашений...
Тут же черным по синему написано: CGI - это набор соглашений. А роутер это часть программы, функция или класс.
>>Подобным образом можно передавать и html-документы,
А роутер-то тут при чем? Роутер не занимается передачей HTML-документов, а лишь разбором URL.
По статье - неточность:
> Фактически, до недавнего времени все Web-программирование представляло собой программирование CGI-приложений
"до недавнего времени" - где-то до 2000 года, так как спецификация FastCGI появилась в 1996.
>>46572
CGI - это не "запрос", а набор правил о том, как веб-сервер взаимодействует с внешней программой, как передает ей данные и что она возвращает ему.
>>46583
Если не можешь спокойно объяснить, то лучше не объяснять вообще.
>>46558
> хттп адрес вызывает программу,
Не так. Веб-сервер при поступлении HTTP-запроса страницы с определенным URL может вызвать внешнюю программу с использованием соглашения CGI, если в его настройках так указано.
"хттп адрес" (URL видимо) это просто строка, и она ничего не может вызвать.
Вы просто не так понимаете. Вы прочли "фабрика может использоваться для создания объектов" и думаете, что "в 2018" все объекты принято создавать через фабрики. Нет, где это написано? Не надо использовать паттерны просто, чтобы они были.
Паттерны (могу ошибаться) начал собирать Фаулер. Он работал с самым разным кодом, и выделил какие-то типичные решения, которые часто встречались. Дал им названия, определения, описал их в книге. Иногда одну задачу можно было решить несколькими способами (например, наследование таблиц). Если у вас нет книги, то краткое описание паттернов есть на его сайте: https://martinfowler.com/eaaCatalog/ Там, кстати, нет Фабрики или Синглтона (которые вы изучаете, так как они вам кажутся самыми простыми). Зато есть Контроллер Страницы (тот самый, из MVC), паттерны наследования таблиц, паттерны взаимодействия с БД. Почитайте, полистайте. У меня как-то язык не повернется сказать, что описанное там "нигде не нужно" - я это видел много раз, а если вы будете разбирать Симфони, там половина этих паттернов встретится.
И кстати, книга вышла в 2003. Довольно давно.
>>46312
В PHP double и float это синонимы. В других языках, вроде Си, это 2 разных способа хранения чисел с плавающей точкой (в Си double занимает 8 байт, а float 4 байта, но первый хранит больше знаков после запятой и представляет более широкий диапазон значений).
> class ImageUpdate
Название класса - это существительное, хотя бы ImageUpdater, "обновлятель картинок" (есть впрочем мнение, что вредно называть классы с суффиксом -er).
> class ImageUpdate extends Container
Здесь ошибка, непонимание наследования. Вот я даже в своем учебнике пытался описать ( http://phpbooktest.ga/l1/pasta.html )
> Наследование позволяет создать новый класс не с нуля, а расширив уже существующий.
> Нельзя наследовать что угодно от чего угодно. Наследование должно применяться только для однотипных сущностей. Например, класс Банк можно унаследовать от класса Организация (так как банк - это вид организации), а вот унаследовать класс Работник от Организации нельзя. Также, нельзя унаследовать Организацию от Банка, так как Организация - это более широкое понятие.
"А наследуется от B" - это значит "А является B". Это значит, объект класса B можно использовать в коде вместо A (принцип замещения Лисков).
Обновлятель Картинок не является улучшенной версией DI Контейнера. Никто в здравом уме не будет передавать его туда, где нужен Контейнер. Он выполняет совсем другие задачи. Наследование тут неприменимо.
Также, ты нарушил принцип единственности ответственности (каждый класс выполняет свою задачу) - у тебя класс ImageUpdate занимается и сбором картинок, и выполняет роль DI контейнера.
Кстати, это типичная ошибка, я такое во многих CMS видел, люди просто не понимают ООП.
Хотя, я могу ошибиться, так как из куска кода неясно, что такое Container. Тем более что некий ci у тебя еще и передается в конструктор.
Дальше, в конструктор ты передаешь DI Container - но DI делается не так. Прочитай мой урок про DI, лень тут пересказывать все: https://github.com/codedokode/pasta/blob/master/arch/di.md . В конструктор передаются сами зависимости, а не контейнер.
> $images = $this->repo->findAll();
Это будет хорошо работать только до нескольких тысяч записей, а потом скрипт начнет есть много памяти и медленно работать.
> $files = Files::find($this->imageRoot, $this->ignore, $this->imageExts);
Название класса Files неудачное. Что, его объект представляет набор файлов? Нет, это просто Utility class со статическими методами и логично было назвать его FileUtil или FileHelper.
Список расширений наверно незачем делать задаваемым извне параметром - у тебя ведь код поддерживает только определнные расширения и логично их тут же жестко и прописать. В какой ситуации тебе понадобится менять этот параметр?
> foreach ($images as $image) array_push($list, $image->getImage());
Надо писать в 3 строки со скобками. Глянь PSR-1 и PSR-2, они есть и в переводе. Или пропусти код через phpformatter.com.
> $image->getImage()
Метод называется getImage но возвращает, судя по всему, не картинку, а путь к ней. Ну так и сделай соответствующее название.
> if ($dup = $this->repo->findOneBy(['sha512' => $sha512Hash])) {
Если ты загрузил все файлы в память выгоднее сделать "индекс" в виде массива и искать по ключу в нем - это в разы быстрее, чем слать запрос в БД.
> $this->ci->em->persist($image);
> $this->ci->em->flush();
Вообще, не выгодно делать flush после каждого файла, выгоднее собрать побольше сущностей и разом их записать в БД.
> $this->ci->em->clear();
А это вообще не логично. Ты понимаешь, что делает эта команда?
> exec(sprintf("convert -thumbnail
Это довольно невыгодно, запускать внешнюю программу на каждую картинку. Выгоднее использовать расширение imagick или gd.
Также, ты плохо сделал запуск внешней программы. Она может вывести что-то, вернуть ненулевой код возврата, даже зависнуть - у тебя это никак не проверяется. А это значит, что ты не обнаружишь ошибку сразу, а потом обнаружишь битую или отсутствующую превьюшку и потратишь кучу времени на выяснение, откуда она взялась.
> ob_flush();
Зачем они там в каждой строке?
> foreach (["medium" => "1000x1000", "small" => "250x250"]
> as $name => $size)
Слишком длинный и нечитаемый заголовок цикла. не надо так.
> $key = array_search($thumb, $files);
Невыгодно искать по значению, быстро делается поиск по ключу.
По коду, код плохо оформлен, не по PSR, оставлены какие-то закомментированные куски, тяжело читать. Также, функции написаны одниой длинной стеной кода, надо выносить отдельные действия. Например, в методе addImages (который правильнее назвать findNewImages или findUnregisteredImages), можно вынести отдельно метод createImageEntity.
В методе createThumbs генерацию одной превьюшки надо вынести отдельно.
Также, ты делаешь обработку в неправильном порядке. Надо сначала генерировать превьюшки, а потом вставлять информацию в БД. Иначе, возможна ситуация, когда картинка есть в БД, но на диске нет соответствующих файлов.
> есть вот такой вариант https://pastebin.com/ceAYHjZ3
Куча методов с плохо составленными названиями, без тайп-хинтов. Если ты хочешь попробовать функциональное программирование, изучай Хаскелл, так как это конечно не оно.
> isset($args[0]) && $args[0] === "thumbs" ?
> $this->thumbs() : $this->thumbs($this->images());
Не надо так делать. Тут нужен if, а ты зачем-то его обфусцируешь, от этого никакой пользы и труднее читать код.
> return array_map(array($this, "putImages"),
> array_filter(
> $this->filterDups(
> array_map(array($this, "prepareSha512"), $diff)
> ),
> array($this, "filterNull")
Эту лестницу невозможно читать.
> Вообще, желал бы перейти на функциональный
Тогда изучи сначала функциональное программирование на примере Хаскелл. На PHP корявость синтаксиса только отпугнет тебя.
> Как это делать, и как понять, когда нужно переносить код в функцию, а когда оставить как есть
Когда полeчается тяжело читаемая стена кода, когда в ней явно можно выделить отдельные действия.
> так ведь только больше места уходит
Цель - читаемость, простота поддержки, а не экономия строчек.
> очень сильно не хватает фантазии на то, чтобы придумать название переменной
Надо учиться объяснять, зачем нужна эта переменаая и что она хранит.
> class ImageUpdate
Название класса - это существительное, хотя бы ImageUpdater, "обновлятель картинок" (есть впрочем мнение, что вредно называть классы с суффиксом -er).
> class ImageUpdate extends Container
Здесь ошибка, непонимание наследования. Вот я даже в своем учебнике пытался описать ( http://phpbooktest.ga/l1/pasta.html )
> Наследование позволяет создать новый класс не с нуля, а расширив уже существующий.
> Нельзя наследовать что угодно от чего угодно. Наследование должно применяться только для однотипных сущностей. Например, класс Банк можно унаследовать от класса Организация (так как банк - это вид организации), а вот унаследовать класс Работник от Организации нельзя. Также, нельзя унаследовать Организацию от Банка, так как Организация - это более широкое понятие.
"А наследуется от B" - это значит "А является B". Это значит, объект класса B можно использовать в коде вместо A (принцип замещения Лисков).
Обновлятель Картинок не является улучшенной версией DI Контейнера. Никто в здравом уме не будет передавать его туда, где нужен Контейнер. Он выполняет совсем другие задачи. Наследование тут неприменимо.
Также, ты нарушил принцип единственности ответственности (каждый класс выполняет свою задачу) - у тебя класс ImageUpdate занимается и сбором картинок, и выполняет роль DI контейнера.
Кстати, это типичная ошибка, я такое во многих CMS видел, люди просто не понимают ООП.
Хотя, я могу ошибиться, так как из куска кода неясно, что такое Container. Тем более что некий ci у тебя еще и передается в конструктор.
Дальше, в конструктор ты передаешь DI Container - но DI делается не так. Прочитай мой урок про DI, лень тут пересказывать все: https://github.com/codedokode/pasta/blob/master/arch/di.md . В конструктор передаются сами зависимости, а не контейнер.
> $images = $this->repo->findAll();
Это будет хорошо работать только до нескольких тысяч записей, а потом скрипт начнет есть много памяти и медленно работать.
> $files = Files::find($this->imageRoot, $this->ignore, $this->imageExts);
Название класса Files неудачное. Что, его объект представляет набор файлов? Нет, это просто Utility class со статическими методами и логично было назвать его FileUtil или FileHelper.
Список расширений наверно незачем делать задаваемым извне параметром - у тебя ведь код поддерживает только определнные расширения и логично их тут же жестко и прописать. В какой ситуации тебе понадобится менять этот параметр?
> foreach ($images as $image) array_push($list, $image->getImage());
Надо писать в 3 строки со скобками. Глянь PSR-1 и PSR-2, они есть и в переводе. Или пропусти код через phpformatter.com.
> $image->getImage()
Метод называется getImage но возвращает, судя по всему, не картинку, а путь к ней. Ну так и сделай соответствующее название.
> if ($dup = $this->repo->findOneBy(['sha512' => $sha512Hash])) {
Если ты загрузил все файлы в память выгоднее сделать "индекс" в виде массива и искать по ключу в нем - это в разы быстрее, чем слать запрос в БД.
> $this->ci->em->persist($image);
> $this->ci->em->flush();
Вообще, не выгодно делать flush после каждого файла, выгоднее собрать побольше сущностей и разом их записать в БД.
> $this->ci->em->clear();
А это вообще не логично. Ты понимаешь, что делает эта команда?
> exec(sprintf("convert -thumbnail
Это довольно невыгодно, запускать внешнюю программу на каждую картинку. Выгоднее использовать расширение imagick или gd.
Также, ты плохо сделал запуск внешней программы. Она может вывести что-то, вернуть ненулевой код возврата, даже зависнуть - у тебя это никак не проверяется. А это значит, что ты не обнаружишь ошибку сразу, а потом обнаружишь битую или отсутствующую превьюшку и потратишь кучу времени на выяснение, откуда она взялась.
> ob_flush();
Зачем они там в каждой строке?
> foreach (["medium" => "1000x1000", "small" => "250x250"]
> as $name => $size)
Слишком длинный и нечитаемый заголовок цикла. не надо так.
> $key = array_search($thumb, $files);
Невыгодно искать по значению, быстро делается поиск по ключу.
По коду, код плохо оформлен, не по PSR, оставлены какие-то закомментированные куски, тяжело читать. Также, функции написаны одниой длинной стеной кода, надо выносить отдельные действия. Например, в методе addImages (который правильнее назвать findNewImages или findUnregisteredImages), можно вынести отдельно метод createImageEntity.
В методе createThumbs генерацию одной превьюшки надо вынести отдельно.
Также, ты делаешь обработку в неправильном порядке. Надо сначала генерировать превьюшки, а потом вставлять информацию в БД. Иначе, возможна ситуация, когда картинка есть в БД, но на диске нет соответствующих файлов.
> есть вот такой вариант https://pastebin.com/ceAYHjZ3
Куча методов с плохо составленными названиями, без тайп-хинтов. Если ты хочешь попробовать функциональное программирование, изучай Хаскелл, так как это конечно не оно.
> isset($args[0]) && $args[0] === "thumbs" ?
> $this->thumbs() : $this->thumbs($this->images());
Не надо так делать. Тут нужен if, а ты зачем-то его обфусцируешь, от этого никакой пользы и труднее читать код.
> return array_map(array($this, "putImages"),
> array_filter(
> $this->filterDups(
> array_map(array($this, "prepareSha512"), $diff)
> ),
> array($this, "filterNull")
Эту лестницу невозможно читать.
> Вообще, желал бы перейти на функциональный
Тогда изучи сначала функциональное программирование на примере Хаскелл. На PHP корявость синтаксиса только отпугнет тебя.
> Как это делать, и как понять, когда нужно переносить код в функцию, а когда оставить как есть
Когда полeчается тяжело читаемая стена кода, когда в ней явно можно выделить отдельные действия.
> так ведь только больше места уходит
Цель - читаемость, простота поддержки, а не экономия строчек.
> очень сильно не хватает фантазии на то, чтобы придумать название переменной
Надо учиться объяснять, зачем нужна эта переменаая и что она хранит.
Ты не написал, речь о фреймворке или о чем-то еще? В PHP переменные сами собой не создаются, ты их все создаешь явно.
В чистом PHP: $x = array_key_exists('x', $_GET) ? strval($_GET['x']) : '';
В новом PHP дял ленивых $x = strval($_GET['x'] ?? '');
В Symfony: $x = $request->query->get('x');
>>46123
Есть поиск в архиве: https://phpclub.tech/search/?q=кошки+мышки если не лень разбирать столько постов.
> Мне эта задача уже года два не дается наверное
Это нездоровый перфекционизм. Ты сделай хоть что-то работающее и вбрось в тред, а там тебе укажут что исправить. Иногда лучше просто что-то сделать, чем долго думать.
Почитай статью про выпечку хлеба, она обязательна для всех, кто недавно изучал ООП или паттерны: https://habrahabr.ru/post/153225/
> Наприрмер о том, где нужно хранить координаты животного. Либо в мире, либо в самом животном например.
Надо взвесить плюсы и минусы.
> Допустим животные хранят в себе своё положение в мире. Стало быть нельзя просто взять и спросить у мира кто рядом с нами?
Ну допустим, координаты хранятся в "мире" в виде массива Coordnate[] (объект Coordinate содержит поля x и y). В чем отличие? В одном случае - массив животных, в другом - массив координат.
Я скажу, в чем. Отличие в том, что когда координаты в мире, их нельзя изменить без его ведома. Если у тебя есть, например, индекс для быстрого поиска на карте, то его надо обновлять при изменении координат. Когда они в мире - это просто. А когда в животных - то мир должен как-то узнавать об их изменении:
- животные должны либо явно уведомлять мир об их изменении
- либо он должен держать копию их координат и после хода сравнением обнаруживать изменения
Если у тебя нет индекса, то разницы, как мы видим, нет, и миру не надо знать, что координаты изменились.
Чтобы быстро спросить "кто рядом" при большом числе объектов, разумеется, массив не годится - там время поиска O(N). Для этого используют индексы - структуры для оптимизации поиска. Есть много разных видов индексов с плюсами и минусами:
- https://ru.wikipedia.org/wiki/Задача_поиска_ближайшего_соседа
- https://en.wikipedia.org/wiki/Nearest_neighbor_search
Например, kD- и BSP-деревья позволяют быстро искать точки в определенном радиусе, но к недостатку можно отнести то, что при перемещении любой точки надо их перестраивать - а у тебя перемещения происходят постоянно. Они лучше годятся для неподвижных объектов (поиск точек на карте, например). R-tree ( https://en.wikipedia.org/wiki/R-tree ) врде лучше заточены под изменение, но очень сложные.
Есть еще другие подходы. Например, разделение пространства на "сектора", причем id сектора вычисляется из координат. Затем мы делаем индекс (просто массив), который хранит для каждого сектора все объекты в нем. Когда нам надо искать ближайшие точки к данной, мы берем ее сектор и, если надо, соседние, берем объекты из них и уже их отсеиваем по расстоянию. При перемещении объекта в другой сектор индекс надо обновить, при перемещении внутри сектора - не надо.
Сюда можно отнести алгортмы:
- https://en.wikipedia.org/wiki/Grid_(spatial_index)
- https://en.wikipedia.org/wiki/Z-order_curve
- https://en.wikipedia.org/wiki/HHCode
- https://en.wikipedia.org/wiki/Quadtree
- другие структуры данных отсюда https://en.wikipedia.org/wiki/Spatial_database#Spatial_index
Многие из алгоритмов рассчитаны на поиск в произвольном радиусе, но если у тебя радиус фиксированный, то их можно сильно упростить.
В этой задаче мышек и кошек не так много, и можно не заморачиваться. Но, если хочется разобраться в теме, я конечно, готов помочь. Индекс стоит сделать в виде отдельного объекта, конечно же. Его надо обновлять при каждом перемещении любого объекта. Но сначала можн осделать просто без индекса.
> Как просто и по полочкам съехать в это примитивное казалось бы ООП с самыми что ни на есть кошечками и собачками :(
Напиши список классов, полей и методов (без кода) и обсудим.
Ты не написал, речь о фреймворке или о чем-то еще? В PHP переменные сами собой не создаются, ты их все создаешь явно.
В чистом PHP: $x = array_key_exists('x', $_GET) ? strval($_GET['x']) : '';
В новом PHP дял ленивых $x = strval($_GET['x'] ?? '');
В Symfony: $x = $request->query->get('x');
>>46123
Есть поиск в архиве: https://phpclub.tech/search/?q=кошки+мышки если не лень разбирать столько постов.
> Мне эта задача уже года два не дается наверное
Это нездоровый перфекционизм. Ты сделай хоть что-то работающее и вбрось в тред, а там тебе укажут что исправить. Иногда лучше просто что-то сделать, чем долго думать.
Почитай статью про выпечку хлеба, она обязательна для всех, кто недавно изучал ООП или паттерны: https://habrahabr.ru/post/153225/
> Наприрмер о том, где нужно хранить координаты животного. Либо в мире, либо в самом животном например.
Надо взвесить плюсы и минусы.
> Допустим животные хранят в себе своё положение в мире. Стало быть нельзя просто взять и спросить у мира кто рядом с нами?
Ну допустим, координаты хранятся в "мире" в виде массива Coordnate[] (объект Coordinate содержит поля x и y). В чем отличие? В одном случае - массив животных, в другом - массив координат.
Я скажу, в чем. Отличие в том, что когда координаты в мире, их нельзя изменить без его ведома. Если у тебя есть, например, индекс для быстрого поиска на карте, то его надо обновлять при изменении координат. Когда они в мире - это просто. А когда в животных - то мир должен как-то узнавать об их изменении:
- животные должны либо явно уведомлять мир об их изменении
- либо он должен держать копию их координат и после хода сравнением обнаруживать изменения
Если у тебя нет индекса, то разницы, как мы видим, нет, и миру не надо знать, что координаты изменились.
Чтобы быстро спросить "кто рядом" при большом числе объектов, разумеется, массив не годится - там время поиска O(N). Для этого используют индексы - структуры для оптимизации поиска. Есть много разных видов индексов с плюсами и минусами:
- https://ru.wikipedia.org/wiki/Задача_поиска_ближайшего_соседа
- https://en.wikipedia.org/wiki/Nearest_neighbor_search
Например, kD- и BSP-деревья позволяют быстро искать точки в определенном радиусе, но к недостатку можно отнести то, что при перемещении любой точки надо их перестраивать - а у тебя перемещения происходят постоянно. Они лучше годятся для неподвижных объектов (поиск точек на карте, например). R-tree ( https://en.wikipedia.org/wiki/R-tree ) врде лучше заточены под изменение, но очень сложные.
Есть еще другие подходы. Например, разделение пространства на "сектора", причем id сектора вычисляется из координат. Затем мы делаем индекс (просто массив), который хранит для каждого сектора все объекты в нем. Когда нам надо искать ближайшие точки к данной, мы берем ее сектор и, если надо, соседние, берем объекты из них и уже их отсеиваем по расстоянию. При перемещении объекта в другой сектор индекс надо обновить, при перемещении внутри сектора - не надо.
Сюда можно отнести алгортмы:
- https://en.wikipedia.org/wiki/Grid_(spatial_index)
- https://en.wikipedia.org/wiki/Z-order_curve
- https://en.wikipedia.org/wiki/HHCode
- https://en.wikipedia.org/wiki/Quadtree
- другие структуры данных отсюда https://en.wikipedia.org/wiki/Spatial_database#Spatial_index
Многие из алгоритмов рассчитаны на поиск в произвольном радиусе, но если у тебя радиус фиксированный, то их можно сильно упростить.
В этой задаче мышек и кошек не так много, и можно не заморачиваться. Но, если хочется разобраться в теме, я конечно, готов помочь. Индекс стоит сделать в виде отдельного объекта, конечно же. Его надо обновлять при каждом перемещении любого объекта. Но сначала можн осделать просто без индекса.
> Как просто и по полочкам съехать в это примитивное казалось бы ООП с самыми что ни на есть кошечками и собачками :(
Напиши список классов, полей и методов (без кода) и обсудим.
if/else и new не подойдет?
Прочти статью https://habrahabr.ru/post/153225/
>>45734
Обратись к специалистам по предсказанию будущего.
>>45942
В смысле, отправка HTTP/2 запросов? Или их прием? Обычно за второе веб-сервер, а не PHP, отвечает. А первое вроде есть в расширении curl.
>>45903
А давай сформулируем задачу и ты сам предложишь ее решения, а там обсудим.
Ну например: надо сделать авторизацию на сайте, и такие функции:
- регистрация: функция получает на вход логин, пароль и "запоминает" их где-то
- проверка данных: функция получает на вход логин, пароль, и проверяет, правльные ли они
- вход на сайт: функция получает на вход логин, пароль, если они верные, то выставляет некую куку
- проверка залогиненности: функция проверяет по кукам, залогинен ли текущий пользователь, если да, то возвращает его логин, если нет - null
- выход: вызов функции "разлогинивает" пользователя, удаляя авторизационную куку
Попробуй описать алгоритм этих функций словами или кодом.
Пароли не запоминаются, а хешируются, есть урок: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md
> действия на сайте
Создается таблица в БД. При каждом действии пользователя в нее добавляется запись. Можно писать действия в лог-файл. Можно использовать Google Analytics, где это уже сделано.
> подгрузка видосов,
Тут куки не причем. Сформулируй конкретную задачу.
> сохранение действий.
Это по моему то же, что и выше. Делается табличка или файл.
if/else и new не подойдет?
Прочти статью https://habrahabr.ru/post/153225/
>>45734
Обратись к специалистам по предсказанию будущего.
>>45942
В смысле, отправка HTTP/2 запросов? Или их прием? Обычно за второе веб-сервер, а не PHP, отвечает. А первое вроде есть в расширении curl.
>>45903
А давай сформулируем задачу и ты сам предложишь ее решения, а там обсудим.
Ну например: надо сделать авторизацию на сайте, и такие функции:
- регистрация: функция получает на вход логин, пароль и "запоминает" их где-то
- проверка данных: функция получает на вход логин, пароль, и проверяет, правльные ли они
- вход на сайт: функция получает на вход логин, пароль, если они верные, то выставляет некую куку
- проверка залогиненности: функция проверяет по кукам, залогинен ли текущий пользователь, если да, то возвращает его логин, если нет - null
- выход: вызов функции "разлогинивает" пользователя, удаляя авторизационную куку
Попробуй описать алгоритм этих функций словами или кодом.
Пароли не запоминаются, а хешируются, есть урок: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md
> действия на сайте
Создается таблица в БД. При каждом действии пользователя в нее добавляется запись. Можно писать действия в лог-файл. Можно использовать Google Analytics, где это уже сделано.
> подгрузка видосов,
Тут куки не причем. Сформулируй конкретную задачу.
> сохранение действий.
Это по моему то же, что и выше. Делается табличка или файл.
Теория программирования не научит тебя писать читаемый код или правильно использовать ООП. Или быстро решать задачу.
>>45789
Код надо выравнивать. У тебя он прижат влево (ты прямо в ideone пишешь? Установи notepad++, sublime text, netbeans, eclipse pdt, phpstorm или другой редактор кода) и потому читать очень тяжело. Или пропусти код через phpformatter.com.
> $amount7 = 02020200;
Это число в 8-чной системе счисления:
- что такое 8-чные числа https://ru.wikipedia.org/wiki/Восьмеричная_система_счисления
- мануал, где говорится о том что числа с 0 восьмеричные: http://php.net/manual/ru/language.types.integer.php
И когда ты пишешь 015, то PHP это понимает как 8-чную форму числа 8 + 5 = 13.
По коду:
> array_push
Проще писать $array[] = $string;
> $hundWithoutDec
hundreds
> if ($num == 0) {
> return $num;
надо возвращать, не 0, а "ноль"
> $hundDec
lastTwo, tensAndUnits
> $hundDecWithoutOne
units, ones
> hundredThous
thousands
> hundWithoutMil
rest, remainder, lastThreeDigits
> $fem = $hundWithoutMil % 10;
$female не надо вычислять - оно всегда равно 1 для тысяч ("тысяча" женского рода) и 0 для миллионов/единиц.
> $numberToString = array();
result, string
> $mill = spellSmallNumber($millions,NULL);
> array_push($numberToString,$mill ,NULL);
$result[] = spellSmallNumber($millions, NULL);
Самое главное, исправь форматирование и пройдись по именам переменных - сделай их попонятнее.
А так, алгоритм верный, все почти готово.
Теория программирования не научит тебя писать читаемый код или правильно использовать ООП. Или быстро решать задачу.
>>45789
Код надо выравнивать. У тебя он прижат влево (ты прямо в ideone пишешь? Установи notepad++, sublime text, netbeans, eclipse pdt, phpstorm или другой редактор кода) и потому читать очень тяжело. Или пропусти код через phpformatter.com.
> $amount7 = 02020200;
Это число в 8-чной системе счисления:
- что такое 8-чные числа https://ru.wikipedia.org/wiki/Восьмеричная_система_счисления
- мануал, где говорится о том что числа с 0 восьмеричные: http://php.net/manual/ru/language.types.integer.php
И когда ты пишешь 015, то PHP это понимает как 8-чную форму числа 8 + 5 = 13.
По коду:
> array_push
Проще писать $array[] = $string;
> $hundWithoutDec
hundreds
> if ($num == 0) {
> return $num;
надо возвращать, не 0, а "ноль"
> $hundDec
lastTwo, tensAndUnits
> $hundDecWithoutOne
units, ones
> hundredThous
thousands
> hundWithoutMil
rest, remainder, lastThreeDigits
> $fem = $hundWithoutMil % 10;
$female не надо вычислять - оно всегда равно 1 для тысяч ("тысяча" женского рода) и 0 для миллионов/единиц.
> $numberToString = array();
result, string
> $mill = spellSmallNumber($millions,NULL);
> array_push($numberToString,$mill ,NULL);
$result[] = spellSmallNumber($millions, NULL);
Самое главное, исправь форматирование и пройдись по именам переменных - сделай их попонятнее.
А так, алгоритм верный, все почти готово.
> наверное самое эффективное решение это выдавать ссылки на файл в публичной папке, а в этой папке отключить обработку скриптов.
Тут есть подвох, что файлы могут быть с самыми разными именами: file.php, .htaccess, файл из иероглифов. И это требует тщательной настройки сервера - стоит сделать ошибку и он начнет радостно выполнять php-файлы. Плюс, может ты захочешь считать статистику скачиваний, ограничивать доступ.
На практике, файлообменники все же обычно используют что-то вроде x-sendfile. То есть запуск скрипта, а потом выдача заголовка для сервера на скачивание файла. При этом файл можно хранить под безопасным именем.
> Каким образом в реальном мире производятся фоновые задачи?
Через очередь задач. В приложении делаешь класс с методами добавить задачу/проверить статус задачи/снять задачу. Обычно там просто делается таблица - очередь задач (могут быть другие варианты - например, очередь в RabbitMQ) - и есть один или несколько скриптов-рабочих, которые следят за ней и при появлении новой задачи берут ее, выполняют, и записывают результат. Могут по ходу дела обновлять прогресс. Опять же, они могут как-то посылать уведомление о завершении.
Использовать БД не принципиально - можно например постить задачи, сообщения о прогрессе, ошибке/успехе в очередь сообщений вроде RabbitMQ. Как удобнее. Можно использовать и то, и другое.
Рабочие могут запускаться через крон, может быть отдельный какой-то супервизор, который за ними следит, может быть какой-то процесс с несколькими потоками-рабочими внутри.
На клиенте - можно использовать поллинг (периодиечски отправлять аякс-запросы на проверку статуса либо просто перезагружать страницу ожидания), либо настроить передачу уведомления с сервера на клиент о прогрессе и завершении задачи (надо изучить вебсокеты и протокол WAMP).
Если ты ищешь готовую функцию, то такой нет. Если ты думаешь, что PHP ограничен выполнением скриптов при вводе URL в адресную строку, то ты ошибаешсья - программу PHP можно запустить отдельно от веб-сервера, вручную или прописав ее в автоматический запуск при включении сервера под наблюдением супервизора.
> По наводке из статьи опа прочитал про gearman, мало что понял,
Задавай вопросы
> есть еще какой-то крон
Ну так изучи его.
> Вот как например ютуб конвертирует видео?
Так, как я описал, только у них скорее всего система распределенная, и конвертацией занимается не просто несколько процессов-рабочих, а множество таких процессов на множестве серверов.
По Ютубу есть кое-какая инфа тут:
- https://www.insight-it.ru/highload/2008/arkhitektura-youtube/
- https://www.insight-it.ru/highload/2012/arkhitektura-youtube-2012/
> Если я буду в превьюхе указывать сорс на оригинальную картинку, то будет ли выполняться пхп код
Нет, с чего бы? Только неэффективно ради превьюшки качать огромную картинку. Но конечно, это зависит от настройки сервера - если ты скажешь ему, что картинки надо выполнять как php-скрипты, то все возможно.
> наверное самое эффективное решение это выдавать ссылки на файл в публичной папке, а в этой папке отключить обработку скриптов.
Тут есть подвох, что файлы могут быть с самыми разными именами: file.php, .htaccess, файл из иероглифов. И это требует тщательной настройки сервера - стоит сделать ошибку и он начнет радостно выполнять php-файлы. Плюс, может ты захочешь считать статистику скачиваний, ограничивать доступ.
На практике, файлообменники все же обычно используют что-то вроде x-sendfile. То есть запуск скрипта, а потом выдача заголовка для сервера на скачивание файла. При этом файл можно хранить под безопасным именем.
> Каким образом в реальном мире производятся фоновые задачи?
Через очередь задач. В приложении делаешь класс с методами добавить задачу/проверить статус задачи/снять задачу. Обычно там просто делается таблица - очередь задач (могут быть другие варианты - например, очередь в RabbitMQ) - и есть один или несколько скриптов-рабочих, которые следят за ней и при появлении новой задачи берут ее, выполняют, и записывают результат. Могут по ходу дела обновлять прогресс. Опять же, они могут как-то посылать уведомление о завершении.
Использовать БД не принципиально - можно например постить задачи, сообщения о прогрессе, ошибке/успехе в очередь сообщений вроде RabbitMQ. Как удобнее. Можно использовать и то, и другое.
Рабочие могут запускаться через крон, может быть отдельный какой-то супервизор, который за ними следит, может быть какой-то процесс с несколькими потоками-рабочими внутри.
На клиенте - можно использовать поллинг (периодиечски отправлять аякс-запросы на проверку статуса либо просто перезагружать страницу ожидания), либо настроить передачу уведомления с сервера на клиент о прогрессе и завершении задачи (надо изучить вебсокеты и протокол WAMP).
Если ты ищешь готовую функцию, то такой нет. Если ты думаешь, что PHP ограничен выполнением скриптов при вводе URL в адресную строку, то ты ошибаешсья - программу PHP можно запустить отдельно от веб-сервера, вручную или прописав ее в автоматический запуск при включении сервера под наблюдением супервизора.
> По наводке из статьи опа прочитал про gearman, мало что понял,
Задавай вопросы
> есть еще какой-то крон
Ну так изучи его.
> Вот как например ютуб конвертирует видео?
Так, как я описал, только у них скорее всего система распределенная, и конвертацией занимается не просто несколько процессов-рабочих, а множество таких процессов на множестве серверов.
По Ютубу есть кое-какая инфа тут:
- https://www.insight-it.ru/highload/2008/arkhitektura-youtube/
- https://www.insight-it.ru/highload/2012/arkhitektura-youtube-2012/
> Если я буду в превьюхе указывать сорс на оригинальную картинку, то будет ли выполняться пхп код
Нет, с чего бы? Только неэффективно ради превьюшки качать огромную картинку. Но конечно, это зависит от настройки сервера - если ты скажешь ему, что картинки надо выполнять как php-скрипты, то все возможно.
Можно всегда показать код и задать вопрос.
>>45606
Это числа в 8-чной системе счисления: http://php.net/manual/ru/language.types.integer.php
>>45497
Код покажи.
Также, есть пример кода в сети - он похож на твой? http://code.iamkate.com/php/sending-files-using-curl/
Также, можно использовать высокоуровневые библиотеки вроде Guzzle.
>>45457
Можно смотреть на библиотеки крупных компаний: Гугл/Яндекс. А так, я не смогу сформулировать требования, думаю, тут те же подходы, что и при написании внутреннего кода, только побольше комментариев и документации. Чтобы код был простой и логичный, без побочных эффектов и "магии".
Примеры:
- https://github.com/google/google-api-php-client (он сложный, так как там много API)
- https://github.com/nixsolutions/yandex-php-library
>>45436
Трудно комментировать, не зная постановки задачи.
>>45426
Что они вообще пришли и что нет ошибки. Ну и может у тебя какие-то дополнительные запреты есть.
Можно всегда показать код и задать вопрос.
>>45606
Это числа в 8-чной системе счисления: http://php.net/manual/ru/language.types.integer.php
>>45497
Код покажи.
Также, есть пример кода в сети - он похож на твой? http://code.iamkate.com/php/sending-files-using-curl/
Также, можно использовать высокоуровневые библиотеки вроде Guzzle.
>>45457
Можно смотреть на библиотеки крупных компаний: Гугл/Яндекс. А так, я не смогу сформулировать требования, думаю, тут те же подходы, что и при написании внутреннего кода, только побольше комментариев и документации. Чтобы код был простой и логичный, без побочных эффектов и "магии".
Примеры:
- https://github.com/google/google-api-php-client (он сложный, так как там много API)
- https://github.com/nixsolutions/yandex-php-library
>>45436
Трудно комментировать, не зная постановки задачи.
>>45426
Что они вообще пришли и что нет ошибки. Ну и может у тебя какие-то дополнительные запреты есть.
species можно сделать ENUM или внешним ключом (ссылкой) на таблицу видов животных, если их ограниченное количество.
> список владельцев с полями, по id животного
> список животных с полями, по id владельца
> информацию по владельцу(ам), по некоторой известной инфе о животном (клеймо, микрочип)
Запросом SELECT с JOIN. Ты изучал джойны? Если нет, то изучи.
>>45388
> тормознутые транзакции откинуть
Это бессмысленное утверждение. Что значит "тормознутые транзакции"? В случае InnoDB любое изменение данных это транзакция.
> Главное чтоб быстро выбирало крупные данные и без лишних полей.
Транзакции тут точно не при чем - они относятся к изменению данных.
>>45329
>тормозов из-за транзакций.
Почему ты решил, что дело в них? Может, у тебя индексы не сделаны? диск медленный? памяти мало выделено? еще что-то не так?
Тебе надо научиться настраивать MySQL, а также профилировать запросы. например, освоить команду EXPLAIN, ну и посмотреть в htop, iotop на процесс MySQL - сколько он ест памяти, CPU, диска.
Внешние ключи и транзакции экономят твое время на исправление багов в данных в БД.
>>45170
Это называется Roadmap - гугли "php roadmap". Но, увы, я там ничего не нашел.
>>45220
Попробуй сдампить echo bin2hex($s), где $s - строка с кириллицей, полученная через fgets() и напиши что получится - может, это даст ответ. Может, там какие-то коды есть, которые интерпретируются как перевод строки.
Так не сказать.
species можно сделать ENUM или внешним ключом (ссылкой) на таблицу видов животных, если их ограниченное количество.
> список владельцев с полями, по id животного
> список животных с полями, по id владельца
> информацию по владельцу(ам), по некоторой известной инфе о животном (клеймо, микрочип)
Запросом SELECT с JOIN. Ты изучал джойны? Если нет, то изучи.
>>45388
> тормознутые транзакции откинуть
Это бессмысленное утверждение. Что значит "тормознутые транзакции"? В случае InnoDB любое изменение данных это транзакция.
> Главное чтоб быстро выбирало крупные данные и без лишних полей.
Транзакции тут точно не при чем - они относятся к изменению данных.
>>45329
>тормозов из-за транзакций.
Почему ты решил, что дело в них? Может, у тебя индексы не сделаны? диск медленный? памяти мало выделено? еще что-то не так?
Тебе надо научиться настраивать MySQL, а также профилировать запросы. например, освоить команду EXPLAIN, ну и посмотреть в htop, iotop на процесс MySQL - сколько он ест памяти, CPU, диска.
Внешние ключи и транзакции экономят твое время на исправление багов в данных в БД.
>>45170
Это называется Roadmap - гугли "php roadmap". Но, увы, я там ничего не нашел.
>>45220
Попробуй сдампить echo bin2hex($s), где $s - строка с кириллицей, полученная через fgets() и напиши что получится - может, это даст ответ. Может, там какие-то коды есть, которые интерпретируются как перевод строки.
Так не сказать.
Не надо смотреть на моду, надо смотреть на постановку задачи.
>>44424
Почему не установить и не настроить PHP/MySQL + Apache если встроенный PHP сервер не сработает?
>>44022
Если ты слабо знаешь программирование, то проще взять CMS. Некоторые Друпал рекомендуют, хотя он не простой. С ModX не знаком.
>Напиши список классов, полей и методов (без кода) и обсудим.
Окей, тогда отталкиваясь от совета:
>Это нездоровый перфекционизм. Ты сделай хоть что-то работающее и вбрось в тред, а там тебе укажут что исправить. Иногда лучше просто что-то сделать, чем долго думать.
Сделаю максимально просто для начала.
Например не буду заморачиваться с тем как это там дожно быть по хорошему в вакууме.
1. Ну для начала нужен класс Animal, у него будут поля $x и $y - это банально место положение на нашей карте.
Далее например будет абстрактный метод lookAround() - который будет переопределен для мышки и кошки отдельно, пока сложно понять что он должен возвращать, допустим пусть возвращает все доступные животному клетки(координаты) со значением привлекательности каждой из этих клеток.
Опять же вот думаю об этом, и если у нас например объекты хранят в себе координаты, то для кошечки, когда она смотрит вокруг, а она будет смотреть на всё поле, для КАЖДОЙ долбанной клеточки на поле будет вызываться перебор ВСЕХ объектов в мире, что бы высчитать для этой клеточки привлекательность, ведь надо что бы рядом с клеточкой было как можно больше мышек и как можно меньше других кошек скажем. Будет адуха адская в плане неоптимальности решения, ну да и черт с ним.
Допустим посмотрели вокруг, и нужно сделать ход, для этого другой метод, которому уже передаем массив клеток с их привлекательностью, и кошечка уже принимает решение куда сходить.
Либо кошечка ходит просто на САМУЮ привлекательную клетку из доступных, либо например сделать так, что бы она ходила на самую привлекательную клетку, из тех, которые лежат на кротчайших путях к САМОЙ привлекательной клетке на поле.
Условно говоря пикрил (пока рисовал, думал что кошечка ходит на 1 клетку за ход, а там вроде бы на 2 по условию задачи, так что не суть, просто как пример)
Для мышки аналогично сделать, опять же перебирать все все объекты на поле, что бы вычислить привлекательность для каждой из тех клеток которые она видит, благо видит она всего +-4 в каждую сторону, так что итераций будет в сотни раз меньше в случае средненького поля.
Ну и методы подсчета привлекательности переделать, подальше от кошек, стен и скопления других мышей ей прописать например. Ну или наоборот что бы жалась к другим мышкам, глядишь в толпе выжить проще и съедят не тебя (бедная глупая мышка, только проще для кошки будет с каждым ходом становиться, когда они в кучке)
2. Ну и наверное класс поля, который будет просто нужен для хранения в себе всех животных, через него наверное будем обращаться ко всем объектам, блин если честно пока вот это писал - уже голова закипать начала, как будто не простейшую задачу пишешь, а целую игру программируешь сложнейшую со своим ИИ и поиском путей, блин.
Ну и метод для отрисовки поля, думаю простейшее - сначала залить поле нулями, а дальше перебирая все объекты заменять нули на иконку мышики или кошки. Выглядит логично.
Ну и какой-нибудь класс по типу gameLoop, для того что бы в него всё свалить, запускать на каждой итерации которой все живые животные по очереди будут ходить, а потом будет отрисовываться карта. И так столько сколько задано.
>Напиши список классов, полей и методов (без кода) и обсудим.
Окей, тогда отталкиваясь от совета:
>Это нездоровый перфекционизм. Ты сделай хоть что-то работающее и вбрось в тред, а там тебе укажут что исправить. Иногда лучше просто что-то сделать, чем долго думать.
Сделаю максимально просто для начала.
Например не буду заморачиваться с тем как это там дожно быть по хорошему в вакууме.
1. Ну для начала нужен класс Animal, у него будут поля $x и $y - это банально место положение на нашей карте.
Далее например будет абстрактный метод lookAround() - который будет переопределен для мышки и кошки отдельно, пока сложно понять что он должен возвращать, допустим пусть возвращает все доступные животному клетки(координаты) со значением привлекательности каждой из этих клеток.
Опять же вот думаю об этом, и если у нас например объекты хранят в себе координаты, то для кошечки, когда она смотрит вокруг, а она будет смотреть на всё поле, для КАЖДОЙ долбанной клеточки на поле будет вызываться перебор ВСЕХ объектов в мире, что бы высчитать для этой клеточки привлекательность, ведь надо что бы рядом с клеточкой было как можно больше мышек и как можно меньше других кошек скажем. Будет адуха адская в плане неоптимальности решения, ну да и черт с ним.
Допустим посмотрели вокруг, и нужно сделать ход, для этого другой метод, которому уже передаем массив клеток с их привлекательностью, и кошечка уже принимает решение куда сходить.
Либо кошечка ходит просто на САМУЮ привлекательную клетку из доступных, либо например сделать так, что бы она ходила на самую привлекательную клетку, из тех, которые лежат на кротчайших путях к САМОЙ привлекательной клетке на поле.
Условно говоря пикрил (пока рисовал, думал что кошечка ходит на 1 клетку за ход, а там вроде бы на 2 по условию задачи, так что не суть, просто как пример)
Для мышки аналогично сделать, опять же перебирать все все объекты на поле, что бы вычислить привлекательность для каждой из тех клеток которые она видит, благо видит она всего +-4 в каждую сторону, так что итераций будет в сотни раз меньше в случае средненького поля.
Ну и методы подсчета привлекательности переделать, подальше от кошек, стен и скопления других мышей ей прописать например. Ну или наоборот что бы жалась к другим мышкам, глядишь в толпе выжить проще и съедят не тебя (бедная глупая мышка, только проще для кошки будет с каждым ходом становиться, когда они в кучке)
2. Ну и наверное класс поля, который будет просто нужен для хранения в себе всех животных, через него наверное будем обращаться ко всем объектам, блин если честно пока вот это писал - уже голова закипать начала, как будто не простейшую задачу пишешь, а целую игру программируешь сложнейшую со своим ИИ и поиском путей, блин.
Ну и метод для отрисовки поля, думаю простейшее - сначала залить поле нулями, а дальше перебирая все объекты заменять нули на иконку мышики или кошки. Выглядит логично.
Ну и какой-нибудь класс по типу gameLoop, для того что бы в него всё свалить, запускать на каждой итерации которой все живые животные по очереди будут ходить, а потом будет отрисовываться карта. И так столько сколько задано.
В общем, идеи верные, можно начинать писать код. Я вижу, что ты сильно заморачиваешься с алгоритмом хода, почемы бы вместо него пока не поставить заглушку - просто делать рандомный ход или даже стоять на месте - сделать все остальное, а потом перейти к тестированию разных вариантов алгоритма?
> Далее например будет абстрактный метод lookAround() - который будет переопределен для мышки и кошки отдельно, пока сложно понять что он должен возвращать, допустим пусть возвращает все доступные животному клетки(координаты) со значением привлекательности каждой из этих клеток.
Тут можно еще чуть упростить задачу, если свести все к функции оценки (сделать ее абстрактной). Мы даем животному координаты и оно оценивает привлекательность этого хода. Так мы можем вынести перебор ходов, выбор лучшего наружу - но правда тогда все животные должны будут использовать этот алгоритм.
Другой вариант - сделать абстрактный метод makeMove(), который ничего не возвращает и сам выбирает и делает ход. В этом случае животное может использовать вообще любой алгоритм.
> Опять же вот думаю об этом, и если у нас например объекты хранят в себе координаты, то для кошечки, когда она смотрит вокруг, а она будет смотреть на всё поле, для КАЖДОЙ долбанной клеточки на поле будет вызываться перебор ВСЕХ объектов в мире, что бы высчитать для этой клеточки привлекательность, ведь надо что бы рядом с клеточкой было как можно больше мышек и как можно меньше других кошек скажем
Ну у нас там пара десятков объектов всего. Ты бы вместо того, чтобы переживать, сделал бы тест и померял, сколько это времени занимает.
И еще мысль. Ты вот сейчас мыслишь по-программистски - надо любой ценой оптимизировать потребление CPU. Но в реальной работе программиста бывают и другие варианты:
- надо оптимизировать время разработки. Лучше плохой, но работающий алгоритм сегодня, чем идеальный через месяц
- надо оптимизировать затраты. Дешевле может быть переехать на сервер помощнее, чем 2 недели оптимизировать код
Мы конечно тебе за обучение не платим и потому расходы твоего времени нас не очень беспокоят, но может быть, они беспокоят тебя.
Ну и если уж ты задался целью любой ценой оптимизировать потребление CPU - надо брать другой язык программирования. Так что давай без фанатизма, но и конечно без откровенно плохого решения - искать компромисс.
В твоем случае, я уже писал выше, можно 1) использовать индексы для поиска ближайщих соседей, причем, что важно, можно сначала писать без индексов и только потом их добавить 2) можно что-то кешировать, например, если несколько кошек делают одни и те же вычисления, можно закеширвать их результаты.
Также, можно упростить алгоритм. Ну например, вместо обзора всех клеток в поле зрения - просто перебирать только те клетки, на которые мы можем сходить, вычислять очки по какой-то простой системе для них и не просчитывать на несколько ходов вперед. Вполне возможно, что тестирование покажет, что этот алгоритм прекрасно справляется с задачей. А если будут какие-то мелкие косяки - закрыть их добавлением дополнительных факторов при оценке хода.
У нас все таки задача больше на ООП, чем на игровые стратегии.
В общем, идеи верные, можно начинать писать код. Я вижу, что ты сильно заморачиваешься с алгоритмом хода, почемы бы вместо него пока не поставить заглушку - просто делать рандомный ход или даже стоять на месте - сделать все остальное, а потом перейти к тестированию разных вариантов алгоритма?
> Далее например будет абстрактный метод lookAround() - который будет переопределен для мышки и кошки отдельно, пока сложно понять что он должен возвращать, допустим пусть возвращает все доступные животному клетки(координаты) со значением привлекательности каждой из этих клеток.
Тут можно еще чуть упростить задачу, если свести все к функции оценки (сделать ее абстрактной). Мы даем животному координаты и оно оценивает привлекательность этого хода. Так мы можем вынести перебор ходов, выбор лучшего наружу - но правда тогда все животные должны будут использовать этот алгоритм.
Другой вариант - сделать абстрактный метод makeMove(), который ничего не возвращает и сам выбирает и делает ход. В этом случае животное может использовать вообще любой алгоритм.
> Опять же вот думаю об этом, и если у нас например объекты хранят в себе координаты, то для кошечки, когда она смотрит вокруг, а она будет смотреть на всё поле, для КАЖДОЙ долбанной клеточки на поле будет вызываться перебор ВСЕХ объектов в мире, что бы высчитать для этой клеточки привлекательность, ведь надо что бы рядом с клеточкой было как можно больше мышек и как можно меньше других кошек скажем
Ну у нас там пара десятков объектов всего. Ты бы вместо того, чтобы переживать, сделал бы тест и померял, сколько это времени занимает.
И еще мысль. Ты вот сейчас мыслишь по-программистски - надо любой ценой оптимизировать потребление CPU. Но в реальной работе программиста бывают и другие варианты:
- надо оптимизировать время разработки. Лучше плохой, но работающий алгоритм сегодня, чем идеальный через месяц
- надо оптимизировать затраты. Дешевле может быть переехать на сервер помощнее, чем 2 недели оптимизировать код
Мы конечно тебе за обучение не платим и потому расходы твоего времени нас не очень беспокоят, но может быть, они беспокоят тебя.
Ну и если уж ты задался целью любой ценой оптимизировать потребление CPU - надо брать другой язык программирования. Так что давай без фанатизма, но и конечно без откровенно плохого решения - искать компромисс.
В твоем случае, я уже писал выше, можно 1) использовать индексы для поиска ближайщих соседей, причем, что важно, можно сначала писать без индексов и только потом их добавить 2) можно что-то кешировать, например, если несколько кошек делают одни и те же вычисления, можно закеширвать их результаты.
Также, можно упростить алгоритм. Ну например, вместо обзора всех клеток в поле зрения - просто перебирать только те клетки, на которые мы можем сходить, вычислять очки по какой-то простой системе для них и не просчитывать на несколько ходов вперед. Вполне возможно, что тестирование покажет, что этот алгоритм прекрасно справляется с задачей. А если будут какие-то мелкие косяки - закрыть их добавлением дополнительных факторов при оценке хода.
У нас все таки задача больше на ООП, чем на игровые стратегии.
Я как раз и пытаюсь выйти на новый уровень, потому что я уже поработал 2 года говношлепом на фреймворке, когда тупо херачишь говнокод быстрее быстрее, лишь бы работало по уже отработанной схеме, просто потому что надо. Ладно, не буду об этом.
Не могу в общем при написании отделаться от ступора, например когда тебе в мир нужно передать объект животное когда ты его вроде бы там логично спавнишь, и при этом же в животное передовать мир, когда ты смотришь вокруг, получается такая вот какая-то взаимозависимость, к чему я ВООБЩЕ НЕ привык на своих нубоработах.
>Я вижу, что ты сильно заморачиваешься с алгоритмом хода, почемы бы вместо него пока не поставить заглушку - просто делать рандомный ход или даже стоять на месте - сделать все остальное, а потом перейти к тестированию разных вариантов алгоритма?
Спасибо, камень с души прям, так и сделаю сейчас.
>1) использовать индексы для поиска ближайщих соседей, причем, что важно, можно сначала писать без индексов и только потом их добавить
Не понял что тут имеется в виду? Хранить отдельно координаты? скажем еще и что бы мир знал что у него в какой клетке и через него спрашивать а кто тут у нас в округе сидит, вместо того что бы опрашивать все объекты в мире? Я над этим уже много думал. Наверное дублирование всё же нужно в хорошей системе. Просто потому что ну как с базами, если всё пытаться к третьей форме приводить, то ты очумеешь делать простейшие запросы собирая страничку юзера, так и тут, одуреешь перебирать все объекты мира, в надежде узнать есть ли кто рядом в соседней клетке, КОГДА МОЖНО ПРОСТО ПРОДУБЛИРОВАТЬ ИНФОРМАЦИЮ 1 РАЗ, и иметь возможность спросить у overseer-объекта кто у нас там рядом в соседней клетке. Ты об этом?
Архивировать на клиенте файлы недопустимых расширений, отправлять на сервер файл вида file.php.tar.gz и хранить на сервере в виде архива, будет плохой идеей? Я тоже решаю эту задачу, только у меня там еще потуга сделать более или менее полноценный фронт-енд.
>Они просто общаются с веб-сервером по HTTP вместо CGI/FastCGI.
И да, и нет. Контейнер сервлетов - такой же полноценный веб сервер. Да и несервлетные приложения тоже.
>В сравнении с CGI это усложняет приложение (ты вряд ли напишешь полноценный HTTP сервер на bash, а с CGI можно работать хоть из bash скрипта), приводит к дублированию функционала (разбором HTTP мог бы заниматься только веб-сервер).
Ты же не пишешь свой сервер. Ты точно так же берёшь томкат/аппликейшн сервер/библиотеку и пользуешься. И опять: веб сервер - это не только апач или нджинкс.
>Есть конечно и плюсы - они могут работать как-то ограниченно даже без веб-сервера.
Они работают полноценно. И на этом основаны всякие ништяки микросервисов вроде service discovery и client side load balancing.
>>46700
Паттерны (могу ошибаться) начал собирать Фаулер.
Фабрику, синглтон и всякие прокси описаны задолго до него бандой четырех. Фаулер именно по ентерпрайзным паттернам угарел.
Это то же самое говно, что на рутрекере. Написано, что 2016, но по факту там материалы за 2015-2016.
Ладно, поясню тебе на пальцах. Там php 5.5 - что самое главное. Там уже есть ооп и прочее. Те изменения, что завезли пхп 7, тебе всё равно в первый год не понадобятся, я базарю.
Во вторых подобный курс - это всё равно лишь основы языка и не более. Тебя научат как сделать простенький сайт на коленке с несложной версткой и основами владения mysql опять же.
Что в подобном курсе от 2014, что от 2018, тебе будут объяснять по сути одно и тоже, тупо в мелочах отличия, которые ты забудишь через пару дней - базарю. А еще если ты не будешь сидеть и ждать пока тебе подкинут идеальный гайд как стать синьёром-php за 5 дней без регистрации и смс, а прямо сразу посомтришь хотя бы первый день, то ты уже бы сделал для своего потенциального будущего куда больше, чем возможно за всю предыдущую жизнь в школе (и универе).
Вкатился после просмотров его уроков. Смотрел дохуя разного - все остальное васянская хуйня
Ну я год назад смотрел. Знач ошибся. А вообще новые от него я бы и сам глянул
>Трудно комментировать, не зная постановки задачи.
Продумываю структуру базы данных. Раньше делал только простенькие из пары таблиц, просто чтобы хранилось.
Хочу помацать InnoDB за транзакции и форейгн-ключики.
Как видишь, уже на диаграмме пиздец, а чо будет дальше та?
Почитал про джойны, примеры работают, а как их к этой базе применить не доходит.
Еще внешние ключи ну никак не могу понять, я вот их наставил тут, но походу немного далеко уехал с ними.
Как мне отсортировать этот массив по букве? Чтобы записи с одинаковыми буквами были сгруппированы внутри большого массива.
Понял, спасибо.
usort(): http://php.net/manual/en/function.usort.php
<?php
$a = [[0, 'b', 'b string'],
[1, 'a', 'a string'],
[2, 'd', 'd string'],
[3, 'f', 'f string'],
[4, 'e', 'e string'],
[5, 'a', 'a2 string']];
usort($a,
function($a, $b){
if ($a[1] == $b[1]) {
return 0;
}
elseif ($a[1] < $b[1]) {
return -1;
} else {
return 1;
}
});
Дополню тебя, что в PHP7 (который вышел аж в 2015-м году) есть spaceship оператор и cтену if'ов в колбеке можно заменить одной строкой: return $a <=> $b;
>1146129
>Еще мне порой очень сильно не хватает фантазии на то, чтобы придумать название переменной.
Не можешь дать нормальное имя переменной - не до конца понимаешь, что в ней находится. Плохое именование от непонимания.
https://ideone.com/cMvAiV
https://ideone.com/A1PoXo
Почему во втором решении код выглядит как не читабельная каша?
там 2 строчки кода в каждом решении, он не может быть неправильным.
>Почему во втором решении код выглядит как не читабельная каша?
Потому что ты не привык просто пока к каким-то операторам или синтаксису и тебе нужно больше практиковаться.
Не парься над такими легкими задачами, то что ты решил её двумя способами - это уже хорошо само по себе, а пытаться вычислить идеальное решение - это глупо, решай так, как тебе больше нравится, думай об этом как о СВОЁМ СОБСТВЕННОМ стиле программирования.
ебучая система образования сука с её заучиванием идеальных путей и алгоритмов, когда тебя именно кормят идеальными путями решения всяких уравнений и прочего говна, а потом ты по жизни везде пытаешься под это подстроиться :( Вместо того что бы просто решать проблемы, ты ищешь идеальный, "правльный" путь её решения. Тьфу пиздос кароче горит аж, потому что у меня тупо саем по жизни
Всё так, ебашь дальше.
спасибо
Сам я пхп макакер, с сайтами приходится работать редко, в основном пишу разные парсеры, ботов, спамеры и пр хуйню-малафью. Ничего другого кроме пхп не знаю когдато знал жс и немного кресты но нихуя не помню. Часто ловлю себя на мысле "ах вот если бы то или се", "вот еслибы запустить куски моего кода асинхронно и кококо". Подумываю взяться учить ноду, стоит ли этим заниматься в 2к18? Спешить никуда не планирую, буду в свободное время посматривать уроки, но может стоит обратить внимание на чтото более актуальное?
сенкс, но у меня есть раб-ота, просто хочу попробовать в другой язык
>А еще, если вдруг ты не очень уверен в ООП, то у меня еще есть пара задач - про Гостиницу и Агенство - не хочешь хотя бы глянуть? >https://phpclub.tech/pr/chain/1108694/
Сап пхпач, что то тред совсем утонул, еле нашел.
Запилил немного задание про гостиницу.
https://github.com/homohomozak/oop
Хранитель треда посмотри пожалуйста, в правильном ли я направлении двигаюсь?
Вкатываюсь в пхп после питона, возник вопрос: почему в пхп функцию можно вызвать до объявления?
таков интерпритатор пхп, а тебя это смущает?
А в чём фишка нодовской асинхронности? Может кто-нибудь расскажет? Ну тоесть я так понял это когда ты отправляешь несколько запросов, и они отрабатываются отдельным потоком каждый? Но ведь по факту там просто формирование очереди запросов и вся асинхронность получается чисто на бумаге. Или я не прав?
У меня вопрос к устроившимся анонам, в остальных компаниях без вышки в большинстве случаев покажут на дверь?
то есть чуваков с опытом/портфолио берут и без вышки?
вот допустим я с головой ухожу в backend может ли сказаться нехватка знаний по высшей математике/азов программирования что изучают в профильных вузах?
А что мешает п_одучить математику или "азы программирования"? Открываешь Кнута или Кормена и читаешь
> Открываешь Кнута или Кормена и читаешь
И ты попрежднему нихуя не понимаешь. Зато можешь говорить, что то или иное словечко видел у кнута.
А что мешает п_одучить математику или "азы хирургии"? Открываешь учебник по биологии за 11 класс и читаешь.
Вот примерно также ты сейчас сказал.
На деле тебе нужны будут тонны практики. Так что советую её получить.
В сурьезные конторы, да и в некоторых случаях заграницу без вышки не выйдет. Никто не запрещает попробовать, откажут ну и хуй с ними.
Во всех остальных случаях не так жеско. Где то якобы требуют, а на деле похуй, где то напрямую говорят нам насрать. На срилансе вообще никого не ебет, что ты там закончил, главное пили таски и не лажай сильно.
Ты упускаешь самое главное для ойти это английский язык. Знаешь хорошо, считай будешь устроен. Знаешь средне придется тяжело. Нихуя не знаешь, только доку иногда покурить можешь, нихуя не найдешь.
А если английский знаешь, то пилишь портфолио или нарабатываешь опыт на галерах, и все получится. Книжки можешь почитать, но это для общего развития. Ты больше узнаешь из практики, чем из книг.
Как же я обожаю этот тред. Тут самфые лучшие и добрые аноны сидят. Спасибо и сори за офф. Мимопроходил.
В универе ты эту практику всё равно не получишь, так что разницы не вижу
При чём тут биология за 11 класс? Чел спрашивал про азы программирования, а их, т.е. алгоритмы, структуры данных и прочее, как раз в этих книгах и можно найти (плюс еще пара книг по архитектуре, сетям, операционным системам и пр).
А дальше да, уже дело за практикой.
В медицине то же самое, ты можешь преспокойно учиться по книгам самостоятельно, но для того, чтобы стать хирургом, безусловно нужна практика.
Ты не опроверг мои слова.
Так я и не хотел опровергнуть, я хотел дать другую перспективу точки зрения. Ну и я сам прочитал овер 9000 книг, но на работу меня не брали пока не появилось более менее вменяемое портфолио и кое какой рассказ об участи в проектах. Никого не смутило что проэкты я сам для себя придумал и написал.
Потому что работодателю по большей части пофиг на твои знания, будь ты хоть ученым в области информатики. Он заинтересован только в том, сможешь ли ты выполнить свою работу или нет, сможет ли он на тебе заработать или нет.
В БД лежат категории и статьи, хочу выводить каскадом по 1 блоку с n-количеством статей своей категории, следующий блок новой категории уже идет справа, как на пикрелейтед.
Я, в принципе, знаю как это сделать, но без каскада, а просто циклом перебрать статьи по категориям из бд.
Можно запрашивать из бд четные категории влево, а нечетные вправо, но тогда как быть с блоками ?
Твои азазы, как мотематика, пригождаются, если ты илонмашк. Простому джуну в 99% они не нужны. А что нужно будет освоит в процессе.
Еще с осени не могу закончить))) Бросал раз 5.
За сколько часов такую задачу должен сделать джун?
1. Программирование наверное единственная профессия, где на образование смотря в последнюю очередь т.к. тут реально нужно уметь делать и это важно в первую очередь.
2. Образование может быть плюсом если ты нубяра полнейший. Друг учился, его взяли работать т.к. понимали, что он учится соответственно его нубство - явление временное и он развивается почучуть, а не забил хуй.
Кукареки про математику придумали долбоебы, которые никогда не работали, нахуй тебе ее знать, сука, объясни? Сам хоть понимаешь? Если конечно под знанием математики подразумевают умение сложить 2+2, то это везде надо уметь и только школьный довнич может назвать это "знанием математики", а не признаком недауна.
Необходимо понять, что человек не может знать все и ты не можешь заранее подготовиться, выучить все, что потребуется, прийти на работу и не столкнуться с трудностями. Везде свой стек, который ты просто не можешь знать заранее. Всегда будет ощущение, что ты нихуя не знаешь, всегда будут появляться ошибки, которые ты не сразу поймешь как исправить - ВСЕГДА. Однако, знать основы нужно конечно и уметь гуглить.
И самое главное - опыт, чем быстрее начнешь работать - тем лучше. Опытного человека всегда видно и всем похуй есть у него образование или нет, чем больше опыта тем более похуй тебе будет на образование и тем менее будет стоять вопрос "если уволят куда я пойду"
Ты лучше скожи когда оп придет...
>Куки же можно угнать у пользователя
Тоже хотелось бы узнать подробнее об этом вопросе
Куки можно угнать:
1. С помощью xss
Чтобы избежать этого нужно выводить все вводимые данные пользователем с помощью функции htmlspecialchars(...)
И, дополнительно, поставить кукисам параметр httpOnly
https://github.com/codedokode/pasta/blob/master/security/xss.md
https://secure.php.net/manual/en/function.htmlspecialchars.php
https://secure.php.net/manual/en/function.setcookie.php
https://en.wikipedia.org/wiki/Cross-site_scripting
2. Проведя атаку "Человек посередине"
Чтобы это избежать, нужно использовать зашифрованное соединение, например https
https://ru.wikipedia.org/wiki/Атака_посредника
3. Имея доступ к устройству пользователя
Так же, хотелось бы узнать, есть ли такой способ кражи, при переходе на посторонний сайт.
Почему бытует мнение, что переход по незнакомым ссылкам чревато? Посторонние сайты же не имеют доступа к кукам вне своего домена. И единственное чем может быть это полезно, это сбором информации о клиенте и его ip-адресе, а так же рамещением фейковой формы, для залогинивания, что, на мой взгляд, совершенно бесполезно.
>Куки же можно угнать у пользователя
Тоже хотелось бы узнать подробнее об этом вопросе
Куки можно угнать:
1. С помощью xss
Чтобы избежать этого нужно выводить все вводимые данные пользователем с помощью функции htmlspecialchars(...)
И, дополнительно, поставить кукисам параметр httpOnly
https://github.com/codedokode/pasta/blob/master/security/xss.md
https://secure.php.net/manual/en/function.htmlspecialchars.php
https://secure.php.net/manual/en/function.setcookie.php
https://en.wikipedia.org/wiki/Cross-site_scripting
2. Проведя атаку "Человек посередине"
Чтобы это избежать, нужно использовать зашифрованное соединение, например https
https://ru.wikipedia.org/wiki/Атака_посредника
3. Имея доступ к устройству пользователя
Так же, хотелось бы узнать, есть ли такой способ кражи, при переходе на посторонний сайт.
Почему бытует мнение, что переход по незнакомым ссылкам чревато? Посторонние сайты же не имеют доступа к кукам вне своего домена. И единственное чем может быть это полезно, это сбором информации о клиенте и его ip-адресе, а так же рамещением фейковой формы, для залогинивания, что, на мой взгляд, совершенно бесполезно.
>За сколько часов такую задачу должен сделать джун?
За 2-3 дня
Не не отчаивайся, я делал её 2 года https://github.com/someApprentice/Students/graphs/code-frequency
Зато сейчас могу решить её за сутки - полагаю, у каждого своя скорость
В задаче на хостинг файлов есть рекомендации на этот счет: https://gist.github.com/codedokode/9424217#Удобство-администрирования-сервера
Из бд запрашиваешь все нужные категории, а в представлении сортируешь и выводишь в блоки как тебе нужно
Например
<div class="content__left">
<? foreach($categories as $key => $category): ?>
<? if ($key % 2 == 1): ?>
...
<? endif; ?>
<? endforeach; ?>
</div>
<div class="content__right">
<? foreach($categories as $key => $category): ?>
<? if ($key % 2 == 0): ?>
...
<? endif; ?>
<? endforeach; ?>
</div>
Гугли как в php обрабатывать форму
В шапке есть урок на эту тему: https://github.com/codedokode/pasta/blob/master/forms.md
Понял, спасибо
А потом все это обернуть в цикл, что бы левый и правый блоки чередовало. Спасибо.
https://ideone.com/VM1bq4
Алсо, почему он из массива только цифры берет, и вообще берет не 5?
Алсо, насколько я понял, isset это не совсем то, что мне нужно для обработки нажатия. Что мне нужно?
братюнь, ты вот рекомендуешь котерова качать, мне интересно, а ты сам где работаешь? у тебя тимлид проводит код ревью? заставляет тесты писать?
После того, как сделал свою ссылку, делай рефреш страницы и всё.
P.S. Для шортлинкера лучше не использовать рандомные комбинации, а последовательно увеличивать последовательность символов.
>Алсо, почему он из массива только цифры берет, и вообще берет не 5?
Не знаю, но с версией PHP7.2.2 берётся именно 5 https://3v4l.org/J9BpQ#output
Должно быть, это как-то связано с этим https://secure.php.net/manual/ru/migration72.incompatible.php#migration72.incompatible.rand-mt_rand-output
>Алсо, насколько я понял, isset это не совсем то, что мне нужно для обработки нажатия. Что мне нужно?
Тебе нужно $_SERVER['REQUEST_METHOD'] == 'POST'
https://secure.php.net/manual/ru/reserved.variables.server.php
А почему ты сохраняешь не в базу данных, а в файлы? И тем более в php скрипты? Лучше было бы в .json - как раз конструкция ключ -> значение
К тому же, у тебя должен быть отдельный php скрипт, который берёт параметр $_GET с ключом к твоей ссылки, и делает редирект - никаких $_SERVER['SERVER_NAME'] делать не нужно (http://htmlbook.ru/samhtml/ssylki/absolyutnye-i-otnositelnye-ssylki):
/redirect.php?key=foo42
<?php
if (isset($_GET['key'])) {
$key = $_GET['key'];
// открываем файл $key.json
// парсим хэш
// делаем редирект
}
А на странице с формой всё делается ещё проще:
if (форма отправлена) {
// валидируем ссылку
// создаем массив [$key => $url]
// преобразуем его в json
// сохраняем json
// перенаправляем на страницу с результатом и выводим ссылку на redirect.php?key=$key
}
Так же не забывай, что если ты позволяешь пользоваться твоей программой посторонним, то тебе следует валидировать ссылки и экранировать их вывод
Функции которые тебе могут понадобиться:
https://secure.php.net/manual/ru/function.json-encode.php обрати внимание на опции JSON_HEX_ https://secure.php.net/manual/ru/json.constants.php
https://secure.php.net/manual/ru/function.json-decode.php
https://secure.php.net/manual/ru/function.htmlspecialchars.php
https://secure.php.net/manual/ru/function.fclose.php
>Алсо, почему он из массива только цифры берет, и вообще берет не 5?
Не знаю, но с версией PHP7.2.2 берётся именно 5 https://3v4l.org/J9BpQ#output
Должно быть, это как-то связано с этим https://secure.php.net/manual/ru/migration72.incompatible.php#migration72.incompatible.rand-mt_rand-output
>Алсо, насколько я понял, isset это не совсем то, что мне нужно для обработки нажатия. Что мне нужно?
Тебе нужно $_SERVER['REQUEST_METHOD'] == 'POST'
https://secure.php.net/manual/ru/reserved.variables.server.php
А почему ты сохраняешь не в базу данных, а в файлы? И тем более в php скрипты? Лучше было бы в .json - как раз конструкция ключ -> значение
К тому же, у тебя должен быть отдельный php скрипт, который берёт параметр $_GET с ключом к твоей ссылки, и делает редирект - никаких $_SERVER['SERVER_NAME'] делать не нужно (http://htmlbook.ru/samhtml/ssylki/absolyutnye-i-otnositelnye-ssylki):
/redirect.php?key=foo42
<?php
if (isset($_GET['key'])) {
$key = $_GET['key'];
// открываем файл $key.json
// парсим хэш
// делаем редирект
}
А на странице с формой всё делается ещё проще:
if (форма отправлена) {
// валидируем ссылку
// создаем массив [$key => $url]
// преобразуем его в json
// сохраняем json
// перенаправляем на страницу с результатом и выводим ссылку на redirect.php?key=$key
}
Так же не забывай, что если ты позволяешь пользоваться твоей программой посторонним, то тебе следует валидировать ссылки и экранировать их вывод
Функции которые тебе могут понадобиться:
https://secure.php.net/manual/ru/function.json-encode.php обрати внимание на опции JSON_HEX_ https://secure.php.net/manual/ru/json.constants.php
https://secure.php.net/manual/ru/function.json-decode.php
https://secure.php.net/manual/ru/function.htmlspecialchars.php
https://secure.php.net/manual/ru/function.fclose.php
Красиво конечно сделано. Приятно просматривать файлы, все понятно сразу что где куда. 2 года ты это постоянно делал или прерывался? Считаешь проект законченным?
У меня были большие перерывы в год и по полгода... Я не помню уже
Это был обучающий проект, поэтому, свою цель он выполнил - я научился обрабатывать формы и общей архитектуре приложений
Я не сделал ничего, я просто делал, что мне говорил ОП треда
Кури в сторону mb_ функций
Нихуя себе ты накатал.
> Не знаю, но с версией PHP7.2.2 берётся именно 5
У меня вообще была версия 5 почему-то в вампе, лол. Переключил на 7.1.9, все также.
> Должно быть, это как-то связано с этим https://secure.php.net/manual/ru/migration72.incompatible.php#migration72.incompatible.rand-mt_rand-output
Нихуя не понял, как это может быть связано с работой функции, которая рандомит элементы из массива.
> Тебе нужно $_SERVER['REQUEST_METHOD'] == 'POST'
Блядь, охуеть, а именно конкретного онклика нет? Язык-костыль.
> А почему ты сохраняешь не в базу данных, а в файлы? И тем более в php скрипты? Лучше было бы в .json - как раз конструкция ключ -> значение
Потому что я вчера впервые в жизни взялся за пхп. И бомбанул от костыльности.
За сим, нихуя из ниже слудующего не понял.
>>48973
> После того, как сделал свою ссылку, делай рефреш страницы и всё.
Так а зачем, если в рефреше и проблема? Если не рефрешить, кстати, а убрать слеш в конце ссылки и перейти, то все норм и ничего не создается.
> P.S. Для шортлинкера лучше не использовать рандомные комбинации, а последовательно увеличивать последовательность символов.
В смысле увеличивать последовательность символов? Чтобы после сотого раза у меня моя короткая ссылка была длиннее чем какой-нить запрос в гугл на русике?
Алсо, наоборот же. Потому что тогда юзеру можно будет смотреть че там другие юзеры делают.
Ты пиздец тупой, еще и быдлан, тебе уважаемый человек в треде отвечал вежливо, а ты хуйню несешь.
>В смысле увеличивать последовательность символов?
Если ты рандомишь, то есть шанс что ты зарандомишь под новый запрос такой же урл, который ты уже отдавал когда-то.
Поэтому если у тебя ссылки например были бы из цифр, то нельзя просто руярить случайное число /34533, /43234 /21387 ... /34533 - так по мере накопления у тебя будут тупо старые заменяться новыми и ты че совсем еблан рили?
/00001, /00002/, /00003, ... /99999 - все урлы равномерно заполнят все возможные комбинации чисел без пробелов и перезатираний.
https://ideone.com/8twAif
У тебя функции pad% не объявлены.
> Ты пиздец тупой, еще и быдлан, тебе уважаемый человек в треде отвечал вежливо, а ты хуйню несешь.
Лол, блядь. Быдлан я, охуеть. В треде про быдлоязык.
> Если ты рандомишь, то есть шанс что ты зарандомишь под новый запрос такой же урл, который ты уже отдавал когда-то.
Я написал про это под спойлером, васька сможет смотреть другие ссылки уменьшая число, а это как-то не комильфо. Я думаю 5-разрядного даже 16-ричного числа хватит чтобы нивелировать шанс перезаписи с лихвой, а ведь туда можно еще буков добавить. Да и вообще, можно просто сделать проверку на существование файла.
А как пофиксить кривой рандом так никто и не сказал.
> А как пофиксить кривой рандом так никто и не сказал
Все, я уже сам нагуглил, охуеть. Оказывается array_rand возвращает ключи, а не значения.
>В смысле увеличивать последовательность символов
Возможно не совсем правильно выразился. Смотри.
Первая ссылка будет такой: shrt.er/0, вторая shrt.er/1, потом цифры закончатся и ты переходишь на буквы:
shrt.er/A
shrt.er/B
...
shrt.er/z
Потом добавляешь второй символ и всё заново:
shrt.er/00
shrt.er/01
...
shrt.er/zz
Ну и так далее.
Я сам делал шортенер с телеграм ботом даже, со статистикой переходов по странам,
времени и прочему, но это очень тупой проект, ибо сервисов дохуя и новый никому не встрался.
Вопрос актуальный, т.к. учусь в Беларуси и попадаю на распределение, поменять место работы или стек не получится.
Пыха стронг.
>В треде про быдлоязык.
>Я думаю 5-разрядного даже 16-ричного числа хватит чтобы нивелировать шанс перезаписи с лихвой
Поссал на лицо смачно.
https://habrahabr.ru/post/333398/
Почему я ушёл из Google и начал работать на себя
https://m.habrahabr.ru/post/350374/
Ведь так сложно убрать два символа, да?
Я раньше не замечал, что можно перечислять любое количество переменных для функции или что-то делаю неправильно?
Почему так, анон?
https://3v4l.org/6lVfP
Можно, но ты делаешь это не правильно.
Вот ссылка на мануал: https://secure.php.net/manual/ru/functions.arguments.php#functions.variable-arg-list
Я не это имел в виду. Можно ли ограничить количество переменных для функции, чтобы, если передаётся больше указанных, то выводилась ошибка?
значит что нельзя иметь доступ к базе под этим пользователем. Там же разгараничения могут быть что под каждую базу свой юзер выделен. Что бы если спиздят пароли от одного лендоса, то другие не положили заодно например.
>>48424
>>49203
> public function addNewRoom($number) {
Здесь в номерах не указываются их параметры (цена, вместимость).
> public function settleGuest($room_id, $guest_id) {
> $rooms[$room_id]->setGuest($guest);
Зачем тут id? Где их брать? У нас же есть объекты. id нужны только для баз данных, тут можно обойтись без них.
Также, заселение придется сделать чуть сложнее. Нам ведь надо вести историю: кто, когда, где останавливался.
А так, начал в правильном направлении. Спрашивай, если что непонятно.
>Оказывается array_rand возвращает ключи, а не значения.
Ну как-бы у ОПа в гайде всё написано же.
>быдлоязык.
Вот это заявления. Оказывается в том что ты что-то не понимаешь язык виноват, а не ты. Ну хорошо.
>почему он из массива только цифры берет, и вообще берет не 5?
А ты из массива и не берёшь ничего, только рандомируешь его ключи, а не элементы массива.
> берет не 5?
Так счёт идет от нуля. 0, 1, 2, 3, 4, 5. То-есть 6 элементов.
> isset это не совсем то, что мне нужно для обработки нажатия. Что мне нужно?
Почему нет то?
Смирись, лучше Котерова никто книгу не написал. Остальные книги настолько плохи что даже для обучения не подходят. К тому-же спорить о стиле кода в 2018, когда всё форматируется под любой стандарт нажатием сочетания клавиш?
Да, можно передать больше, чем надо. Проверить точное количество можно функциями func_num_args() и func_get_args().
>>49481
Нужно заходить в БД с логином и паролем. Если пользователей нет - с логином админа, но на продакшене желательно для каждого сайта создать своего пользователя с доступом только к одной базе данных.
>>49380
Через if + func_num_args.
>>49332
Если ты ищешь работу, почему бы не пройти по сайтам вакансий вроде hh.ru и не посмотреть требования?
>>49230
Зайди на сайт вакансий и посмотри.
>>49168
Эти функции надо написать самому. Они добивают строку пробелами слева или справа до заданной длины. Пишутся с mb_strlen + str_repeat.
>>49345
Смотри сайты вакансий.
>>49167
Используй события вроде hover/mouseenter. На каждую ссылку ставить обработчик замучаешься, потому можно поставить один глобальный на документ с фильтром по классу/тегу ($.on). В случае наведения мыши показываем прелоадер, запускаем загрузку данных. Когда загрузятся - создаем абс. поз. относительно родителя див с нужным нам смещением и в него вставляем HTML код поста.
При уведении мыши все происходит в обратном порядке, див скрывается, загрузку можно отменять, если она началась.
Что именно непонятно?
Да, можно передать больше, чем надо. Проверить точное количество можно функциями func_num_args() и func_get_args().
>>49481
Нужно заходить в БД с логином и паролем. Если пользователей нет - с логином админа, но на продакшене желательно для каждого сайта создать своего пользователя с доступом только к одной базе данных.
>>49380
Через if + func_num_args.
>>49332
Если ты ищешь работу, почему бы не пройти по сайтам вакансий вроде hh.ru и не посмотреть требования?
>>49230
Зайди на сайт вакансий и посмотри.
>>49168
Эти функции надо написать самому. Они добивают строку пробелами слева или справа до заданной длины. Пишутся с mb_strlen + str_repeat.
>>49345
Смотри сайты вакансий.
>>49167
Используй события вроде hover/mouseenter. На каждую ссылку ставить обработчик замучаешься, потому можно поставить один глобальный на документ с фильтром по классу/тегу ($.on). В случае наведения мыши показываем прелоадер, запускаем загрузку данных. Когда загрузятся - создаем абс. поз. относительно родителя див с нужным нам смещением и в него вставляем HTML код поста.
При уведении мыши все происходит в обратном порядке, див скрывается, загрузку можно отменять, если она началась.
Что именно непонятно?
> конкретного онклика нет?
onclick - это атрибут элемента DOM. На сервере никакого DOM нет, никаких нажатий нет, на сервер просто приходит HTTP-запрос и никакого "онклика" быть в принципе не может.
>>49038
Нету. Нужно это прописывать вручную в стиле "здесь может быть буква д или d, за ней у кириллицей или y латиницей".
>>48818
После успешной обработки POST запроса и создания новой ссылки надо делать редирект, чтобы страница загрузилась методом GET. Это называется POST-Redirect-GET: https://ru.wikipedia.org/wiki/Post/Redirect/Get
Работа с формами описана у меня в уроке https://github.com/codedokode/pasta/blob/master/forms.md
>>48916
Не надо создавать кучу PHP файлов. Ты скорее всего думаешь, что веб-сервер всегда ищет тот файл, который указан в URL. Но это можно настроить как угодно, например, чтобы всегда бы вызывался один и тот же скрипт index.php и уже в нем разбирался URL. Как именно это делать - зависит от используемого веб-сервера, в каждом по-разному. В апаче через htaccess и mod_rewrite, в встроенном в PHP веб-сервере через скрипт роутинга, в nginx через конфиг.
Обычно используют базу данных. Если неохота задействовать отдельную СУБД, можно использовать Sqlite, которая хранит таблицы в файлах.
При вставке в БД можно проверить, не занят ли нужный идентификатор, а также можно автоматически генерировать порядковые номера.
Если ты хочешь лучше научиться делать такие вещи, я советую посмотреть первый пост треда и задачу про студентов - в ней много комментариев и она учит как раз, как писать приложения с формами и таблицами.
В JSON не лучше. Не стоит изобретать велосипед, когда есть:
- примитивные файловые key-value БД вроде BerkeleyDB и ее наледников
- файловая SQL БД Sqlite
- отдельные SQL СУБД вроде Postgres и MySQL
>>47404
А что значит "выбирался"? Просто select со списком документов не подойдет? Или тебе надо поле для загрузки файла? Изучи, какие поля есть в HTML формах.
>>48575
Может официальный мануал? http://php.net/manual/ru/index.php
>>48490
Наверно имеет смысл для каждого треда делать свою папку - проще будет например удалять или архивировать или еще что-нибудь делать. Если несколько разделов, то можно еще для каждого раздела свою папку тоже.
>>48841
Просто так куки угнать нельзя. Куки отдаются только тому сайту (домену), который их выставил. Но дальше начинаются интересные варианты.
Ну например, атака на DNS: злодей взламывает твой роутер (а китайские роутеры очень дырявы) и перехватывает DNS запросы, чтобы сайту example.com соответствовал бы их сервер и твой браузер бы отправлял куки туда. Защита: использование HTTPS, установка флага secure у кук, чтобы их не отдавало по HTTP.
Или социнженерия: отправляем письмо с просьбой посмотреть документ info.doc.____________.exe.
> Так же, хотелось бы узнать, есть ли такой способ кражи, при переходе на посторонний сайт.
Нет при условии отсутствия уязвимостей в браузере и ОС.
> переход по незнакомым ссылкам чревато?
Потому, что браузеры и ОС не идеальные и в них могут быть уязвимости, которые позволяют запустить вредоносный код на машине или обойти ограничения. Но если ты обновляешь браузер и ОС, не используешь флеш, Adobe Reader и ява-плагин и используешь браузер с печочницой (вроде Chrome), то вероятность этого не велика. Так как уязвимости такого уровня стоят десятки тыс. долл. и вряд ли кто-то ради протроянивания твоего пк будет столько тратить. Если ты конечно не связан с военными тайнами какими-нибудь.
Регулярно проводится конкурс pwn2own на взлом браузеров (запуск вредоносного кода при посещении сайта). Ты можешь по призовым выплатам оценить, насколько сложен взлом: https://habrahabr.ru/company/kingservers/blog/324480/
Часто ломают не сами браузеры, а плагины, в которых защита слабее: флеш много раз ломали, adobe reader, ява-плагин. Потому Гугл пытается поскорее вытеснить флеш и использует свой просмотрщик для PDF. Ломают через офисные приложения (Word, Excel). Так как их разработчики не выстраивают такую надежную защиту, как Гугл, а иногда делают откровенное решето (макросы в офисных приложениях). Также, были случаи, когда ломали браузер за счет уязвимости в виндовой библиотеке, отвечающей за вывод шрифтов - Хром по моему позже от нее отказался.
> Браузер Safari поддался участникам соревнования четыре раза, Firefox — один раз, Google Chrome взломать пытались, но не хватило времени.
А раньше по моему взламывали.
> а так же рамещением фейковой формы, для залогинивания, что, на мой взгляд, совершенно бесполезно.
Вообще-то через фейковые формы входа в Гугл-аккаунт была взломана какая-то американская партия и они очень обиделись. Фишинг работает, и еще как. Потому что пароли довольно неудобная и ненадежная система, в адресную строку никто не смотрит, плюс браузеры пишут там "Надежный" при наличии HTTPS, вводя пользователя в заблуждение. Я сторонник аппаратных ключей, которые можно носить с собой. Хотя, конечно, их можно отобрать силой.
В JSON не лучше. Не стоит изобретать велосипед, когда есть:
- примитивные файловые key-value БД вроде BerkeleyDB и ее наледников
- файловая SQL БД Sqlite
- отдельные SQL СУБД вроде Postgres и MySQL
>>47404
А что значит "выбирался"? Просто select со списком документов не подойдет? Или тебе надо поле для загрузки файла? Изучи, какие поля есть в HTML формах.
>>48575
Может официальный мануал? http://php.net/manual/ru/index.php
>>48490
Наверно имеет смысл для каждого треда делать свою папку - проще будет например удалять или архивировать или еще что-нибудь делать. Если несколько разделов, то можно еще для каждого раздела свою папку тоже.
>>48841
Просто так куки угнать нельзя. Куки отдаются только тому сайту (домену), который их выставил. Но дальше начинаются интересные варианты.
Ну например, атака на DNS: злодей взламывает твой роутер (а китайские роутеры очень дырявы) и перехватывает DNS запросы, чтобы сайту example.com соответствовал бы их сервер и твой браузер бы отправлял куки туда. Защита: использование HTTPS, установка флага secure у кук, чтобы их не отдавало по HTTP.
Или социнженерия: отправляем письмо с просьбой посмотреть документ info.doc.____________.exe.
> Так же, хотелось бы узнать, есть ли такой способ кражи, при переходе на посторонний сайт.
Нет при условии отсутствия уязвимостей в браузере и ОС.
> переход по незнакомым ссылкам чревато?
Потому, что браузеры и ОС не идеальные и в них могут быть уязвимости, которые позволяют запустить вредоносный код на машине или обойти ограничения. Но если ты обновляешь браузер и ОС, не используешь флеш, Adobe Reader и ява-плагин и используешь браузер с печочницой (вроде Chrome), то вероятность этого не велика. Так как уязвимости такого уровня стоят десятки тыс. долл. и вряд ли кто-то ради протроянивания твоего пк будет столько тратить. Если ты конечно не связан с военными тайнами какими-нибудь.
Регулярно проводится конкурс pwn2own на взлом браузеров (запуск вредоносного кода при посещении сайта). Ты можешь по призовым выплатам оценить, насколько сложен взлом: https://habrahabr.ru/company/kingservers/blog/324480/
Часто ломают не сами браузеры, а плагины, в которых защита слабее: флеш много раз ломали, adobe reader, ява-плагин. Потому Гугл пытается поскорее вытеснить флеш и использует свой просмотрщик для PDF. Ломают через офисные приложения (Word, Excel). Так как их разработчики не выстраивают такую надежную защиту, как Гугл, а иногда делают откровенное решето (макросы в офисных приложениях). Также, были случаи, когда ломали браузер за счет уязвимости в виндовой библиотеке, отвечающей за вывод шрифтов - Хром по моему позже от нее отказался.
> Браузер Safari поддался участникам соревнования четыре раза, Firefox — один раз, Google Chrome взломать пытались, но не хватило времени.
А раньше по моему взламывали.
> а так же рамещением фейковой формы, для залогинивания, что, на мой взгляд, совершенно бесполезно.
Вообще-то через фейковые формы входа в Гугл-аккаунт была взломана какая-то американская партия и они очень обиделись. Фишинг работает, и еще как. Потому что пароли довольно неудобная и ненадежная система, в адресную строку никто не смотрит, плюс браузеры пишут там "Надежный" при наличии HTTPS, вводя пользователя в заблуждение. Я сторонник аппаратных ключей, которые можно носить с собой. Хотя, конечно, их можно отобрать силой.
Безопасна. Куки угнать можно только при наличии уязвимостей.
>>48069
Потому что видимо сначала PHP парсит файл, создает функции, а потом только выполняет код. В JS по моему так же.
http://php.net/manual/ru/functions.user-defined.php
> Функции не обязаны быть определены до их использования, исключая тот случай, когда функции определяются условно, как это показано в двух последующих примерах.
>>48151
Тут есть паста, но не уверен, что она хорошо объяснит: https://gist.github.com/codedokode/ffd520440a970c07c1c6 - про асинхронность в конце.
Это такой подход, когда мы просим ОС начать выполнять операцию и не ждем, пока она завершится, а делаем в этом время другие вещи.
Желательно понимать что такое процессы, ядро ОС и тд. То есть изучить основы линукса и может быть сетевого программирования (Сокеты Беркли, TCP, UDP) не помешало бы, иначе можно так и не понять многое.
>>43562
У нас не очень торопливый тред, ты бампай если несколько дней прошло без ответа. Ну и решай дальше.
Верно
Правильно
На кубике не может выпасть 0, нижний предел должен быть 1
exit не требуется. В последнем условии можно вместо elseif(...) писать просто else без условий. А так, верно.
Ну ок, верно.
bankPercent никак не используется, но ответ получается верный.
Как-то многовато кода для такой задачи. Тяжело разбираться. Ответ верный, но решение можно сильно упростить.
Ну например, так:
- вычисляем баланс с добавлением процентов и коммиссии
- определяем, сколько мы платим в этом месяце (используя min()/max()) и кладем в переменную
- платим
- если дошли до нуля - кредит выплачен
Верно
Верно
Ок, верно
Правильно
Вроде как работает, но есть одна проблема. Символы, которые ты используешь, я не очень хорошо знаю (да и ты наверно тоже) и есть вероятность, что где-то там ты мог использовать один и тот же символ для нескольких букв. Легко ведь не заметить. Можешь ли ты программно проверить - все ли символы уникальные или среди них есть 2 одинаковых?
>>43562
У нас не очень торопливый тред, ты бампай если несколько дней прошло без ответа. Ну и решай дальше.
Верно
Правильно
На кубике не может выпасть 0, нижний предел должен быть 1
exit не требуется. В последнем условии можно вместо elseif(...) писать просто else без условий. А так, верно.
Ну ок, верно.
bankPercent никак не используется, но ответ получается верный.
Как-то многовато кода для такой задачи. Тяжело разбираться. Ответ верный, но решение можно сильно упростить.
Ну например, так:
- вычисляем баланс с добавлением процентов и коммиссии
- определяем, сколько мы платим в этом месяце (используя min()/max()) и кладем в переменную
- платим
- если дошли до нуля - кредит выплачен
Верно
Верно
Ок, верно
Правильно
Вроде как работает, но есть одна проблема. Символы, которые ты используешь, я не очень хорошо знаю (да и ты наверно тоже) и есть вероятность, что где-то там ты мог использовать один и тот же символ для нескольких букв. Легко ведь не заметить. Можешь ли ты программно проверить - все ли символы уникальные или среди них есть 2 одинаковых?
Оба верные.
Вообще, во втором решении можно было сделать цикл из 2 шагов, а после него - отдельно сделать вывод третьей строки. В цикл надо помещать только действия, которые повторяются, а последняя строка не повторяется.
Сложно выглядит код наверно из-за длинных выражений вроде $line[$i] = $word1[array_rand($word1) ]....
Лучше это выражение разбить на части покороче:
$part1 = $word1[array_rand($word1)];
$part2 = ...
...
echo $part1 . ' ' . $part2....;
И вместо массива $line сразу использовать echo.
> for ($i = 1; ; $i++) {
Цикл с явным указанием числа повторений гораздо понятнее.
Но это хорошо, что ты замечаешь, что код плохо выглядит.
>>46883
> Почитал про джойны, примеры работают, а как их к этой базе применить не доходит.
Если тебе нужно объединить в одну строчку данные из 2 таблиц или искать что-то в 2 таблицах сразу - используешь джойн. Джойн по умолчанию создает декартово произведение строчек (очень много строк), потому обычно сразу же в нем пишут условие отбора строчек.
Почти все задачи на SQL решаются именно через джойн + иногда группировка.
> Еще внешние ключи ну никак не могу понять,
Если в таблице стоит ссылка на ячейку другой таблицы, то это внешний ключ. Вот и все. Где и как ставится внешний ключ, зависит от типа связи. Их там всего несколько - 1:1, 1:M и M:N. И еще вариации, например, бывает связь 1:M, а бывает [0, 1]:M. То есть левая сущность может быть обязательной, а может и нет.
Ты определяешь тип связи между сущностями, и исходя из этого, создаешь внешние ключи.
Вот тут неплохо объясняются типы связей, джойны и внешние ключи: http://jtest.ru/bazyi-dannyix/sql-dlya-nachinayushhix-chast-3.html
По схеме БД: процедуры (в receptions) придется в будущем всего выносить в отдельную таблицу. У них могут быть свои какие-то атрибуты, цены и тд.
Также, у тебя есть избыточные связи. Например, в receptions приписан owner. Если pay_ticket привязан к reception, то owner в нем не лишний ли? Да и если еще подумать, может быть счет логично выписывать на животное, а не на конкретного владельца? Их ведь там несколько.
То же самое касается поля employee. Хотя конечно бухгалтерия дело сложное, и может там счет выписывает другой сотрудник?
Также, насчет именования таблиц/полей, советовал бы гайд http://www.sqlstyle.guide/ru/
Насчет связи между receptions и pets - а не может хозяин придти без животного? На консультацию например? Это учтено?
Насчет связи между receptions и pay_tickets - мне кажется, должно быть связь 1 receptions - (0..N) pay_tickets. То есть по итогам приема может быть выписано сколько угодно счетов (инвойсов?).
Связь между prescriptions и pay_tickets - я не уверен, что она нужна. Разве выдача рецепта как-то связана с оплатой? Вполне возможно, что врач решил выписать рецепт бесплатно.
Насчет правой части - где учет медикаментов - я не очень понял, что там к чему. Почему и как запись в журнале расхода медикаментов связана с записью в журнале прихода.
> Еще внешние ключи ну никак не могу понять, я вот их наставил тут, но походу немного далеко уехал с ними.
Ты определеяешь связи между сущностями, и исходя из них ставишь внешние ключи. То есть сначала определи, что с чем связано и как.
> Почитал про джойны, примеры работают, а как их к этой базе применить не доходит.
Ну простой пример: вывести дату приема и имя животного на приеме:
SELECT r.date, p.name FROM receptions r JOIN pets p ON p.id = r.pet;
Почитай статью выше.
Оба верные.
Вообще, во втором решении можно было сделать цикл из 2 шагов, а после него - отдельно сделать вывод третьей строки. В цикл надо помещать только действия, которые повторяются, а последняя строка не повторяется.
Сложно выглядит код наверно из-за длинных выражений вроде $line[$i] = $word1[array_rand($word1) ]....
Лучше это выражение разбить на части покороче:
$part1 = $word1[array_rand($word1)];
$part2 = ...
...
echo $part1 . ' ' . $part2....;
И вместо массива $line сразу использовать echo.
> for ($i = 1; ; $i++) {
Цикл с явным указанием числа повторений гораздо понятнее.
Но это хорошо, что ты замечаешь, что код плохо выглядит.
>>46883
> Почитал про джойны, примеры работают, а как их к этой базе применить не доходит.
Если тебе нужно объединить в одну строчку данные из 2 таблиц или искать что-то в 2 таблицах сразу - используешь джойн. Джойн по умолчанию создает декартово произведение строчек (очень много строк), потому обычно сразу же в нем пишут условие отбора строчек.
Почти все задачи на SQL решаются именно через джойн + иногда группировка.
> Еще внешние ключи ну никак не могу понять,
Если в таблице стоит ссылка на ячейку другой таблицы, то это внешний ключ. Вот и все. Где и как ставится внешний ключ, зависит от типа связи. Их там всего несколько - 1:1, 1:M и M:N. И еще вариации, например, бывает связь 1:M, а бывает [0, 1]:M. То есть левая сущность может быть обязательной, а может и нет.
Ты определяешь тип связи между сущностями, и исходя из этого, создаешь внешние ключи.
Вот тут неплохо объясняются типы связей, джойны и внешние ключи: http://jtest.ru/bazyi-dannyix/sql-dlya-nachinayushhix-chast-3.html
По схеме БД: процедуры (в receptions) придется в будущем всего выносить в отдельную таблицу. У них могут быть свои какие-то атрибуты, цены и тд.
Также, у тебя есть избыточные связи. Например, в receptions приписан owner. Если pay_ticket привязан к reception, то owner в нем не лишний ли? Да и если еще подумать, может быть счет логично выписывать на животное, а не на конкретного владельца? Их ведь там несколько.
То же самое касается поля employee. Хотя конечно бухгалтерия дело сложное, и может там счет выписывает другой сотрудник?
Также, насчет именования таблиц/полей, советовал бы гайд http://www.sqlstyle.guide/ru/
Насчет связи между receptions и pets - а не может хозяин придти без животного? На консультацию например? Это учтено?
Насчет связи между receptions и pay_tickets - мне кажется, должно быть связь 1 receptions - (0..N) pay_tickets. То есть по итогам приема может быть выписано сколько угодно счетов (инвойсов?).
Связь между prescriptions и pay_tickets - я не уверен, что она нужна. Разве выдача рецепта как-то связана с оплатой? Вполне возможно, что врач решил выписать рецепт бесплатно.
Насчет правой части - где учет медикаментов - я не очень понял, что там к чему. Почему и как запись в журнале расхода медикаментов связана с записью в журнале прихода.
> Еще внешние ключи ну никак не могу понять, я вот их наставил тут, но походу немного далеко уехал с ними.
Ты определеяешь связи между сущностями, и исходя из них ставишь внешние ключи. То есть сначала определи, что с чем связано и как.
> Почитал про джойны, примеры работают, а как их к этой базе применить не доходит.
Ну простой пример: вывести дату приема и имя животного на приеме:
SELECT r.date, p.name FROM receptions r JOIN pets p ON p.id = r.pet;
Почитай статью выше.
У меня есть подозрение, что во-первых, не везде это работает, во-вторых, затраты времени на запаковку могут быть больше чем затраты на передачу данных. Плюс, это потом распаковывать надо. Плюс, многие типы файлов - картинки, аудио, видео - не пакуются дальше, они и так сжатые.
У той же mega.nz "толстый" фронтенд и она субъективно очень тормозная и сильно грузит процессор.
Еще при проектировании БД стоит следовать принципам нормализации. Если ты с ними не знаком, то у меня тут относительно несложно идет объяснение: https://github.com/codedokode/pasta/blob/master/db/normalization.md
это может и так, но ты ответь на вопрос, ты в конторе работаешь? пишешь поддерживаемый код? есть код-ревью? у вас такой код, который пишет котеров, пропустили бы?
речь не про psr. просто в любой нормальной фирме за такой код тебя сразу отправят в бухгалтерию забирать документы.
>в любой нормальной фирме за такой код тебя сразу отправят в бухгалтерию забирать документы.
За какой такой то? Почему Котерова не попросили забрать документы тогда? Он книги пишет, но видимо анону с двачей виднее каким должен быть код конечно же.
К тому-же он обьясняет и учит как применять то или иное, а не говорит мол пиши как я и только как я. У меня например не возникло сложностей интерпретировать его код. Почему у тебя такие сложности должны возникнуть?
>Зачем тут id?
Я вот тут запнулся, мне надо придумать какой нибудь хэш для комнаты(он же идентификатор), но по идее идентификатор комнаты ее номер.
А вот по поводу гостя, какой идентификатор добавить?
Если сделать идентификатором пользователя имя и фамилию и использовать как ключ для доступа поля в массиве?
Историю клиента я планирую хранить отдельно для номера, отдельно для клиента.
Хотя может это не имеет смысла, потому что история заселения это сущность отеля, и хранить надо в отеле? Например создать класс HotelLog, который будет содержать в себе информацию о дате заселения, номере и посетителе. А в классе отель создать приватный параметр массив содержащий в себе эти логи. Какой из этих вариантов лучше выбрать?
Еще мне очень интересно как на это все добавить тестов или вообще в идеале делать по тдд, если это конечно возможно?
Имя + Фамилия могут повторяться. Например в соседние комнаты заселятся отец и сын Петровы, оба Иваны.
Вопрос ОП-у: что нужно делать первее — придумать сущности в PHP или структуру базы данных продумать?
>тебя сразу отправят в бухгалтерию забирать документы.
Брр, от тебя повеяло совком каким то, ты на заводе каком то работаешь наверно или тебе лет 50, угадал?
>но видимо анону с двачей виднее каким должен быть код конечно же
видимо да, лол. любой анон, имеющий опыт написания промышленного поддерживаемого кода, будет более компетентным, чем котеров с его миллионом книг по пхп4.
ты так говоришь, как будто для тебя является новостью, что часто люди, не добившиеся успехов в программировании, начинают стричь бабло с новичков, называя это обучением. котеров выезжает исключительно на том, что он начинал первым.
опять же, я на самом деле не против таких советов. чем больше людей будут учиться по котерову, тем проще будет вменяемым программистам устроиться на нормальную работу.
>>49602
нет, контора в дс, удаленка, просто официальное трудоустройство. ты когда начнешь работать, узнаешь, как происходит процесс трудоустройства и тогда все встанет на свои места.
мне 30, если тебе так важно.
Короче ответов от тебя нет вообще никаких. Конкретики нет, одна обобщённая критика, причём ещё и PHP4, хотя у Котерова по 7 версии книга есть таки.
>любой анон, имеющий опыт написания промышленного поддерживаемого кода, будет более компетентным, чем котеров с его миллионом книг по пхп4.
Окей спорить не буду. Назови Другую книгу по PHP7?
>Конкретики нет
я в прошлых тредах (98 или 97) подробно разбирал какой-то кусок его кода примеров к какой-то книге как раз по пхп7. немного лень искать, можешь это сделать сам по слову "котеров" в архиваче
>причём ещё и PHP4, хотя у Котерова по 7 версии книга есть таки
это ирония была. у него книги по пхп7, а код как на пхп4 (опять же, я приводил примеры с каким-то минимальным разбором почему так неправильно и как надо)
>Назови Другую книгу по PHP7
книг "с нуля" нет. к сожалению, из-за исторических особенностей развития пхп, на нем основная масса книг учат писать html и sql-запросы в одном файле, что раньше считалось нормальным (и за что пхп справделиво считали языком веб-макак). язык и сообщество развились, но книги почему-то не подвезли.
если тебе нужны именно книги, то есть очень урезанная адаптация книги clean code роберта мартина https://github.com/jupeter/clean-code-php хотя я рекомендую читать ее оригинал на джаве. еще есть http://www.phptherightway.com/ ну и мануал.
>Конкретики нет, одна обобщённая критика
вот, не поленился и нашел:
https://phpclub.tech/pr/res/1109863.html#1114606
https://phpclub.tech/pr/res/1109863.html#1114646
Спасибо анон
> post-redirect-get
Спасибо, но я уже пофиксил это с помощью ajax'a. Теперь-то и выглядит это все не так костыльно, ты лично посылаешь запрос скрипту на серв, и лично получаешь и обрабатываешь от него ответ.
>>49525
Счет идет от нуля, а параметр отвечает за количество. Впрочем, неважно, когда я переделал код под возвращаемый массив с индексами, все заработало как надо.
> почему нет
В гугле написано, насколько я помню, что это проверяет, объявлена ли переменная. Не, ну оно и подходит, в принципе.
>>49523
Быдлоязык - потому что в него вкатывается всякое быдло ради 300кк/нсек(особенно в треде на мейлаче), а еще потому, что у меня бомбануло, он слишком не похож на другие нормальные языки, где берешь, и без задней мысли делаешь, а здесь какой-то пердолинг. И еще все эти долларчики, блядь, аж трясет от них.
Были бы халявные хосты с питоном или нодой, я бы туда убежал за милую душу.
>потому что в него вкатывается всякое быдло ради 300кк/нсек
исторически так сложилось, что да. например, ты
>он слишком не похож на другие нормальные языки
конкретнее, пожалуйста. можно недостатки языка по пунктам? про долларчики это не аргумент, а вкусовщина.
>Были бы халявные хосты с питоном или нодой
шта? 5 долларов в месяц за свой впс с нужным окружением для программиста на нормальных языках слишком серьезная сумма?
Похоже, что это почётное звание перешло к js. В моём окружении таким языком вообще Java является. Но стартанул я не очень, потом перескочил на что было.
К языку нет претензий - седьмой пых очень приятный.
белорус-на-распреде
https://ideone.com/PwMKoy
Если ты используешь аякс - проверь, выполнены ли рекомендации по правильной работе с аяксом: https://github.com/codedokode/pasta/blob/master/js/ajax.md
Ну впрочем старожилов веба этим не удивишь, "фронтенд специалисты" постоянно радуют нас своими нездоровыми придумками.
Критикуя - предлагай, скажет читатель. Предлагаю: не можете сделать хорошо, делайте просто черный текст на белом фоне. Вы удивитесь, насколько это прекрасный дизайн.
>error_reporting
Вот эта претензия меня всегда смущала, потому-что в других языках если я получаю ошибку, - по факту я либо кладу весь сайт! Либо весь сервис! ДЛЯ ВСЕХ ЮЗЕРОВ! (Привет ASP). Для тех кто в танке. Представьте что у одного юзера вкмылору произошла ошибка получения доступа к бд например. И из-за этого ВК лёг у всех. Удобно да? Поэтому говорить о том что это минус ну ооооочень странно. Да и настраивать error_reporting учат раньше чем Hello world писать.
>Сам он настолько экзотичный, что я скорее отнес бы php к эзотерическим языкам программирования и поставил где-нибудь рядом с HOtMEfSPRIbNG.
Дальше можно не читать. Как вообще можно воспринимать человека всерьёз, если он по факту не знаком с целым семейством языков? Я вообще в шоке. Синтаксис похож вообще на всё что я знаю, разьве что кроме JS. И говорить что PHP экзотический? Либо толстота, либо крайне скудный опыт в ЯП.
Руби помер 10 месяцев как. Да и вообще язык одного фрэймворка (Rails). Который за всю историю своего развития получил тонны похвал, тонны хвалебных статей, тонны упоминаний в IT сообществе и вообще язык хайп и чуть ли не идеальный язык программирования, но при этом худо бедно можно наскрести 2-3 приложения которые на нём действительно написаны.
Сорян за оффтоп. ПРосто я реально не понимаю зачем нужен руби.
Летом проходили сборы всяких хакатонов, и прочих набегов где обсуждаются языки программирования и прочее. Выяснилось что на мероприятия с руби в залах собирается по 5-10 человек, редко 40. Когда на аналогичные мероприятия собираются 1000-1200. Ну как-бы "At this moment Jonny knew - he fucked up."
Ну эзотерика здесь скорее понимается не в плане синтаксиса, а в кучу мелочей в семантике, которые потом описаны.
error_reporting это вредная и плохая идея. Если произошла ошибка - надо прекращать обработку запроса и отдавать 5xx.
Также, весь сайт не упадет, а ошибку получит только тот, у кого она произошла.
Скрытие ошибок ни к чему хорошему не приведет, их просто будет труднее заметить.
В PHP много плохого, это да. Синтаксис страшный, да. Работа с ошибками сломана безнадежно. Но есть и хорошее: тайп-хинты (ну-ка, покажите мне тайп-хинты в Руби, Питоне или JS), классы как в Яве (покажите мне классы в JS). Есть HHVM. В отличие от JS есть поддержка тредов.
Вообще, у разных языков свои сильные и слабые стороны. Мне нравится в плане возможностей Java и C#, они с типизацией, с классами и компилируются (хорошая производительность). Но в плане установки и использования они не такие простые как PHP, и Симфони там нету.
Плюсами PHP считается наличие большого числа разных CMS например. Тот же Вордпресс. Покажите мне вордпресс на JS.
Также, PHP очень просто в использовании. Пишешь файл 1.php, запускаешь встроенный веб-сервер - страница готова. Попробуйте сделать то же в Руби, Питоне, JS без поиска нужных библиотек.
> 1. Настройка и установка php - это весьма своеобразная история.
Набрать команду apt-get install php - это своеобразная история? Давайте посмотрим на Питон, где инструкция по установке почти любого приложения начинается с установки одного пакетного менеджера через другой. И с освоения virtualenv.
> То, где может искаться php.ini - это целый здоровый список в документации с целой кучей вариантов в зависимости от ОС и сервера.
Можно набрать php -i и посмотреть.
> Сюда же идёт тот факт, что php всегда намертво связано с веб-сервером и не может толком использоваться вне его
Может, хотя не очень понятно, зачем.
> что интерпретатор в общем случае живет в рамках одного http запроса.
И это очень полезная фича. Вообще, PHP можно запускать так, чтобы он обрабатывал много запросов не перезапускаясь (как Руби, Питон итд), и экономить на инициализации приложения, но тут есть свои подвохи. Ну например, я читал, что у людей в Руби утекала память и они не нашли ничего лучше как по крону прибивать и перезапускать приложение.
> Зачем-то в динамический язык скопировали ООП из джавы.
> Зачем, почему, непонятно
Потому, что в Яве прекрасный ООП, в отличие от других языков.
> Долгое время, конечно же, не было пакетного менеджера
PEAR был.
> Безопасность среднего поделия на php ниже плинтуса,
Виноват ли в этом язык?
Ну и автор не назвал, какой язык он считает хорошим. Не беда; какой бы он не назвал, у меня есть, что ответить: https://habrahabr.ru/post/315152/
В PHP много плохого, это да. Синтаксис страшный, да. Работа с ошибками сломана безнадежно. Но есть и хорошее: тайп-хинты (ну-ка, покажите мне тайп-хинты в Руби, Питоне или JS), классы как в Яве (покажите мне классы в JS). Есть HHVM. В отличие от JS есть поддержка тредов.
Вообще, у разных языков свои сильные и слабые стороны. Мне нравится в плане возможностей Java и C#, они с типизацией, с классами и компилируются (хорошая производительность). Но в плане установки и использования они не такие простые как PHP, и Симфони там нету.
Плюсами PHP считается наличие большого числа разных CMS например. Тот же Вордпресс. Покажите мне вордпресс на JS.
Также, PHP очень просто в использовании. Пишешь файл 1.php, запускаешь встроенный веб-сервер - страница готова. Попробуйте сделать то же в Руби, Питоне, JS без поиска нужных библиотек.
> 1. Настройка и установка php - это весьма своеобразная история.
Набрать команду apt-get install php - это своеобразная история? Давайте посмотрим на Питон, где инструкция по установке почти любого приложения начинается с установки одного пакетного менеджера через другой. И с освоения virtualenv.
> То, где может искаться php.ini - это целый здоровый список в документации с целой кучей вариантов в зависимости от ОС и сервера.
Можно набрать php -i и посмотреть.
> Сюда же идёт тот факт, что php всегда намертво связано с веб-сервером и не может толком использоваться вне его
Может, хотя не очень понятно, зачем.
> что интерпретатор в общем случае живет в рамках одного http запроса.
И это очень полезная фича. Вообще, PHP можно запускать так, чтобы он обрабатывал много запросов не перезапускаясь (как Руби, Питон итд), и экономить на инициализации приложения, но тут есть свои подвохи. Ну например, я читал, что у людей в Руби утекала память и они не нашли ничего лучше как по крону прибивать и перезапускать приложение.
> Зачем-то в динамический язык скопировали ООП из джавы.
> Зачем, почему, непонятно
Потому, что в Яве прекрасный ООП, в отличие от других языков.
> Долгое время, конечно же, не было пакетного менеджера
PEAR был.
> Безопасность среднего поделия на php ниже плинтуса,
Виноват ли в этом язык?
Ну и автор не назвал, какой язык он считает хорошим. Не беда; какой бы он не назвал, у меня есть, что ответить: https://habrahabr.ru/post/315152/
> Если произошла ошибка - надо прекращать обработку запроса и отдавать 5xx.
В том то и дело что ту не можешь узнать произошла ошибка или нет. Даже блоки try catch иногда не отрабатывают ошибку.
>Также, весь сайт не упадет, а ошибку получит только тот, у кого она произошла.
У тебя явно мало опыта в таких проектах на других языках. Пример ASP показывает что падает у всех, хотя ASP и старенький по современным меркам, но тем не мение он как раз из вот этой концепции.
>Скрытие ошибок ни к чему хорошему не приведет, их просто будет труднее заметить.
Что значит труднее заметить? На продакшне ты вообще не должен их замечать. И вообще вываливать тонны ошибок на юзера - как по мне КРАЙНЕ странная практика. На тестовом сервере ты можешь выставить ошибки и отловить всё что тебе угодно.
Опять же на ASP выводятся тонны ошибок если где-то в SQL запросе что-то пошло не так или вообще по любой другой причине, в результате я как програмист разработчик который может это исправить может и радубсь, но 5000 юзеров сайта недоумевают зачем им вообще знать что там какой-то SQL запрос неправильный? Сделать то они ничего с этим не могут.
>они не нашли ничего лучше как по крону прибивать и перезапускать приложение.
Забавно что у Node.js точно также обстоят дела. Хотя это было в прошлом году, может сейчас есть что-то новое.
>И это очень полезная фича.
Языки с корректно сделанной сборкой мусора и рантаймом (JVM и CLR) умеют жить очень в рамках одного процесса. Возможно, автор, как раз на них и ориентировался.
>Яве прекрасный ООП,
Но только он завязан на статическую типизацию, которой в ПХП толком не было.
>>49926
Опять-таки у приложений на той же JVM или CLR с обработкой ошибок всё хорошо и там как раз в веб приложениях обычно падает только обработчик конкретного запроса.
Вообще, по идее утечки памяти можно находить. Для языка Си, например, есть Valgrind, думаю, что и для JS мог бы быть инструмент, но его никто не написал. Для PHP, кстати, тоже.
Вот кстати, отладка - отдельная вещь. Насколько я знаю, для PHP есть отладчики, увы, только в виде тяжелых IDE вроде PHPStorm или Netbeans, а для Node.JS или Go - вообще нету. То же касается профайлинга, у нас хотя бы xdebug есть.
В PHP есть сборка мусора (хотя ее нет для нативных расширений). Утечки памяти в долгоживущих приложениях происходят не из-за этого.
Условно говоря, если у тебя где-то в коде есть глобальная переменная-массив и ты в нее добавляешь элементы и никогда не удаляешь, то будет утечка памяти. И найти это без специальных инструментов (отслеживающих аллокации/деаллокации памяти) сложно. А их для многих языков нет. А вот кстати для взрослых энтерпрайзных языков вроде Ява инструментов написано много, хотя и не все бесплатные.
> Но только он завязан на статическую типизацию, которой в ПХП толком не было.
Это лучше чем вообще ничего.
Ты все понял неправильно. Правильная система обработки ошибок - это исключения. Не должно быть такого, что произошла ошибка и программа продолжается. На пользователя их никто не вываливает, он получает 503 страницу и ошибка фиксируется в лог.
> В том то и дело что ту не можешь узнать произошла ошибка или нет. Даже блоки try catch иногда не отрабатывают ошибку.
Я как раз могу. Все фиксируется и логгируется. Даже падения процесса PHP можно фиксировать и логгировать, если запускать под супервизором например (ну и php-fpm их тоже по моему отслеживает).
> Пример ASP показывает что падает у всех, хотя ASP и старенький по современным меркам, но тем не мение он как раз из вот этой концепции.
Может быть у вас что-то было неправильно настроено.
> но 5000 юзеров сайта недоумевают зачем им вообще знать что там какой-то SQL запрос неправильный? Сделать то они ничего с этим не могут.
Именно потому им надо показывать не текст ошибки, а страницу 503. "тонны ошибок" там быть не может, так как обработка запроса прекращается на первой же ошибке и следовательно больше одной ошибки за раз быть вообще не может.
Почитай про ошибки и принцип fail fast: https://habrahabr.ru/post/218325/
>Я как раз могу. Все фиксируется и логгируется. Даже падения процесса PHP можно фиксировать и логгировать, если запускать под супервизором например (ну и php-fpm их тоже по моему отслеживает).
Ну так-то да, вот только error_reporting довольно далеко от этого. То-есть претензия была к нему, и к тому что отслеживать ошибки трудно. А в итоге то всё-равно лезь в логи и смотри. Тогда причём тут error_reporting? Непонятно.
>Может быть у вас что-то было неправильно настроено.
Это весьма спорно. Поскольку настраивали всё аж спецы из Американского офиса Майкрософта. Ну и я сам имел около 5 проектов на ASP. И был весьма удивлён таким вот поведением.
Я обычно на шрифты внимания не обращаю. но после первого параграфа глаза реально стали слезиться.
Логи это лишь первичные данные. Ты с ними можешь потом делать что угодно, в том числе например пересылать данные из них в какую-то систему мониторинга.
> Тогда причём тут error_reporting?
При том, что это опция, позволяющая игнорировать отдельные виды ошибок и она вредная.
Что же тут может быть непонятного? Если у тебя произошла любая ошибка или предупреждение, ты останавливаешь скрипт, выдаешь пишешь ошибку в лог и выдаешь пользователю страницу 503.
И очень плохо, что в PHP так не сделано по умолчанию.
>>49965
Это вопрос к хабру. я когда-то читал эту статью в нормальном виде.
> Даже блоки try catch иногда не отрабатывают ошибку.
Потому что они ловят исключения, а не ошибки.
что значит this.request в данном контексте? создается переменная request в которую записывается что?
https://github.com/dorsha/login-modal-react-redux/blob/master/src/util/api.js#L21
что тут происходит?
https://github.com/dorsha/login-modal-react-redux/blob/master/src/util/api.js#L23
Статья с частичным объяснением https://medium.com/@dorsha/implement-login-modal-with-redux-reselect-and-reactjs-668c468bcbe3
Скиньте пожалуйста пример готового сайта, с фронт-эндом, бэк-эндом и всем вот этим. Интересует конкретно структура файлов и папок в нем.
Эм... как бы тебе сказать. Я не понимаю зачем тебе структура файлов и папок на сайте, потому-что банально она может быть любой. Ну тоесть вообще любой. От банального все файлы в одной папке в корне, до каждый файл в своей подпапке. А некоторые JS вообще умудряются разнести функционал по 3-50 доменам! Так что структура папок и файлов тебе вообще не скажут ничего.
> Так что структура папок и файлов тебе вообще не скажут ничего
Так мне и не нужно, чтобы они мне что-то говорили. Просто я поехавший перфекционист, и все должно быть максимально упорядочено. Сейчас вот пилю некое подобие сайта, накатал 1 индекс страницу, другие уже так как обмазался пыхой планирую загружать в нее из БД, так вот есть этот индекс, рядом с ним лежит папка res, и в ней все сразу: и жс, и сасс/сиэсэс, шрифты, картинки, либы, теперь там еще и пыха, которая вообще не из этой тарелки. Типа, я бы мог конечно навасянить себе свою личную структуру, но зачем придумывать велосипед.
Сам разобрался, сам отвечу
>что значит this.request в данном контексте? создается переменная request в которую записывается что?
>https://github.com/dorsha/login-modal-react-redux/blob/master/src/util/api.js#L21
Функция checkStatus вызывается с привязанным контекстом с помощью checkStatus.bind(...), новой созданной переменной request устанавливается значение одноименной переменной из контекста.
>что тут происходит?
>https://github.com/dorsha/login-modal-react-redux/blob/master/src/util/api.js#L23
Очередь с рекурсивными промисами с кэррингом и привязкой контекста. Что может быть проще?
Новый request получает ссылку на вызов функций resolve и reject в созданном Promise, чтобы в дальнейшем можно было их вызвать в другом месте (в очереди будет запущен request, который является ф-ей postPut/get с привязаным контекстом). Сам промис возвращается как результат выполнения checkStatus, в то место где был вызван, и после запуска resolve или reject (в очереди) промис получит соответствующий статус и результат запроса (postPut/get) отправится в обработчик.
> модалка для логина на реакте
> Очередь с рекурсивными промисами с кэррингом и привязкой контекста.
Вспомнился пик. Мне кажется, что раз задача такая простая, а код настолько сложный, то ему не место в продакшене. В проект будут приходить новые люди, им тоже нужно будет ломать голову над таким кодом?
Опушка, а не мог бы ты расставить якоря на каждой задаче? Что бы можно было бы пользоваться ссылками вида
http://archive-ipq-co.narod.ru/l1/pasta.html#vector
http://archive-ipq-co.narod.ru/l1/pasta.html#catsmice
например.
Для меня весь js такой, слишком запутанный.
В защиту конкретно этого примера скажу, что модалка появляется автоматически, как только сервер ответил кодом 401 на любой запрос, и этот запрос будет отправлен повторно после того, как юзер залогинится. Я смотрел другие варианты реализации очереди с реквестами, они не намного проще. Хотя наверное, можно избавиться от рекурсии, кэрринга и привязки контекста. Но кода будет больше.
То чувство, когда ванила JS написанная на коленке с тем-же фугкционалом - получается примерно в 1000 раз проще и понятней чем вот это вот всё. Зато реакт, модно стильно молождёжно.
JS без фрэймворков и библиотек. Термин с американского интернета
Единственное, что из похожего нашел - https://habrahabr.ru/post/150267/, но тут комменты какие-то противоречивые.
Весь тостер уже перерыл, везде в духе пикрлейтеда.
Читаю сейчас Зандстру, попутно пилю проектик, но в итоге один хуй получается какая-то мешанина из классов и процедурного кода.
Это смотрел? https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Также, можно почитать комментарии в задаче про список студентов из ОП поста.
>22. Долгое время, конечно же, не было пакетного менеджера, но в итоге добро всё же победило.
Я вот понимаю что пакетный менеджер - это круто в какой-нибудь JS, где разрабы сами себе кучу говна наложили, и теперь чтобы например автообновление в браузере врубить - надо ставить npm, потом node, потом gulp, И ТОЛЬКО ПОТОМ расширение для gulp. Когда я ставил расширение для PHP, всё что я сделал - копирнул файлы и в php.ini прописал параметры. Стоит ли ради этого делать пакетный менеджер - хз. Вообще кто из вас думает что для PHP он впринципе нужен то?
https://stackoverflow.com/questions/1849618/difference-between-a-factory-provider-and-a-service вот тут написано, что это что-то типа абстрактной фабрики.
притом в реальных проектах я часто вижу чтонибудь типа SmsProvider, который по сути занимается тем, что по АПИ стучится к оператору, дает ему команду отправить смс и получает ответ, который потом например логирует.
где тут абстрактная фабрика? и вообще подобных провайдеров я кучу видел, они все больше похожи на Service.
>Когда я ставил расширение для PHP, всё что я сделал - копирнул файлы и в php.ini прописал параметры
ты говоришь о менеджере экстеншнов видимо (pecl)? не каждый экстеншн ты можешь просто копирнуть и вставить в ини файл, некоторые надо собирать и компилировать (пример - xdebug). pecl делает это все за тебя и очень экономит время
Есть же C# который в этом отношен аз в 1000 легче?
Давай подумаем. Ты когда-нибудь на сайтах жал лайк, оставлял комментарий через виджет ВК, регистрировался или входил на сайт через аккаунт ВК? Я имею в виду, не на известных сайтах вроде Хабра, а на малоизвестных?
А так, ты мог бы сам попробовать изучить, как оно работает. Открой отладчик (Ctrl + shift + I) в браузере на вкладке Network и перезагрузи сайт. Там ты увидишь запросы к серверу vboro.de и соответственно можешь попробовать изучить эти скрипты. И может даже увидишь, как определеяются твои данные.
Я не пользуюсь ВК потому мне понять трудно, как оно работает.
Твой аккаунт они могли узнать разными способами:
- ты мог на каком-то сайте использовать любой виджет ВК (лайки, комментарии, вход через ВК) и они слили твои данные отслеживающему сервису
- они могли использовать кликджекинг: это когда под курсор тебе подводится прозрачный виджет ВК (например, кнопка лайка или вступления в группу) и ты на него нажимаешь
- может быть, ты использовал какое-то приложение в ВК или игру и она слила твои данные сторонним сайтам
Отчаиваться не стоит. Скорее всего эти данные можно удалить, полностью очистив куки и прочую информацию в браузере (Ctrl + Shift + Del). Если это не поможет, значит, они привязали твои данные к IP адресу и user-agent. IP адреса обычно со временем меняются, если у тебюя динамический IP, а user-agent меняется при смене или обновлении браузера.
Также, есть еще вариант, что они не знают твое имя, а просто показывают тебе обрезанный кусок какого-то виджета ВК в ифрейме, где оно выводится, но это менее вероятно.
Провайдером обычно просто называют класс, который что-то предоставляет. Лучше называть классы исходя из их ответственности. В противном случае получится пикрил. Есть ещё полезная статья: https://habrahabr.ru/post/153225/
В Yii2 например есть DataProviderInterface, который предоставляет единый интерфейс для всяких виджетов: http://www.yiiframework.com/doc-2.0/yii-data-dataproviderinterface.html
А его уже имлементят ElasticSearch provider, Sphinx Provider, Array Provider, ОткудаУгодноProvider
> SmsProvider, который по сути занимается тем, что по АПИ стучится к оператору, дает ему команду отправить смс и получает ответ, который потом например логирует.
Ну и такой класс правильнее назвать SmsTransport (по аналогии с email транспортами в swiftmailer) или может быть даже SmsSender. Такое название лучше описывает назначение класса.
>>51079
Composer - лучшее, что произошло с PHP за последнее время, есть уйма статьей в сети объясняющих почему. Советую освоить, без него будет сложно обновлять зависимости, будут конфликты между разными зависимостями и уйма других проблем. Без Composer путь в серьёзную разработку закрыт.
>>51090
PHP - отличный выбор, я использовал фреймворк BotMan, который позиционирует себя как кросс-платформенный: https://botman.io/
Бамп вопросу
>Также, есть еще вариант, что они не знают твое имя, а просто показывают тебе обрезанный кусок какого-то виджета ВК в ифрейме, где оно выводится, но это менее вероятно.
Это какраз-таки единственный возможный вариант
Потому что эти сайты могут сливать твои данные на сторону. Ну и еще возможен кликджекинг, я точно знаю что некоторые компании использовали его чтобы потом связываться с покупателями, которые пришли на сайт, но по каким-то причинам не произвели покупку.
Можно кстати для соцсетей завести отдельный браузер.
У меня другой вопрос. Могу ли я запускать его с произвольного хостинга под веб-сайт с пхп?
У меня запущен на локалхосте сервер, слушающий порт 8080 по https
Из php c помощью curl я к нему обращаюсь. CURLOPT_SSL_VERIFYPEER установлено в false.
Если я вызываю php-шный скрипт, в котором curl-запрос через браузер, apache, то все работает.
А если пытаюсь вызвать этот скрипт через консоль -
"php path/to/script.php", то curl мне выдает ошибку
"Unknown SSL protocol error in connection to path.to.server:port".
Причем если я из консоли самим curl-ом пытаюсь подключиться, то все тоже работает "curl -k path.to.server:port"
Подскажите, пожалуйста, хоть в каком направлении искать решение этой проблемы, уже все перепробовал, ничего не работает.
спасибо большое.
>Ну и такой класс правильнее назвать SmsTransport
мне тоже такое название кажется более логичным, но менять пока нельзя, я над этим проектом работаю 3 дня.
У тебя какая идея для бота? Я вот написал простейшего, наполовину спиздив код с hello-bot'a. Типа пишешь ему сообщение, а он тебе рандом пик с гелбуры в ответочку. Хотел бы игрового бота запилить, что-то типа угадайки. Но я неебу как его отлаживать можно через эти веб-хуки. А на локал-хосте не смог поднять.
Хз для моего милионника плотят неплохо, но яж нихуя не научусь ничему верно? За месяц заебало прямо тошнит, все эти хуки хуюки, собственнописные плагины обоссаные из кучи рандомных функций, рандомно все как то, может вообще бросить нахуй кодинг, раз единственно чо нашел в мухосрани это вротпрес.
Я другой анон и мне кажется удобнее подключать через исходники. Все эти менеджеры усложняют простые вещи. Если бы ты вынужнен был каждый день по 10 проектов разворачивать, менеджер проектов пригодился, когда у тебя новый проект раз в полгода, оно только мешает.
Ну ты прав, только вот я вообще не про проекты говорил и не про код. А про модули самого PHP
Ну там apt-get и подобные помогают. Если чего то нету, собирать из исходников боль и страдание. Вот где уж реально нужны менеджеры пакетов, там где просто нужно побыстрому закинуть бинарники и настроить окружения.
Обычно используют layout'ы (я хз как на русском правильно звучит), обычно это header + footer и динамический body, либо контент внутри body.
То-есть при формировании любой страницы генерируется контент который вставляется в layout.
Пример layout в yii2:
https://github.com/yiisoft/yii2-app-basic/blob/master/views/layouts/main.php
Что тут сложного? Выносишь шапку и подвал в отдельные шаблоны и вызываешь их в начале и конце страницы.
>>51600
Не надо так писать.
>>51352
А не может быть такого, что ты просто в композере не разобрался (тем более что там дока на английском)?
Вот мне просто интересно, что может быть проще, чем дописать одну строку (!) в composer.json, или набрать команду composer require? То есть по твоему проще - это идти искать библиотеку, скачивать архив, распаковывать, читать, что ей нужно, идти скачивать зависимости, распаковывать, копировать, потом настраивать автозагрузку (библиотека сама себя не загрузит)? Что-то мне так не кажется.
Также, в случае с менеджером пакетов обновление происходит проще. Также, это позволяет не хранить в репозитории сторонний код (и защищает от любителей его править).
Да и возьми тот же Андроид. Никто там вручную файлы не скачивает, ставятся приложения через репозиторий и менеджер пакетов (Google Play).
>>51348
А ты документацию по ВП офииальную хотя бы читал? Все эти хуки ведь описаны.
>>51340
Проще всего по символу пробела. Запятые удалить, чтобы не мешались.
Также, у тебя ошибка:
array_reverse($parts)
Ты никуда не сохраняешь результат, надо писать $parts = array_reverse($parts).
>>51339
На локалхосте можно вроде использовать бота, если использовать не хуки (когда сервер к тебе коннектится), а самому раз в N секунд коннектиться к серверу и забирать новые сообщения.
>>51262
> Если я вызываю php-шный скрипт, в котором curl-запрос через браузер, apache, то все работает.
> А если пытаюсь вызвать этот скрипт через консоль -
> "php path/to/script.php", то curl мне выдает ошибку
> "Unknown SSL protocol error in connection to path.to.server:port".
У тебя может использоваться разная конфигурация при работе с веб-сервером и в командной строке. С помощью команды phpinfo() (или php -i в ком. строке) проверь, какой файл конфига используется. Какие расширения установлены, включено ли расширение openssl.
Сравни параметры расширения curl в обоих случаях в phpinfo().
Также, может быть там различаются переменные окружения, влияющие на OpenSSL (это будет видно в phpinfo).
Что тут сложного? Выносишь шапку и подвал в отдельные шаблоны и вызываешь их в начале и конце страницы.
>>51600
Не надо так писать.
>>51352
А не может быть такого, что ты просто в композере не разобрался (тем более что там дока на английском)?
Вот мне просто интересно, что может быть проще, чем дописать одну строку (!) в composer.json, или набрать команду composer require? То есть по твоему проще - это идти искать библиотеку, скачивать архив, распаковывать, читать, что ей нужно, идти скачивать зависимости, распаковывать, копировать, потом настраивать автозагрузку (библиотека сама себя не загрузит)? Что-то мне так не кажется.
Также, в случае с менеджером пакетов обновление происходит проще. Также, это позволяет не хранить в репозитории сторонний код (и защищает от любителей его править).
Да и возьми тот же Андроид. Никто там вручную файлы не скачивает, ставятся приложения через репозиторий и менеджер пакетов (Google Play).
>>51348
А ты документацию по ВП офииальную хотя бы читал? Все эти хуки ведь описаны.
>>51340
Проще всего по символу пробела. Запятые удалить, чтобы не мешались.
Также, у тебя ошибка:
array_reverse($parts)
Ты никуда не сохраняешь результат, надо писать $parts = array_reverse($parts).
>>51339
На локалхосте можно вроде использовать бота, если использовать не хуки (когда сервер к тебе коннектится), а самому раз в N секунд коннектиться к серверу и забирать новые сообщения.
>>51262
> Если я вызываю php-шный скрипт, в котором curl-запрос через браузер, apache, то все работает.
> А если пытаюсь вызвать этот скрипт через консоль -
> "php path/to/script.php", то curl мне выдает ошибку
> "Unknown SSL protocol error in connection to path.to.server:port".
У тебя может использоваться разная конфигурация при работе с веб-сервером и в командной строке. С помощью команды phpinfo() (или php -i в ком. строке) проверь, какой файл конфига используется. Какие расширения установлены, включено ли расширение openssl.
Сравни параметры расширения curl в обоих случаях в phpinfo().
Также, может быть там различаются переменные окружения, влияющие на OpenSSL (это будет видно в phpinfo).
Запускать бота надо скорее всего в командной строке, а не через Апач. Нужно чтобы хостинг поддерживал ssh-доступ и возможность прописать произвольные команды в автозапуск, а значит, тебе нужен не хостинг, а VPS.
>>50430
Раз тебя банят, значит, не хотят, чтобы ты с них парсил данные. Займись чем-нибудь более полезным.
Автоматизировать можно через любое облачное API, например, API амазона.
>>51091
Я не слышал про такой паттерн.
>>51079
Пакетные менеджеры это как раз правильно. Почему я должен руками скачивать и копировать какие-то библиотеки, искать их зависимости, ставить их? Пусть это все ставится одной командой.
Как удобно все сделано в Дебиане, где программы ставятся через apt-get или через их стор. Не то что винда, где надо что-то качать, потом отключать галочки для установки троянов от яндекса и мейл ру. В дебиане к пользователю относятся как к человеку, а не к продукту.
> надо ставить npm, потом node, потом gulp,
Вообще-то npm идет в комплекте с нодой. Надо ставить ноду, и если все настроено правильно и есть файл package.json, то gulp с расширениями ставится одной командой npm install. Куда проще?
> Когда я ставил расширение для PHP, всё что я сделал - копирнул файлы и в php.ini прописал параметры
Не все расширения есть в виде dll, а под линукс все ставится либо через пакетный менеджер ОС, либо через pecl.
> Стоит ли ради этого делать пакетный менеджер
Конечно, стоит. Не руками же расширения компилировать.
Запускать бота надо скорее всего в командной строке, а не через Апач. Нужно чтобы хостинг поддерживал ssh-доступ и возможность прописать произвольные команды в автозапуск, а значит, тебе нужен не хостинг, а VPS.
>>50430
Раз тебя банят, значит, не хотят, чтобы ты с них парсил данные. Займись чем-нибудь более полезным.
Автоматизировать можно через любое облачное API, например, API амазона.
>>51091
Я не слышал про такой паттерн.
>>51079
Пакетные менеджеры это как раз правильно. Почему я должен руками скачивать и копировать какие-то библиотеки, искать их зависимости, ставить их? Пусть это все ставится одной командой.
Как удобно все сделано в Дебиане, где программы ставятся через apt-get или через их стор. Не то что винда, где надо что-то качать, потом отключать галочки для установки троянов от яндекса и мейл ру. В дебиане к пользователю относятся как к человеку, а не к продукту.
> надо ставить npm, потом node, потом gulp,
Вообще-то npm идет в комплекте с нодой. Надо ставить ноду, и если все настроено правильно и есть файл package.json, то gulp с расширениями ставится одной командой npm install. Куда проще?
> Когда я ставил расширение для PHP, всё что я сделал - копирнул файлы и в php.ini прописал параметры
Не все расширения есть в виде dll, а под линукс все ставится либо через пакетный менеджер ОС, либо через pecl.
> Стоит ли ради этого делать пакетный менеджер
Конечно, стоит. Не руками же расширения компилировать.
video.js это просто обертка, которая вставляет в страницу либо тег video, либо флеш-плеер в зависимости от формата файла и версии браузера. Так что разницы нет.
Если ты используешь теги audio/video напрямую, то высока вероятность, что многие форматы не будут воспроизводиться, так как браузеры поддерживают ограниченное число форматов. Форматов мало, потому большинство файлов воспроизводиться не будут. В комментариях к задаче это ведь описано и даны ссылки на MDN, где перечислены форматы: https://gist.github.com/codedokode/9424217#Информация-о-файле
Можно сделать по-простому, но если тебе захочется, чтобы любые форматы вопроизводились, то придется заморачиваться с перекодированием в поддерживаемые форматы. Это довольно сложно.
>>50614
Как я понимаю, react отвечает ведь за view, отображение данных, не очень понятно, какое отношение он имеет к HTTP-запросам?
Это не JS запутанный, это автор не умеет писать простой и понятный код и придумывает какие-то сложные решения.
>>50518
Вообще, у меня тоже вопросы к коду появляются, например:
> function checkStatus(response) {
> var quiet = this.quiet;
checkStatus это же не метод объекта, что тут значит this? Оказывается, если поискать, то ниже можно увидеть:
> then(checkStatus.bind({request: postPut.bind(undefined, uri, method, data, true), quiet: quiet}))
Это конечно запутывание кода. Что мешает опции явно передать в аргументы либо сделать настоящий объект RequestOptions? Где это видано, чтобы аргументы функции передавались через привязку объекта к this?
Далее, из промиса извлекаются коллбеки resolve/reject и записываются куда-то в объект request (который, если присмотреться, является функцией: postPut.bind(...)). Это конечно тоже запутывает код, так как очень трудно понять, куда они потом передаются, что с ними делается. Что мешает их обычным способом, например, через аргументы, передавать?
Не, по моему с точки зрения читабельности это плохой код. В нем сложно разобраться и легко допустить ошибку. Я сильно сомневаюсь в адекватности того, кто его писал.
> export function setStore(s) {
Вот это тоже какая-то извращенная идея, они модуль используют как объект. Если вам нужен объект, почему не сделать класс?
Хуже того, это все неочевидно и никак не документировано. Мы должны как-то догадаться, что сначала надо вызывать setStore(), а только потом можно вызывать другие функции из модуля.
Такое ощущение, что для автора JS - первый язык и он просто не знает, как те или иные вещи принято делать и изобретает какие-то свои странные подходы.
Также, я не уверен, что вообще имеет смысл делать показ окон через react. А тем более, сохранение отложенных запросов в store. Очень странный выбор, по моему человеку просто принципиально все делать на реакте, даже если это усложняет код.
video.js это просто обертка, которая вставляет в страницу либо тег video, либо флеш-плеер в зависимости от формата файла и версии браузера. Так что разницы нет.
Если ты используешь теги audio/video напрямую, то высока вероятность, что многие форматы не будут воспроизводиться, так как браузеры поддерживают ограниченное число форматов. Форматов мало, потому большинство файлов воспроизводиться не будут. В комментариях к задаче это ведь описано и даны ссылки на MDN, где перечислены форматы: https://gist.github.com/codedokode/9424217#Информация-о-файле
Можно сделать по-простому, но если тебе захочется, чтобы любые форматы вопроизводились, то придется заморачиваться с перекодированием в поддерживаемые форматы. Это довольно сложно.
>>50614
Как я понимаю, react отвечает ведь за view, отображение данных, не очень понятно, какое отношение он имеет к HTTP-запросам?
Это не JS запутанный, это автор не умеет писать простой и понятный код и придумывает какие-то сложные решения.
>>50518
Вообще, у меня тоже вопросы к коду появляются, например:
> function checkStatus(response) {
> var quiet = this.quiet;
checkStatus это же не метод объекта, что тут значит this? Оказывается, если поискать, то ниже можно увидеть:
> then(checkStatus.bind({request: postPut.bind(undefined, uri, method, data, true), quiet: quiet}))
Это конечно запутывание кода. Что мешает опции явно передать в аргументы либо сделать настоящий объект RequestOptions? Где это видано, чтобы аргументы функции передавались через привязку объекта к this?
Далее, из промиса извлекаются коллбеки resolve/reject и записываются куда-то в объект request (который, если присмотреться, является функцией: postPut.bind(...)). Это конечно тоже запутывает код, так как очень трудно понять, куда они потом передаются, что с ними делается. Что мешает их обычным способом, например, через аргументы, передавать?
Не, по моему с точки зрения читабельности это плохой код. В нем сложно разобраться и легко допустить ошибку. Я сильно сомневаюсь в адекватности того, кто его писал.
> export function setStore(s) {
Вот это тоже какая-то извращенная идея, они модуль используют как объект. Если вам нужен объект, почему не сделать класс?
Хуже того, это все неочевидно и никак не документировано. Мы должны как-то догадаться, что сначала надо вызывать setStore(), а только потом можно вызывать другие функции из модуля.
Такое ощущение, что для автора JS - первый язык и он просто не знает, как те или иные вещи принято делать и изобретает какие-то свои странные подходы.
Также, я не уверен, что вообще имеет смысл делать показ окон через react. А тем более, сохранение отложенных запросов в store. Очень странный выбор, по моему человеку просто принципиально все делать на реакте, даже если это усложняет код.
Вообще, хорошая идея, в будущем постараюсь сделать, когда буду переделывать верстку.
>>50434
Тут сразу видны проблемы. Например, в свойствах Room:
> private $arrivalDate;
> private $countOfGuests;
Никак не учтено, что вообще-то одну комнату можно забронировать несколько раз - на разные даты. Бронь - это тоже объект вообще-то.
> private $guests = array("firstName" => array(), "lastName" => array());
Ты тут пытаешься вместо того, чтобы использовать объект Гость, имитировать его с помощью массива.
> private $isFree = TRUE;
Это свойство довольно неудачное, так как занятость номера зависит от даты - в одни дни он свободен, в другие занят.
> public function changeIsFtee():void
Это неудачная функция, так как ее результат зависит от предыдущего значения занятости. Лучше явно передавать значение true/false в аргументы. Тогда будет очевидно, какое значение записывается в поле при вызове.
В общем, логичнее сделать так: сделать объект Бронь и добавлять Бронь к Номеру. А у тебя вместо этого какие-то разбросанные по отдельным полям не связанные друг с другом данные. Это все усложняет, плюс появляется шанс, что ты где-то изменишь одно поле и забудешь про другое.
> class Hotel
> public function addGuest(string $firstName, string $lastName): void
Непонятно, куда эта функция добавляет Гостя и зачем. Она ведь ничего не возвращает. Да и что это за список гостей? Это все, кто останавливались в Гостнице? Кто бронировал? Кто собирался бронировать, но передумал?
> public function getRoom(int $numberOfRoom): Room
Это неудачная функция, так как непонятно, где брать $numberOfRoom.
> public function getGuest(string $firstName, string $lastName): Guest
Это неудачная функция. Зачем нужно искать объект по его свойствам, если объект сам по себе уникален и обладает идентичностью? Зачем сначала вызывать addGuest, а потом искать его по имени/фамилии, если можно сразу возвращать объект Guest из функции addGuest? Или вообще создать через new?
> private $receipts = array("date" => array(), "money" => array());
Опять, имитация объекта с помощью массива.
> class Guest
> public function addVisitedRoom(int $numberOfRoom): void
Зачем добавлять сюда порядковый номер комера? Он ведь в теории еще и поменяться может при удалении номера например. Если и добавлять, то сам объект Room, а не его номер.
> class Registration
Многие методы отсюда можно было бы перенести в Гостиницу
> if($hotel->getReceipts()["date"][$i] == end($hotel->getReceipts()["date"])){
Это какой-то адски переусложненный код на массивах, даже трудно понять, как он работает.
> $room = $hotel->getRoom($room);
Так делать нельзя. Не надо в одной переменной хранить разные типы данных (число и объект), это запутывает код.
То есть тут неудачно спроектированы классы и их методы (что можно с ними делать). Вот взять то же заселение:
> $hotel->getRoom($numberOfRoom)->setDate($hotel, $arrivalDate, $dateOfDeparture);
> $hotel->getRoom($numberOfRoom)->addGuestToRoom($firstName, $lastName);
> $hotel->getRoom($numberOfRoom)->changeIsFtee();
Почему заселение делается за 3 вызова? Что, можно вызвать только setDate() и не вызывать остальные методы? Ты тут нарушаешь принцип инкапсуляции. Ты должен просто вызвать метод класса Room "пометить номер забронированным таким-то гостем", а дальше внутри класса Room уже код будет заполнять нужные поля. При твоем подходе очень легко ошибиться, например, забыть вызвать один из методов.
Если бы у тебя был класс, представляющий Бронь, то хватило бы просто вызова
номер->добавитьБронь(бронь);
Сортировку номеров лучше делать с помощью usort, а не городить там сложные циклы.
Вообще, хорошая идея, в будущем постараюсь сделать, когда буду переделывать верстку.
>>50434
Тут сразу видны проблемы. Например, в свойствах Room:
> private $arrivalDate;
> private $countOfGuests;
Никак не учтено, что вообще-то одну комнату можно забронировать несколько раз - на разные даты. Бронь - это тоже объект вообще-то.
> private $guests = array("firstName" => array(), "lastName" => array());
Ты тут пытаешься вместо того, чтобы использовать объект Гость, имитировать его с помощью массива.
> private $isFree = TRUE;
Это свойство довольно неудачное, так как занятость номера зависит от даты - в одни дни он свободен, в другие занят.
> public function changeIsFtee():void
Это неудачная функция, так как ее результат зависит от предыдущего значения занятости. Лучше явно передавать значение true/false в аргументы. Тогда будет очевидно, какое значение записывается в поле при вызове.
В общем, логичнее сделать так: сделать объект Бронь и добавлять Бронь к Номеру. А у тебя вместо этого какие-то разбросанные по отдельным полям не связанные друг с другом данные. Это все усложняет, плюс появляется шанс, что ты где-то изменишь одно поле и забудешь про другое.
> class Hotel
> public function addGuest(string $firstName, string $lastName): void
Непонятно, куда эта функция добавляет Гостя и зачем. Она ведь ничего не возвращает. Да и что это за список гостей? Это все, кто останавливались в Гостнице? Кто бронировал? Кто собирался бронировать, но передумал?
> public function getRoom(int $numberOfRoom): Room
Это неудачная функция, так как непонятно, где брать $numberOfRoom.
> public function getGuest(string $firstName, string $lastName): Guest
Это неудачная функция. Зачем нужно искать объект по его свойствам, если объект сам по себе уникален и обладает идентичностью? Зачем сначала вызывать addGuest, а потом искать его по имени/фамилии, если можно сразу возвращать объект Guest из функции addGuest? Или вообще создать через new?
> private $receipts = array("date" => array(), "money" => array());
Опять, имитация объекта с помощью массива.
> class Guest
> public function addVisitedRoom(int $numberOfRoom): void
Зачем добавлять сюда порядковый номер комера? Он ведь в теории еще и поменяться может при удалении номера например. Если и добавлять, то сам объект Room, а не его номер.
> class Registration
Многие методы отсюда можно было бы перенести в Гостиницу
> if($hotel->getReceipts()["date"][$i] == end($hotel->getReceipts()["date"])){
Это какой-то адски переусложненный код на массивах, даже трудно понять, как он работает.
> $room = $hotel->getRoom($room);
Так делать нельзя. Не надо в одной переменной хранить разные типы данных (число и объект), это запутывает код.
То есть тут неудачно спроектированы классы и их методы (что можно с ними делать). Вот взять то же заселение:
> $hotel->getRoom($numberOfRoom)->setDate($hotel, $arrivalDate, $dateOfDeparture);
> $hotel->getRoom($numberOfRoom)->addGuestToRoom($firstName, $lastName);
> $hotel->getRoom($numberOfRoom)->changeIsFtee();
Почему заселение делается за 3 вызова? Что, можно вызвать только setDate() и не вызывать остальные методы? Ты тут нарушаешь принцип инкапсуляции. Ты должен просто вызвать метод класса Room "пометить номер забронированным таким-то гостем", а дальше внутри класса Room уже код будет заполнять нужные поля. При твоем подходе очень легко ошибиться, например, забыть вызвать один из методов.
Если бы у тебя был класс, представляющий Бронь, то хватило бы просто вызова
номер->добавитьБронь(бронь);
Сортировку номеров лучше делать с помощью usort, а не городить там сложные циклы.
str_pad не поддерживает utf-8, в частности кириллицу: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
>>50217
Почитай комментарии к задаче про студентов, там немного есть про это: https://github.com/codedokode/pasta/blob/master/student-list.md#Структура-файлов
> и жс, и сасс/сиэсэс, шрифты, картинки,
Это все лучше выносить в отдельную публичную папку.
>Раз тебя банят, значит, не хотят, чтобы ты с них парсил данные. Займись чем-нибудь более полезным.
Да, вот только это и есть более полезное так как мне за это платят деньги.
>
> Что тут сложного? Выносишь шапку и подвал в отдельные шаблоны и вызываешь их в начале и конце страницы.
И так все делают, лол?
Вообще, единственное, что пришло мне в голову, это наоборот загружать на одну html страницу динамическую часть из БД с помощью аджакса, вроде и выглядит красиво, но потом я понял, что тогда при обновлении страницы оно будет все сбрасывать до начального состояния, и вообще что большинство сайтов таки крутят колесо когда на другую страницу переходишь.
>Как удобно все сделано в Дебиане, где программы ставятся через apt-get или через их стор. Не то что винда
представляю, как ты обрадуешься, когда узнаешь, например, о yum.
>Не руками же расширения компилировать
вообще-то какие-то расширения ты по-другому не поставишь, например pthreads. более того, сам пхп рекомендуется компилировать вручную: http://www.phpinternalsbook.com/build_system/building_php.html#why-not-use-packages
правда я кладу на это и ставлю из репозиториев
Проще всего сдеалть денормализацию и добавить поле "число статей" к таблице тегов. Так как SQL-запрос с группировкой потребует обхода всех статей (их могут быть сотни и тысячи) и будет не эффективен. Либо кешировать его результаты, если не нужна оперативность.
По твоему коду - не проще ли писать DQL, чем городить кучу скобок и стрелочек?
>>39178
Не нужно использовать addslashes. Плейсхолдеры использовать нужно. Строки сами по себе никакого вреда не несут, уязвимость появляется при неправильной подстановке данных от пользователя в какую-то строку, например, SQL-запрос или HTML-код страницы.
>>39452
Не знаю, советовали ли, но попробуй прочесть мануал PHP.
>>39633
Справедливости ради, уж HTML теги для списков надо бы знать.
Ты все переусложнил. После того, как ты нашел все буквы первой регуляркой, ты можешь просто обойти массив этих найденных букв в цикле и посчитать их число, используя массив такого вида для хранения результата:
'a' => 0,
'б' => 0,
...
На каждом шаге цикла ты берешь 1 букву и увеличиваешь соответсвующее значение в массиве.
Есть еще функция array_count_values, но тут она не очень подойдет.
>>40110
mysqldump в простейшем случае + крон-скрипт.
>>40179
Там можно много рекомендаций написать. Большинство из них есть в подробных комментариях к задаче про студентов, вот тут:
- https://github.com/codedokode/pasta/blob/master/php/templates.md
- https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
- https://github.com/codedokode/pasta/blob/master/student-list.md
Ты можешь прочесть комментарии и посмотреть, какие из них можно применить к твоему коду.
Ну например, не надо смешивать в кучу php-логику и вывод HTML-кода, не надо подставлять переменные прямо в SQL запросы (у тебя там SQL инъекция), не надо писать сплошную стену кода на 200 строк, а надо разбивать код на функции.
Код надо правильно отформатировать на phpformatter.com
Надо давать нормальные имена переменным. Что такое mea или st? Кто это будет расшифровывать?
mysql-функции давно устарели.
Плюс, у тебя есть просто синтаксические ошибки, например в $_GET[from] надо from брать в кавычки. Ты пробовал включить вывод предупреждений и посмотреть, что выведется?
Пока код очень некачественный. Ты по какому-то очень устаревшему учебнику учился.
Ты все переусложнил. После того, как ты нашел все буквы первой регуляркой, ты можешь просто обойти массив этих найденных букв в цикле и посчитать их число, используя массив такого вида для хранения результата:
'a' => 0,
'б' => 0,
...
На каждом шаге цикла ты берешь 1 букву и увеличиваешь соответсвующее значение в массиве.
Есть еще функция array_count_values, но тут она не очень подойдет.
>>40110
mysqldump в простейшем случае + крон-скрипт.
>>40179
Там можно много рекомендаций написать. Большинство из них есть в подробных комментариях к задаче про студентов, вот тут:
- https://github.com/codedokode/pasta/blob/master/php/templates.md
- https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
- https://github.com/codedokode/pasta/blob/master/student-list.md
Ты можешь прочесть комментарии и посмотреть, какие из них можно применить к твоему коду.
Ну например, не надо смешивать в кучу php-логику и вывод HTML-кода, не надо подставлять переменные прямо в SQL запросы (у тебя там SQL инъекция), не надо писать сплошную стену кода на 200 строк, а надо разбивать код на функции.
Код надо правильно отформатировать на phpformatter.com
Надо давать нормальные имена переменным. Что такое mea или st? Кто это будет расшифровывать?
mysql-функции давно устарели.
Плюс, у тебя есть просто синтаксические ошибки, например в $_GET[from] надо from брать в кавычки. Ты пробовал включить вывод предупреждений и посмотреть, что выведется?
Пока код очень некачественный. Ты по какому-то очень устаревшему учебнику учился.
Если почитать мануал http://php.net/manual/ru/datetime.modify.php то там упоминается, что метод modify может вернуть false. Надо проверить, не происходит ли этого?
По поводу if, можно поставить echo во все ветки и увидеть, что выполняется.
На дампе справа я вижу, что в массиве один и тот же объект - это видно по номеру после слова DateTime - он одинаковый. То есть ты добавил в массив кучу ссылок на один и тот же объект, и так как объект один, то тебе кажется что у тебя много объектов которые синхронно модифицируются. но объект там один. Короче говоря
$a = new \DateTime;
$b = $a;
Тут всего один объект и 2 переменные, которые на него указывают. И если ты делаешь $a->modify() то в $b значение тоже обновится так как она указывает на тот же самый объект.
Основы ООП, в общем.
Также, строчка date->format() у тебя ничего не делает.
>>41013
Если ты не знаешь PHP, то ничего не сделать.
>>41534
А в чем вообще смысл void-функции? ЧТо она делает? Если она вообще ничего не делает, зачем она нужна? Если что-то делает, то это и надо тестировать.
>>43242
Там не очень хорошо, что есть условие
> if ($creditBalance >= 1000) {
Откуда взялась эта цифра? Непонятно.
Лучше сделать так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
Если почитать мануал http://php.net/manual/ru/datetime.modify.php то там упоминается, что метод modify может вернуть false. Надо проверить, не происходит ли этого?
По поводу if, можно поставить echo во все ветки и увидеть, что выполняется.
На дампе справа я вижу, что в массиве один и тот же объект - это видно по номеру после слова DateTime - он одинаковый. То есть ты добавил в массив кучу ссылок на один и тот же объект, и так как объект один, то тебе кажется что у тебя много объектов которые синхронно модифицируются. но объект там один. Короче говоря
$a = new \DateTime;
$b = $a;
Тут всего один объект и 2 переменные, которые на него указывают. И если ты делаешь $a->modify() то в $b значение тоже обновится так как она указывает на тот же самый объект.
Основы ООП, в общем.
Также, строчка date->format() у тебя ничего не делает.
>>41013
Если ты не знаешь PHP, то ничего не сделать.
>>41534
А в чем вообще смысл void-функции? ЧТо она делает? Если она вообще ничего не делает, зачем она нужна? Если что-то делает, то это и надо тестировать.
>>43242
Там не очень хорошо, что есть условие
> if ($creditBalance >= 1000) {
Откуда взялась эта цифра? Непонятно.
Лучше сделать так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
> 1. подскажите обязательно ли заключать переменные находящиеся в echo внутрь скобок {}, пробовал без них все работает. Зачем они нужны?
Мануал объяснит: http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
> 2. Что выделено на пике является дурным тоном в написании кода? html так вставлять нельзя, как я понял.
Можно так писать, почему бы и нет. Насчет HTML - не понял, HTML это просто разметка для текста, ничего ее не мешает вставлять.
>>43636
>>>Заходишь по ssh на сервер и выполняешь этот скрипт
> вот этот процесс и хотелось бы автоматизировать (не заходить и не запускать каждый раз)
Ты можешь сделать у себя скрипт с таким содержимым
#!/bin/bash
ssh user@server command
Он зайдет на сервер по SSH и выполнит команду. Если команд несколько, то может быть придется написать sh -c 'команды'
>>43669
Этот тред больше про PHP чем про вордпресс. Тут скорее всего тебя спросят, читал ли ты документацию.
>>43724
Надо понять, отдается ли заголовок вообще - потому я и посоветовал использовать инструменты разработчика.
Как альтернатива, можно в код натыкать echo чтобы видеть путь выполнения скрипта и значения переменных.
> 1. подскажите обязательно ли заключать переменные находящиеся в echo внутрь скобок {}, пробовал без них все работает. Зачем они нужны?
Мануал объяснит: http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
> 2. Что выделено на пике является дурным тоном в написании кода? html так вставлять нельзя, как я понял.
Можно так писать, почему бы и нет. Насчет HTML - не понял, HTML это просто разметка для текста, ничего ее не мешает вставлять.
>>43636
>>>Заходишь по ssh на сервер и выполняешь этот скрипт
> вот этот процесс и хотелось бы автоматизировать (не заходить и не запускать каждый раз)
Ты можешь сделать у себя скрипт с таким содержимым
#!/bin/bash
ssh user@server command
Он зайдет на сервер по SSH и выполнит команду. Если команд несколько, то может быть придется написать sh -c 'команды'
>>43669
Этот тред больше про PHP чем про вордпресс. Тут скорее всего тебя спросят, читал ли ты документацию.
>>43724
Надо понять, отдается ли заголовок вообще - потому я и посоветовал использовать инструменты разработчика.
Как альтернатива, можно в код натыкать echo чтобы видеть путь выполнения скрипта и значения переменных.
> Почему количество коффе,которое задается в условии для каждой профессии не является свойством? (так написано в подсказках)
Я думаю, там была идея про то, что надо различать базовое количество кофе (свойство работника) и итоговое потребление с учетом ранга (вычисляется из базового). И для итогового не делать свойство, а сделать метод и вычислять на ходу.
> . Зачем нужно свойство "профессия" (так написано в подсказках)?
Чтобы знать, какой профессии работник? Там есть 2 подхода, можно сделать для каждой профессии свой класс, а можно сделать единый класс, но тогда нужно свойство, показывающее, к какой профессии относится работник.
>>43907
Да, только через if
>>44020
По опыту предыдущих решений, там придется хранить метаданные (битрейт, разрешение, кодек) либо в JSON-поле, либо делать EAV (Entity Attribute Value). Так как они разные для разных форматов файлов.
> Хотя более логичным мне кажется использовать паттерн одна сущность - одна таблица без явных связей с другими таблицами(Concrete Table Inheritance), ведь объект полностью имеет поля своего предка, и раз в бд нельзя провернуть наследование, то может оно и не нужно?
Это неудобно по таким причинам:
- не будет генерироваться возрастающий id для файлов
- неудобно ставить внешний ключ. Ну например, с комментария на файл.
> Я правильно понимаю что в бд я записываю путь к файлу, который лежит на диске, а потом при отправке пишу нужные заголовки и вставляю туда же путь к файлу
Нет конечно. Если ты вставишь в ответ путь к файлу, то только путь и отправится, а не файл. Ты конечно можешь давать пользователю прямую ссылку на файл, но там есть свои подвохи.
В комментариях к задаче предложены варианты отдачи файла.
> вроде обёртка есть для переменной _FILES
$_FILES - это файлы, отправленные из браузера на сервер.
> Почему количество коффе,которое задается в условии для каждой профессии не является свойством? (так написано в подсказках)
Я думаю, там была идея про то, что надо различать базовое количество кофе (свойство работника) и итоговое потребление с учетом ранга (вычисляется из базового). И для итогового не делать свойство, а сделать метод и вычислять на ходу.
> . Зачем нужно свойство "профессия" (так написано в подсказках)?
Чтобы знать, какой профессии работник? Там есть 2 подхода, можно сделать для каждой профессии свой класс, а можно сделать единый класс, но тогда нужно свойство, показывающее, к какой профессии относится работник.
>>43907
Да, только через if
>>44020
По опыту предыдущих решений, там придется хранить метаданные (битрейт, разрешение, кодек) либо в JSON-поле, либо делать EAV (Entity Attribute Value). Так как они разные для разных форматов файлов.
> Хотя более логичным мне кажется использовать паттерн одна сущность - одна таблица без явных связей с другими таблицами(Concrete Table Inheritance), ведь объект полностью имеет поля своего предка, и раз в бд нельзя провернуть наследование, то может оно и не нужно?
Это неудобно по таким причинам:
- не будет генерироваться возрастающий id для файлов
- неудобно ставить внешний ключ. Ну например, с комментария на файл.
> Я правильно понимаю что в бд я записываю путь к файлу, который лежит на диске, а потом при отправке пишу нужные заголовки и вставляю туда же путь к файлу
Нет конечно. Если ты вставишь в ответ путь к файлу, то только путь и отправится, а не файл. Ты конечно можешь давать пользователю прямую ссылку на файл, но там есть свои подвохи.
В комментариях к задаче предложены варианты отдачи файла.
> вроде обёртка есть для переменной _FILES
$_FILES - это файлы, отправленные из браузера на сервер.
Я не очень понял, в чем вопрос? Это где-то описано и ты хочешь ссылку или ты сам придумал? Если сам, то наверно тебе придется и алгоритм работы роутера придумать.
>>44119
Друпал и ворппресс.
>>49596
> мне надо придумать какой нибудь хэш для комнаты(он же идентификатор), но по идее идентификатор комнаты ее номер.
Не надо - объект сам по себе идентификатор. Но как ты заметил, есть номер.
> А вот по поводу гостя, какой идентификатор добавить?
То же самое.
> Если сделать идентификатором пользователя имя и фамилию и использовать как ключ для доступа поля в массиве?
Плохая идея. Они не уникальны.
> Еще мне очень интересно как на это все добавить тестов или вообще в идеале делать по тдд, если это конечно возможно?
ТДД значит, что ты сначала определяешь требования к классам в виде тестов, а только потом пишешь код.
Что касается тестирования, то тут как раз все хорош тестируется. Определяешь требования к классам и их сочетаниям и на каждое требование пишешь тест, проверяющий его выполнение.
Например, возьмем такое требование к функции проверки занятости номера:
- функция проверки занятости номера должна возвращать, что номер занят, если он забронирован на эту дату
И пишем тест:
- создать Номер
- добавить в него бронь с 3 по 5 января
- проверить, что функция свободенЛи() для 4 января вернет false
То есть попробуй рассмотреть все классы, методы и сформулировать требования к ним.
Я не очень понял, в чем вопрос? Это где-то описано и ты хочешь ссылку или ты сам придумал? Если сам, то наверно тебе придется и алгоритм работы роутера придумать.
>>44119
Друпал и ворппресс.
>>49596
> мне надо придумать какой нибудь хэш для комнаты(он же идентификатор), но по идее идентификатор комнаты ее номер.
Не надо - объект сам по себе идентификатор. Но как ты заметил, есть номер.
> А вот по поводу гостя, какой идентификатор добавить?
То же самое.
> Если сделать идентификатором пользователя имя и фамилию и использовать как ключ для доступа поля в массиве?
Плохая идея. Они не уникальны.
> Еще мне очень интересно как на это все добавить тестов или вообще в идеале делать по тдд, если это конечно возможно?
ТДД значит, что ты сначала определяешь требования к классам в виде тестов, а только потом пишешь код.
Что касается тестирования, то тут как раз все хорош тестируется. Определяешь требования к классам и их сочетаниям и на каждое требование пишешь тест, проверяющий его выполнение.
Например, возьмем такое требование к функции проверки занятости номера:
- функция проверки занятости номера должна возвращать, что номер занят, если он забронирован на эту дату
И пишем тест:
- создать Номер
- добавить в него бронь с 3 по 5 января
- проверить, что функция свободенЛи() для 4 января вернет false
То есть попробуй рассмотреть все классы, методы и сформулировать требования к ним.
Тут ведь нет базы. А только объекты.
А так, есть разные подходы, нельзя так сказать, какой лучше.
Но могу сказать, что более-менее сложный граф объектов плохо ложится на реляционную БД.
>Не надо - объект сам по себе идентификатор.
А как проверять, что у меня нужный мне объект?
С идентификатором комнаты понятно, сравнить у моего объекта и какого либо другого номера, но если нету такого идентификатора, нужно получается, что то типо uuid поля создавать?
>Определяешь требования к классам и их сочетаниям
То есть в твоем примере теста, проверка свободен ли номер 4 января, это и есть требование?
Если я не прав можно попросить пример требований?
А что проверяется в сочетаниях классов? Все тоже самое только в комбинациях классов? Например класс А может использовать классы Б и В, я проверяю тестами сначала для классов А+Б, потом для классов А+В?
Может есть какой совет или рекомендация, как увидеть все требования, ничего не забыть или не напридумывать других требований?
>Как я понимаю, react отвечает ведь за view, отображение данных, не очень понятно, какое отношение он имеет к HTTP-запросам?
На случай, если это был не риторический вопрос, у автора разделен код компонента модального окна (view, components/Modal/LoginModal.js ) от кода, который отвечает за создание и отправку реквеста (util/api.js). Но есть зависимость "export function setStore(s)", причем она используется только для запуска метода store.dispatch(loginRequired(request)), можно передать только сам метод dispatch() а не store целиком.
>>51714
>> export function setStore(s) {
>Вот это тоже какая-то извращенная идея, они модуль используют как объект. Если вам нужен объект, почему не сделать класс?
За то небольшое время, пока я ковыряю исходники и примеры различных библиотек около рект/редакс модулей, я ни разу не видел, чтобы кто-то использовал классы, только файлы с набором функций. Я не защищаю такой подход, просто делюсь наблюдением.
>>51714
>Также, я не уверен, что вообще имеет смысл делать показ окон через react. А тем более, сохранение отложенных запросов в store. Очень странный выбор, по моему человеку просто принципиально все делать на реакте, даже если это усложняет код.
Но если все приложение использует react+redux, то немного странно делать модальное окно не на основе компонента react? Или как быть с запросами, ведь интерфейс должен инициировать запросы к api и каким-то образом реагировать в случае, если сервер вернул ошибку 401?
Допустим я сделаю класс класс Api, который знает о том где находится сервер и как отправлять запросы, создам класс Request, который будет хранить заголовки и данные. Но где создавать и хранить Request? Сделать еще один класс посредник, который будет подписан на события изменения store, забирать нужные данные, формировать, отправлять и хранить запросы?
На Гитхабе есть статья: https://help.github.com/articles/removing-sensitive-data-from-a-repository/
Если это слишком сложно, то можно просто удалить репозиторий на гитхабе, у себя создать новый пустой репозиторий и скопировать туда нужные файлы.
И в следующий раз перед git commit делать git status и смотреть, что коммитишь.
>>51852
Представь, что ты поручаешь кому-то написать функцию. Ты должен сформулировать требования к этой функции, чтобы человек знал, что от него нужно. Что она должна делать? Как должна себя вести в той или иной ситуации?
Когда он напишет эту функцию, ты берешь по очереди каждое требование и проверяешь, что оно выполняется. Вот это и должны делать тесты - проверять, что код соответствует поставленным при его написании требованиям.
Соответственно, когда ты потом будешь использовать эту функцию в коде, ты можешь ожидать, что она соответствует этим требованиям, но ты не должен ожидать от нее что-то сверх этого.
Обычно сначала пишется функция, а потом тесты к ней. В случае использования TDD, мы сначала пишем тесты, а только потом код функции. TDD позволяет, например, одному человеку написать требования в виде тестов и передать их разработчику для написания кода.
Ну например, возьмем метод добавления брони $room->reserve() на определенные даты на номер в классе Room. Что он должен делать?
- он должен выдать ошибку, если выбранные даты уже заняты
- иначе, он должен добавить бронь (то есть где-то сохранить информацию, что номер забронирован на такие-то даты такими-то гостями, и это потом можно проверить)
- (тут еще могут быть дополнительные требования по проверке данных, которые я для простоты не пишу)
Имея требования, мы можем написать тесты, проверяющие их выполнение. Тут нам придется проявить смекалку и придумать, как именно их проверять. Например, для проверки второго требования можно написать такой тест (я использую синтаксис phpunit):
public function testReservedRoomIsMarkedAsOccupied()
{
$room = new Room(..);
$guest = new Guest(...);
$room->reserve($guest, new DateTime('2020-01-03'), new DateTime('2020-01-05'));
// Проверяет, что функция вернет true
$this->assertTrue($room->isOccupied(new DateTime('2020-01-04')));
// При желании еще можно написать так, хотя некоторые скажут,
// что это нужно писать в отдельном тесте
$this->assertFalse($room->isOccupied(new DateTime('2020-01-06')));
}
В случае TDD, можно использовать даже специальный язык для формулирования требований, например, Gherkin. На нем требования пишутся с использованием конструкций Given (дано) - When (если) - Then (то). Например, аналитик может записать одно из требований так (я пишу текст на русском для удобства чтения):
Feature: бронирование номера
Scenario: Забронированный номер помечается как занятый
Given Есть свободный Номер 100
And Есть Гость Иван Иванов
And Иван Иванов бронирует номер 100 с 3.01.2020 по 5.01.2020
When мы проверяем, занят ли номер 4.01.2020
Then номер помечен как занятый
Правда, судя по статьям, сами аналитики не очень любят такие языки: https://habrahabr.ru/post/275013/
> То есть в твоем примере теста, проверка свободен ли номер 4 января, это и есть требование?
Нет. Требование - функция должна позволить забронировать незанятый номер и запомнить это.
> А что проверяется в сочетаниях классов?
Некоторые классы можно тестировать отдельно, но некоторые классы не могут работать сами по себе и им нужны еще какие-то другие классы. Тогда мы их тестируем вместе.
> Например класс А может использовать классы Б и В, я проверяю тестами сначала для классов А+Б, потом для классов А+В?
Такое редко бывает, обычно бывает, что классу А нужны Б и В. Тогда в тесте для класса А мы создаем объекты Б и В и передаем их в А.
> как увидеть все требования, ничего не забыть или не напридумывать других требований?
Нужно взять каждый класс, каждый публичный метод и подумать, что мы от него хотим. Что он должен уметь делать и как себя вести в той или иной ситуации.
На Гитхабе есть статья: https://help.github.com/articles/removing-sensitive-data-from-a-repository/
Если это слишком сложно, то можно просто удалить репозиторий на гитхабе, у себя создать новый пустой репозиторий и скопировать туда нужные файлы.
И в следующий раз перед git commit делать git status и смотреть, что коммитишь.
>>51852
Представь, что ты поручаешь кому-то написать функцию. Ты должен сформулировать требования к этой функции, чтобы человек знал, что от него нужно. Что она должна делать? Как должна себя вести в той или иной ситуации?
Когда он напишет эту функцию, ты берешь по очереди каждое требование и проверяешь, что оно выполняется. Вот это и должны делать тесты - проверять, что код соответствует поставленным при его написании требованиям.
Соответственно, когда ты потом будешь использовать эту функцию в коде, ты можешь ожидать, что она соответствует этим требованиям, но ты не должен ожидать от нее что-то сверх этого.
Обычно сначала пишется функция, а потом тесты к ней. В случае использования TDD, мы сначала пишем тесты, а только потом код функции. TDD позволяет, например, одному человеку написать требования в виде тестов и передать их разработчику для написания кода.
Ну например, возьмем метод добавления брони $room->reserve() на определенные даты на номер в классе Room. Что он должен делать?
- он должен выдать ошибку, если выбранные даты уже заняты
- иначе, он должен добавить бронь (то есть где-то сохранить информацию, что номер забронирован на такие-то даты такими-то гостями, и это потом можно проверить)
- (тут еще могут быть дополнительные требования по проверке данных, которые я для простоты не пишу)
Имея требования, мы можем написать тесты, проверяющие их выполнение. Тут нам придется проявить смекалку и придумать, как именно их проверять. Например, для проверки второго требования можно написать такой тест (я использую синтаксис phpunit):
public function testReservedRoomIsMarkedAsOccupied()
{
$room = new Room(..);
$guest = new Guest(...);
$room->reserve($guest, new DateTime('2020-01-03'), new DateTime('2020-01-05'));
// Проверяет, что функция вернет true
$this->assertTrue($room->isOccupied(new DateTime('2020-01-04')));
// При желании еще можно написать так, хотя некоторые скажут,
// что это нужно писать в отдельном тесте
$this->assertFalse($room->isOccupied(new DateTime('2020-01-06')));
}
В случае TDD, можно использовать даже специальный язык для формулирования требований, например, Gherkin. На нем требования пишутся с использованием конструкций Given (дано) - When (если) - Then (то). Например, аналитик может записать одно из требований так (я пишу текст на русском для удобства чтения):
Feature: бронирование номера
Scenario: Забронированный номер помечается как занятый
Given Есть свободный Номер 100
And Есть Гость Иван Иванов
And Иван Иванов бронирует номер 100 с 3.01.2020 по 5.01.2020
When мы проверяем, занят ли номер 4.01.2020
Then номер помечен как занятый
Правда, судя по статьям, сами аналитики не очень любят такие языки: https://habrahabr.ru/post/275013/
> То есть в твоем примере теста, проверка свободен ли номер 4 января, это и есть требование?
Нет. Требование - функция должна позволить забронировать незанятый номер и запомнить это.
> А что проверяется в сочетаниях классов?
Некоторые классы можно тестировать отдельно, но некоторые классы не могут работать сами по себе и им нужны еще какие-то другие классы. Тогда мы их тестируем вместе.
> Например класс А может использовать классы Б и В, я проверяю тестами сначала для классов А+Б, потом для классов А+В?
Такое редко бывает, обычно бывает, что классу А нужны Б и В. Тогда в тесте для класса А мы создаем объекты Б и В и передаем их в А.
> как увидеть все требования, ничего не забыть или не напридумывать других требований?
Нужно взять каждый класс, каждый публичный метод и подумать, что мы от него хотим. Что он должен уметь делать и как себя вести в той или иной ситуации.
> А как проверять, что у меня нужный мне объект?
Объекты можно сравнить с помощью ===: if ($a === $b) выполнится только если $a и $b ссылаются на один и тот же объект.
$a = new Guest('Иван Иванов');
$b = $a;
// В $a и $b один и тот же объект, $a === $b
$c = new Guest('Иван Иванов');
$d = new Guest('Иван Иванов');
// в $c и $d разные объекты, $a !== $b
Потому я и пишу, что каждый объект обладает идентичностью и отличается от всех других объектов (даже если у них одинаковые значения всех свойств). Не нужно добавлять искуственные идентификаторы только для того, чтобы сравнивать объекты.
>>49718
>>51786
> public function __construct($rank, $rate, $isBoss, $profession)
Если ты используешь PHP7 (я надеюсь, что да), то нужно расставить тайп хинты для аргументов, а также для возвращаемых значений функций, мануал http://php.net/manual/ru/functions.arguments.php
Для $isBoss лучше использовать значения true/false вместо 1/0.
> public function GetSalary()
>
> switch ($this->rank) {
Здесь для надежности надо добавить пункт default с выбросом исключения, если ранг не равен 1, 2 или 3.
> get_class($this)::COFFE*2
Это неправильно. Во-первых, ты бы мог просто написать static::COFFEE. Во-вторых, ты не должен в базовом классе обращаться к константам, которые добавят только в наследнике.
И тут есть еще одна проблема. А где вообще гарантия, что тот, кто пишет наследника, сделает эти константы? Это ведь никак не описано и никак не проверяется.
И еще одна проблема. А что, если кто-то создаст объект класса Employee? Он ведь не помечен как абстрактный, значит создавать его не запрещено. А констант в нем нет.
В ООП (да и не только в ООП) ты должен стараться так писать код, чтобы нельзя было его неправильно использовать. Если класс Employee используется только как основа для наследования, то надо пометить его абстрактным, чтобы никто даже не пытался создать объект такого класса.
Если ты хочешь, чтобы в каждом классе профессии была определена базовая зарплата, это тоже надо зафиксировать в коде, чтобы нельзя было ее не определить при объявлении класса профессии.
В идеале, ты бы мог еще проверять данные, чтобы например при создании работника нельзя было передать неправильный ранг.
Это все делает код более надежным и позволяет обнаружить ошибки как можно раньше.
Вместо констант тут нужно сделать так:
- пометить базовый класс как абстрактный
- определить в нем абстрактные методы вроде getBaseSalary(), которые должны будут реализовать наследники. Так мы укажем, какие методы обязан реализовать наследник, и PHP не позволит это не сделать. Про абстрактные методы мельком написано в уроке по ООП (где-то рядом с задачей Вектор).
Если ты используешь для каждой профессии свой класс, то свойство profession избыточно.
> abstract class AbstractDepartment
> public $rank;
Это неправильно. Разве у Департамента есть свойство Ранг? Оно есть только у Работников.
> class BuyDepartment extends AbstractDepartment
Если департаменты отличаются только названием, то нет смысла для них делать отдельные классы. Они нужны, когда объекты одного типа различаются поведением (то есть в них есть одни и те же методы, но они разные).
Я бы советовал у Департамента сделать свойство списокРаботников и методы для приема на работу/увольнения работника.
Также, советовал бы сделать класс, представляющий всю Компанию.
И еще кое-что. Ты используешь тут публичные свойства - а значит, любой может записать в них любые значения. Разве это хорошо? Давай сделаем свойства закрытыми от доступа снаружи и сделаем методы для их изменения. Так мы во-первых, можем решить, какие свойства можно менять, а какие нет, во-вторых, мы можем гарантировать, что в них не запишут неправильное значение. Это назвыается инкапсуляция.
Минус этого подхода в том, что кода будет больше чем с публичными свойствами, но тут задача простая, так что я не вижу проблемы.
Про инкапсуляцию:
----------
Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные (помечает их private/protected), а наружу выставляет только методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, ему достаточно вызвать нужный метод, чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private, то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
При инкапсуляции автор класса строго ограничивает, что можно делать с объектом.
Как плюс, мы можем поставить какие-то проверки в методах, и запретить установку неправильных значений свойств. Таким образом, снаружи записать неправильное значение в объект будет нельзя и автор класса может гарантировать его корректную работу в любой ситуации.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
> А как проверять, что у меня нужный мне объект?
Объекты можно сравнить с помощью ===: if ($a === $b) выполнится только если $a и $b ссылаются на один и тот же объект.
$a = new Guest('Иван Иванов');
$b = $a;
// В $a и $b один и тот же объект, $a === $b
$c = new Guest('Иван Иванов');
$d = new Guest('Иван Иванов');
// в $c и $d разные объекты, $a !== $b
Потому я и пишу, что каждый объект обладает идентичностью и отличается от всех других объектов (даже если у них одинаковые значения всех свойств). Не нужно добавлять искуственные идентификаторы только для того, чтобы сравнивать объекты.
>>49718
>>51786
> public function __construct($rank, $rate, $isBoss, $profession)
Если ты используешь PHP7 (я надеюсь, что да), то нужно расставить тайп хинты для аргументов, а также для возвращаемых значений функций, мануал http://php.net/manual/ru/functions.arguments.php
Для $isBoss лучше использовать значения true/false вместо 1/0.
> public function GetSalary()
>
> switch ($this->rank) {
Здесь для надежности надо добавить пункт default с выбросом исключения, если ранг не равен 1, 2 или 3.
> get_class($this)::COFFE*2
Это неправильно. Во-первых, ты бы мог просто написать static::COFFEE. Во-вторых, ты не должен в базовом классе обращаться к константам, которые добавят только в наследнике.
И тут есть еще одна проблема. А где вообще гарантия, что тот, кто пишет наследника, сделает эти константы? Это ведь никак не описано и никак не проверяется.
И еще одна проблема. А что, если кто-то создаст объект класса Employee? Он ведь не помечен как абстрактный, значит создавать его не запрещено. А констант в нем нет.
В ООП (да и не только в ООП) ты должен стараться так писать код, чтобы нельзя было его неправильно использовать. Если класс Employee используется только как основа для наследования, то надо пометить его абстрактным, чтобы никто даже не пытался создать объект такого класса.
Если ты хочешь, чтобы в каждом классе профессии была определена базовая зарплата, это тоже надо зафиксировать в коде, чтобы нельзя было ее не определить при объявлении класса профессии.
В идеале, ты бы мог еще проверять данные, чтобы например при создании работника нельзя было передать неправильный ранг.
Это все делает код более надежным и позволяет обнаружить ошибки как можно раньше.
Вместо констант тут нужно сделать так:
- пометить базовый класс как абстрактный
- определить в нем абстрактные методы вроде getBaseSalary(), которые должны будут реализовать наследники. Так мы укажем, какие методы обязан реализовать наследник, и PHP не позволит это не сделать. Про абстрактные методы мельком написано в уроке по ООП (где-то рядом с задачей Вектор).
Если ты используешь для каждой профессии свой класс, то свойство profession избыточно.
> abstract class AbstractDepartment
> public $rank;
Это неправильно. Разве у Департамента есть свойство Ранг? Оно есть только у Работников.
> class BuyDepartment extends AbstractDepartment
Если департаменты отличаются только названием, то нет смысла для них делать отдельные классы. Они нужны, когда объекты одного типа различаются поведением (то есть в них есть одни и те же методы, но они разные).
Я бы советовал у Департамента сделать свойство списокРаботников и методы для приема на работу/увольнения работника.
Также, советовал бы сделать класс, представляющий всю Компанию.
И еще кое-что. Ты используешь тут публичные свойства - а значит, любой может записать в них любые значения. Разве это хорошо? Давай сделаем свойства закрытыми от доступа снаружи и сделаем методы для их изменения. Так мы во-первых, можем решить, какие свойства можно менять, а какие нет, во-вторых, мы можем гарантировать, что в них не запишут неправильное значение. Это назвыается инкапсуляция.
Минус этого подхода в том, что кода будет больше чем с публичными свойствами, но тут задача простая, так что я не вижу проблемы.
Про инкапсуляцию:
----------
Инкапсуляция. У этого слова есть разные определения, в том числе такие что ничего не понять, потому объясню простыми словами.
Суть инкапсуляции в том, что класс скрывает (инкапслирует) в себе логику работы с данными и сами данные (помечает их private/protected), а наружу выставляет только методы. Пользователю этих методов не важно, как класс устроен внутри, как он хранит данные, ему достаточно вызвать нужный метод, чтобы получить результат.
Это упрощает понимание кода: тебе не надо читать и разбирать код класса, достаточно прочитать название метода (и может быть комментарий к нему). Также, это упрощает изменение кода: если какое-то свойство имеет уровень private, то доступ к нему возможен только из того же класса и тебе не надо бегать по всему коду и смотреть что там с этим свойством делается, тебе достаточно просмотреть один файл с этим классом.
При инкапсуляции автор класса строго ограничивает, что можно делать с объектом.
Как плюс, мы можем поставить какие-то проверки в методах, и запретить установку неправильных значений свойств. Таким образом, снаружи записать неправильное значение в объект будет нельзя и автор класса может гарантировать его корректную работу в любой ситуации.
Инкапсуляция это хорошо. Так как весь код, который занимается одной задачей, оказывается заключен внутри одного класса. Противоположный случай это когда код (или знание о его внутреннем устройстве) вылезает из класса и размазывается по всей программе.
Если проводить аналогии, то можно представить кофе-машину. Ты нажимаешь кнопку (=вызываешь публичный метод) и получаешь кофе (=результат вызова этого метода), при этом ты не видишь что происходит внутри нее и тебе не надо в этом разбираться.
Некоторые используют наследование шаблонов, если оно есть в шаблонизаторе - с ним конечно удобнее.
> Вообще, единственное, что пришло мне в голову, это наоборот загружать на одну html страницу динамическую часть из БД с помощью аджакса, вроде и выглядит красиво,
Переусложнение.
>>49725
Не до конца отредактировал. Например:
> function spellSmallNumber($num, $female) {
> $result = array();
Должно быть
function spellSmallNumber($num, $female)
{
--->$result = array();
Без отступов тяжело читать код.
Если ты пишешь прямо в ideone, то поставь себе какой-нибудь редактор кода или IDE - такие большие куски кода неудобно писать без них.
Искать форматтеры можно по "php beautify", хотя часть из них кривые. Вот этот работает, если повозиться с настройками: http://phpbeautifier.com/beautify.php
> $hundOne = $lastTwo % 10;
Название неудачное, лучше просто lastDigit или units.
> $units = floor($lastTwo / 10) * 10;
Десятки - это tens
> if ($female == 1 or $female == 2) {
Тут по задумке передается не последняя цифра (она уже есть в числе), а 1 если используется женский род (для тысяч) или 0 для мужского. Неазвисимо от того, какое число.
Так, алгоритм примерно правильный, но код читать невозможно. Надо отформатировать правильно. Во втором посте треда вроде написано, как форматировать код.
Некоторые используют наследование шаблонов, если оно есть в шаблонизаторе - с ним конечно удобнее.
> Вообще, единственное, что пришло мне в голову, это наоборот загружать на одну html страницу динамическую часть из БД с помощью аджакса, вроде и выглядит красиво,
Переусложнение.
>>49725
Не до конца отредактировал. Например:
> function spellSmallNumber($num, $female) {
> $result = array();
Должно быть
function spellSmallNumber($num, $female)
{
--->$result = array();
Без отступов тяжело читать код.
Если ты пишешь прямо в ideone, то поставь себе какой-нибудь редактор кода или IDE - такие большие куски кода неудобно писать без них.
Искать форматтеры можно по "php beautify", хотя часть из них кривые. Вот этот работает, если повозиться с настройками: http://phpbeautifier.com/beautify.php
> $hundOne = $lastTwo % 10;
Название неудачное, лучше просто lastDigit или units.
> $units = floor($lastTwo / 10) * 10;
Десятки - это tens
> if ($female == 1 or $female == 2) {
Тут по задумке передается не последняя цифра (она уже есть в числе), а 1 если используется женский род (для тысяч) или 0 для мужского. Неазвисимо от того, какое число.
Так, алгоритм примерно правильный, но код читать невозможно. Надо отформатировать правильно. Во втором посте треда вроде написано, как форматировать код.
Насчет хранения истории - сложный вопрос. Давай рассмотрим варианты:
1) хранить историю бронирований только в Room
Плюс: данные не дублируются, значит не может быть противоречий
Плюс: работает инкапсуляция, Room знает, когда она занята или свободна
Минус: если мы хотим получить историю по клиенту, мы должны обойти все комнаты. Также, а что делать при удалении комнаты? Куда денется история?
Минус: чтобы получить данные по отелю за сутки, надо обойти все комнаты.
Минус: гость не знает, где он был и когда
"обойти все комнаты" - само по себе не такая уж проблема. Проблема, что делать, когда мы захотим удалить комнату? Наверно, придется делать soft-delete - то есть помечать комнату закрытой, но не удалять ее.
2) дублировать историю в Room и Guest
Плюс: теперь у Гостя появилась "память".
Примерно тот же набор минусов, только теперь данные дублируются и мы должны следить, чтобы всегда добавление/отмена бронирования происходило в 2 местах. А если в процессе этого вылетит исключение? То есть мы создаем новую проблему - отслеживание согласованности данных - которой не было бы, если бы данные не дублировались.
Также, хранение истории в 2 местах не повлечет ли дублирование кода?
3) хранить историю в Hotel (или в HistoryLog, который хранится внутри Hotel)
Плюс: данные не дублируются
Плюс: удобно строить отчеты
Теперь у нас Room и Guest становятся классами почти без логики, а вся логика перемещается в Hotel. Немного меньше разделения обязанностей.
4) сделать класс HistoryLog, держать на него ссылку в Hotel и передавать (инжектировать) во все Room и Guest при создании
Плюс: централизованное хранение истории, при этом Room/Guest могут сами с ней работать
Минус: новые объекты Room/Guest теперь можно создавать только через Hotel, нельзя создать через new
Минус: а что, если Гость хочет остановиться в нескольких Гостиницах?
То есть попробуй выписывать разные варианты и искать их плюсы/минусы.
Насчет хранения истории - сложный вопрос. Давай рассмотрим варианты:
1) хранить историю бронирований только в Room
Плюс: данные не дублируются, значит не может быть противоречий
Плюс: работает инкапсуляция, Room знает, когда она занята или свободна
Минус: если мы хотим получить историю по клиенту, мы должны обойти все комнаты. Также, а что делать при удалении комнаты? Куда денется история?
Минус: чтобы получить данные по отелю за сутки, надо обойти все комнаты.
Минус: гость не знает, где он был и когда
"обойти все комнаты" - само по себе не такая уж проблема. Проблема, что делать, когда мы захотим удалить комнату? Наверно, придется делать soft-delete - то есть помечать комнату закрытой, но не удалять ее.
2) дублировать историю в Room и Guest
Плюс: теперь у Гостя появилась "память".
Примерно тот же набор минусов, только теперь данные дублируются и мы должны следить, чтобы всегда добавление/отмена бронирования происходило в 2 местах. А если в процессе этого вылетит исключение? То есть мы создаем новую проблему - отслеживание согласованности данных - которой не было бы, если бы данные не дублировались.
Также, хранение истории в 2 местах не повлечет ли дублирование кода?
3) хранить историю в Hotel (или в HistoryLog, который хранится внутри Hotel)
Плюс: данные не дублируются
Плюс: удобно строить отчеты
Теперь у нас Room и Guest становятся классами почти без логики, а вся логика перемещается в Hotel. Немного меньше разделения обязанностей.
4) сделать класс HistoryLog, держать на него ссылку в Hotel и передавать (инжектировать) во все Room и Guest при создании
Плюс: централизованное хранение истории, при этом Room/Guest могут сами с ней работать
Минус: новые объекты Room/Guest теперь можно создавать только через Hotel, нельзя создать через new
Минус: а что, если Гость хочет остановиться в нескольких Гостиницах?
То есть попробуй выписывать разные варианты и искать их плюсы/минусы.
Не лучше ли тут реализовать это не через store? То есть у нас есть условно говоря, клиент API. Мы в нем можем предусмотреть состояние залогиненности/незалогиненности. И пусть он об этом сообщает, что нужен логин:
var client = new ApiClient;
client.onAuthRequested(function () {
var popup = showAuthWindow();
popup.onSubmit(function (user, pass) {
// перезапускает провалившиеся запросы
client.updateCredentials(user, pass);
});
});
// делаем запрос через API
var promise = client.getSomeData();
То есть вынести это в отдельную сущность, не использовать для очереди запросов store. Зачем все в store тащить-то? Получится же God Object.
Кстати, сам ApiClient тоже можно разделить на 2 класса - класс, который умеет делать запросы и класс, который умеет повторять их при различных ошибках.
> Но есть зависимость "export function setStore(s)", причем она используется только для запуска метода store.dispatch(loginRequired(request)), можно передать только сам метод dispatch() а не store целиком.
Сделана она неудачно, так как можно вызвать другие методы модуля, не задав store. Более того, тут еще и жестко задана невозможность использовать более одного store. Они модули используют как синглтон.
А в случае с классами мы могли бы сделать класс и передавать store в конструктор. Еще можно не делать класс, а просто добавить store в аргументы функции, которым он нужен.
> Но если все приложение использует react+redux, то немного странно делать модальное окно не на основе компонента react?
Не знаю, а почему нет? В моем понимании:
store - это что-то вроде модели, хранящей состояние. Это не совсем модель из MVC с данными приложения, так как она хранит еще и состояние интерфейса (то, что иногда называют ViewModel).
окно - это view, отображающее данные из модели. Никто не запрещает сделать каждое окно отдельным view, и создавать/удалять их не через react. Я, кстати, даже не вижу проблем с тем, чтобы делать для некоторых окон свой store - а почему нет? Разделение ответственности.
А так, подход react/redux - получается, мы делаем одно мегавью, в котором внутри есть все попапы. И при любом изменении модели мы перерендерим все это мегавью и все попапы в нем.
У меня просто ощущение, что реакт задумывался, условно, для каких-то интерактивных мест на странице, например, сложных форм, каких-то редакторов. А не для того, чтобы целиком все на нем делать.
Не лучше ли тут реализовать это не через store? То есть у нас есть условно говоря, клиент API. Мы в нем можем предусмотреть состояние залогиненности/незалогиненности. И пусть он об этом сообщает, что нужен логин:
var client = new ApiClient;
client.onAuthRequested(function () {
var popup = showAuthWindow();
popup.onSubmit(function (user, pass) {
// перезапускает провалившиеся запросы
client.updateCredentials(user, pass);
});
});
// делаем запрос через API
var promise = client.getSomeData();
То есть вынести это в отдельную сущность, не использовать для очереди запросов store. Зачем все в store тащить-то? Получится же God Object.
Кстати, сам ApiClient тоже можно разделить на 2 класса - класс, который умеет делать запросы и класс, который умеет повторять их при различных ошибках.
> Но есть зависимость "export function setStore(s)", причем она используется только для запуска метода store.dispatch(loginRequired(request)), можно передать только сам метод dispatch() а не store целиком.
Сделана она неудачно, так как можно вызвать другие методы модуля, не задав store. Более того, тут еще и жестко задана невозможность использовать более одного store. Они модули используют как синглтон.
А в случае с классами мы могли бы сделать класс и передавать store в конструктор. Еще можно не делать класс, а просто добавить store в аргументы функции, которым он нужен.
> Но если все приложение использует react+redux, то немного странно делать модальное окно не на основе компонента react?
Не знаю, а почему нет? В моем понимании:
store - это что-то вроде модели, хранящей состояние. Это не совсем модель из MVC с данными приложения, так как она хранит еще и состояние интерфейса (то, что иногда называют ViewModel).
окно - это view, отображающее данные из модели. Никто не запрещает сделать каждое окно отдельным view, и создавать/удалять их не через react. Я, кстати, даже не вижу проблем с тем, чтобы делать для некоторых окон свой store - а почему нет? Разделение ответственности.
А так, подход react/redux - получается, мы делаем одно мегавью, в котором внутри есть все попапы. И при любом изменении модели мы перерендерим все это мегавью и все попапы в нем.
У меня просто ощущение, что реакт задумывался, условно, для каких-то интерактивных мест на странице, например, сложных форм, каких-то редакторов. А не для того, чтобы целиком все на нем делать.
1. поднять сервер.
2. поднять доман на локалхосте.
3. всё это запустить и протестить.
4. Подключиться к гитхабу - залить туда репозиторий.
>>52037
>1. поднять сервер.
>2. поднять доман на локалхосте.
>3. всё это запустить и протестить.
почитать интернеты, например https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-16-04
>4. Подключиться к гитхабу - залить туда репозиторий.
создать репозиторий на гитхабе, скопировать код "git add remote ..." из его интерфейса, потом на локальном хосте написать git init, git add ., git push origin master
Дайте подсказку как это сделать правильно, а то я сидел, думал, но высрал только это.
Используй циклы вместо 9 условий. Тебе нужно всего лишь рост каждого одноклассника сравнить с ростом Антона.
Твоя реализация такая, чисто человеческая. Представь, что у тебя не было бы заданного массива, а файл с произвольными данными об одноклассниках какого-то анона. Тут уже этот велосипед не сработает.
>Не лучше ли тут реализовать это не через store? То есть у нас есть условно говоря, клиент API. Мы в нем можем предусмотреть состояние залогиненности/незалогиненности. И пусть он об этом сообщает, что нужен логин:
>
>var client = new ApiClient;
>
Тогда нужно будет соединить его с основным приложением (я предполагаю случай, когда реакт+редакс app - основное приложение, компонент базовый элемент интерфейса наследующий React класс Component):
1. Можно импортировать его как модуль в каждом компоненте, где необходимо что-то отправлять или получать от api, при этом данные полученные от ApiClient отправляются компонентом в store с помощью dispatch(somAction(data)); Компонент знает о ApiClient и его методах.
2. Сделать middleware класс, который слушает основной поток событий от компонентов, и реагирует на определенные события, запуская ApiClient.someFuction(); Middleware класс знает о ApiClient и о App (store.dispatch() и определенных Action).
3. Можно сделать компонент ApiClient, который имеет локальный state, в котором хранит свои специфические данные, например очередь запросов, и подписан на определенные изменения store, которые являются условием инициации отправки запросов, также умеет в dispatch() как и обычные компоненты. Именно так реализована библиотека Redux-Json-Api, которая позволяет отправлять и получать запросы в формате jsonapi, выковыривать из них данные и нормализовав сохранять в store
https://github.com/redux-json-api/redux-json-api
Т.е. возможность иметь отдельный ApiClient, который не знает о store это вариант 1 и 2. Я пока не могу в полной мере оценить плюсы и минусы каждого подхода хотя и пробовал оба варианта.
>>52028
>Более того, тут еще и жестко задана невозможность использовать более одного store. Они модули используют как синглтон.
Тут такая религия, store един.
с оф сайта редакс:
Redux can be described in three fundamental principles:
1.Single source of truth
The state of your whole application is stored in an object tree within a single store.
Некоторые последователи предлагают таки хранить часть данных в локальном state компонента, например информация о поле формы, валидна инфа в поле или нет.
>>52028
>> Но если все приложение использует react+redux, то немного странно делать модальное окно не на основе компонента react?
>Не знаю, а почему нет?
С помощью react мы можем сделать модальное окно, используя кнопки и поля ввода, для которых мы уже создали компоненты. Если даже это и не удобно, то во всяком случае соблюдается единый стиль описания html элементов.
>В моем понимании:
>store - это что-то вроде модели, хранящей состояние. Это не совсем модель из MVC с данными приложения, так как она хранит еще и состояние интерфейса (то, что иногда называют ViewModel).
>
>окно - это view, отображающее данные из модели. Никто не запрещает сделать каждое окно отдельным view, и создавать/удалять их не через react. Я, кстати, даже не вижу проблем с тем, чтобы делать для некоторых окон свой store - а почему нет? Разделение ответственности.
Вообще у компонентов есть способ хранить состояние - local state. Мы можем там хранить данные относящиеся к UI.
React предлагает компоненты, классы которые позволяют делать не связанные между собой элементы интерфейса, которые могут хранить свое состояние и отрисовывать html элементы описанные с помощью JSX. Иметь свои обработчики событий в качестве методов. Бонусом, компоненты умеют в композицию, т.е. компонент форма может быть собрана из компонента поле-ввода и компонента кнопки. В дочерние элементы данные передаются по цепочке через props, который передается в конструктор компонентов.
Rudux нужен для того, чтобы создать единое хранилище состояния всего приложения. Store - это хранилище. Изменение в нем происходит единственным способом: с помощью reducer, это функции, которые принимают в качестве аргументов объекты action и предыдущую версию store. Action это объекты контейнеры, имеющие определенные типы и содержащие данные. Все участники вечеринки могут получить доступ к функции store.dispatch(someAction), после запуска которого someAction попадет в цепочку редьюсеров для обработки. А компоненты могут "подписаться" на изменение определенных данных в store и получать их каждый раз, когда они изменятся. Т.е. данные поступают в store только с помощью store.dispatch(someAction), а из store в компоненты через props, каждый раз, когда изменяется store.
>А так, подход react/redux - получается, мы делаем одно мегавью, в котором внутри есть все попапы. И при любом изменении модели мы перерендерим все это мегавью и все попапы в нем.
DOM не обязательно перерисовывается при изменении store, т.к. данные могут не затрагивать сам интерфейс, а только их внутреннее хранилище local state или же просто не один из компонентов не подписан на изменение этих данных.
>Не лучше ли тут реализовать это не через store? То есть у нас есть условно говоря, клиент API. Мы в нем можем предусмотреть состояние залогиненности/незалогиненности. И пусть он об этом сообщает, что нужен логин:
>
>var client = new ApiClient;
>
Тогда нужно будет соединить его с основным приложением (я предполагаю случай, когда реакт+редакс app - основное приложение, компонент базовый элемент интерфейса наследующий React класс Component):
1. Можно импортировать его как модуль в каждом компоненте, где необходимо что-то отправлять или получать от api, при этом данные полученные от ApiClient отправляются компонентом в store с помощью dispatch(somAction(data)); Компонент знает о ApiClient и его методах.
2. Сделать middleware класс, который слушает основной поток событий от компонентов, и реагирует на определенные события, запуская ApiClient.someFuction(); Middleware класс знает о ApiClient и о App (store.dispatch() и определенных Action).
3. Можно сделать компонент ApiClient, который имеет локальный state, в котором хранит свои специфические данные, например очередь запросов, и подписан на определенные изменения store, которые являются условием инициации отправки запросов, также умеет в dispatch() как и обычные компоненты. Именно так реализована библиотека Redux-Json-Api, которая позволяет отправлять и получать запросы в формате jsonapi, выковыривать из них данные и нормализовав сохранять в store
https://github.com/redux-json-api/redux-json-api
Т.е. возможность иметь отдельный ApiClient, который не знает о store это вариант 1 и 2. Я пока не могу в полной мере оценить плюсы и минусы каждого подхода хотя и пробовал оба варианта.
>>52028
>Более того, тут еще и жестко задана невозможность использовать более одного store. Они модули используют как синглтон.
Тут такая религия, store един.
с оф сайта редакс:
Redux can be described in three fundamental principles:
1.Single source of truth
The state of your whole application is stored in an object tree within a single store.
Некоторые последователи предлагают таки хранить часть данных в локальном state компонента, например информация о поле формы, валидна инфа в поле или нет.
>>52028
>> Но если все приложение использует react+redux, то немного странно делать модальное окно не на основе компонента react?
>Не знаю, а почему нет?
С помощью react мы можем сделать модальное окно, используя кнопки и поля ввода, для которых мы уже создали компоненты. Если даже это и не удобно, то во всяком случае соблюдается единый стиль описания html элементов.
>В моем понимании:
>store - это что-то вроде модели, хранящей состояние. Это не совсем модель из MVC с данными приложения, так как она хранит еще и состояние интерфейса (то, что иногда называют ViewModel).
>
>окно - это view, отображающее данные из модели. Никто не запрещает сделать каждое окно отдельным view, и создавать/удалять их не через react. Я, кстати, даже не вижу проблем с тем, чтобы делать для некоторых окон свой store - а почему нет? Разделение ответственности.
Вообще у компонентов есть способ хранить состояние - local state. Мы можем там хранить данные относящиеся к UI.
React предлагает компоненты, классы которые позволяют делать не связанные между собой элементы интерфейса, которые могут хранить свое состояние и отрисовывать html элементы описанные с помощью JSX. Иметь свои обработчики событий в качестве методов. Бонусом, компоненты умеют в композицию, т.е. компонент форма может быть собрана из компонента поле-ввода и компонента кнопки. В дочерние элементы данные передаются по цепочке через props, который передается в конструктор компонентов.
Rudux нужен для того, чтобы создать единое хранилище состояния всего приложения. Store - это хранилище. Изменение в нем происходит единственным способом: с помощью reducer, это функции, которые принимают в качестве аргументов объекты action и предыдущую версию store. Action это объекты контейнеры, имеющие определенные типы и содержащие данные. Все участники вечеринки могут получить доступ к функции store.dispatch(someAction), после запуска которого someAction попадет в цепочку редьюсеров для обработки. А компоненты могут "подписаться" на изменение определенных данных в store и получать их каждый раз, когда они изменятся. Т.е. данные поступают в store только с помощью store.dispatch(someAction), а из store в компоненты через props, каждый раз, когда изменяется store.
>А так, подход react/redux - получается, мы делаем одно мегавью, в котором внутри есть все попапы. И при любом изменении модели мы перерендерим все это мегавью и все попапы в нем.
DOM не обязательно перерисовывается при изменении store, т.к. данные могут не затрагивать сам интерфейс, а только их внутреннее хранилище local state или же просто не один из компонентов не подписан на изменение этих данных.
Вот так? https://ideone.com/TIKGLG
Вроде бы получилось. Спасибо! Но возможно это снова говнокод
Хорошо, спасибо за помощь
>>37298
Надо бы добавить ридми. Прочитай комментарии к задаче, там это написано: https://github.com/codedokode/pasta/blob/master/student-list.md#Публикация-проекта - там же есть ссылка на пример README.
А то открываешь, видишь кучу файлов и даже непонятно, что это. Непонятно, как установить и что надо делать. Пришлось гуглить, разбираться в документации Laravel итд. Очень неудобно.
Желательно убрать код, который не используется. Вот зачем нужен этот файл например? https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/tests/Feature/ExampleTest.php
Если ты не используешь тесты, то файлы от них не нужно добавлять.
Также, у тебя там прописана сборка JS-файлов, подключение Vue. Но он нигде не используется. Зачем тогда это добавлять? Из-за этого труднее найти, где именно твой код, а где стандартные заготовки.
Дальше, мне не нравится, что в composer.json прописан "name": "laravel/laravel". Как будто бы это не твое приложение, а официальный репозиторий фреймворка Laravel. По моему, это вводит в заблуждение. Поле name предназначено в первую очередь для добавляемых в репозиторий packagist библиотек, а в твоем случае оно вообще не нужно.
У тебя (вроде бы) сделано так, что таблица студентов недоступна без авторизации, но вообще в задаче она должна выводиться для любых пользователей.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/app/Http/Controllers/Table/TableController.php#L22
Разве это правильно, что в одном случае передается переменная в шаблон, а в другом - нет?
> return view('table', ['orderBy' => $request['orderBy'], 'users' => $users, 'search' => $searchWord]);
> return view('table', ['users' => $users, 'orderBy' => $request['orderBy']]);
Также, не стоило копировать 2 раза эти строки
> $orderBy = $this->validateOrderByParam($request['orderBy']);
> $users = $this->getUsers($request, $orderBy);
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/app/Http/Controllers/Table/TableController.php#L47
Получение данных по идее должно быть в модели, а не в контроллере. Ты тут пишешь типичный "толстый контроллер".
Ты используешь в форме регистрации PUT, но ведь браузеры не поддерживают этот метод и там будет использована POST-форма с скрытым полем, а на стороне Ларавел будет сымитировано поступление PUT-запроса. Не переусложнение ли?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/app/Http/Controllers/Profile/ProfileController.php#L22
По условиям задачи требовалось разрешить пробелы, дефисы и апострофы в именах.
> 'birth_year' => ['required', 'string', 'regex:@^199[0-9]|200[0-5]$@iu'],
Люди старше 28 лет - не допускаются?
Далее, я попробовал запустить у себя проект с помощью встроенного в PHP веб-сервера - он показывает страницу "Whoops, looks like something went wrong" (2 раза), но подробности ошибки нигде не выводятся - ни на странице, ни в консоли (выяснилось, что надо создать .env, но я не понимаю, почему по умолчанию подробности ошибки не пишутся в консоль - как это отлаживать?).
В форме регистрации подписи к полям в нечеловекочитаемом виде вроде "second_name". Также, сообщения об ошибках почему-то на английском. Плохо смешивать разные языки в интерфейсе. В меню также надписи на английском. А где-то в форме подсказки на русском.
Также, в задаче была предложена безпарольная регистрация - ты не хочешь сделать такую же? Наверяка в Ларавель это можно настроить.
При сортировке никак не выделена колонка и направление сортировки. Нужно выводить стрелочку или треугольничек или еще как-то показать режим сортировки.
Если при поиске ничего не найдено, то надо бы выводить соответствующую надпись, а не шапку от пустой таблицы.
> protected function validator(array $data)
Имена функций обычно начинаются с глагола, сделайЧтоТо()
> `birth_year` int(11) NOT NULL
В таблице можно было бы использовать тип YEAR.
Насчет этой таблицы https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/database/migrations/2014_10_12_100000_create_password_resets_table.php - разве токен сброса пароля не должен привязываться к пользователю?
Насчет форм - я вижу, ты используешь бутстрап. Так почему бы не использовать стандартные стили бустрапа для форм? http://getbootstrap.com/docs/3.3/css/#forms
Так, конечно, при использовании Ларавел тут получается очень мало твоего кода (так-то это хорошо, но у нас ведь задача научиться). На мощном фреймворке лучше было бы делать задачу вроде TestHub, где все сложнее. Ну или попробовать сделать безпарольную авторизацию, как описано в задаче.
>>37298
Надо бы добавить ридми. Прочитай комментарии к задаче, там это написано: https://github.com/codedokode/pasta/blob/master/student-list.md#Публикация-проекта - там же есть ссылка на пример README.
А то открываешь, видишь кучу файлов и даже непонятно, что это. Непонятно, как установить и что надо делать. Пришлось гуглить, разбираться в документации Laravel итд. Очень неудобно.
Желательно убрать код, который не используется. Вот зачем нужен этот файл например? https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/tests/Feature/ExampleTest.php
Если ты не используешь тесты, то файлы от них не нужно добавлять.
Также, у тебя там прописана сборка JS-файлов, подключение Vue. Но он нигде не используется. Зачем тогда это добавлять? Из-за этого труднее найти, где именно твой код, а где стандартные заготовки.
Дальше, мне не нравится, что в composer.json прописан "name": "laravel/laravel". Как будто бы это не твое приложение, а официальный репозиторий фреймворка Laravel. По моему, это вводит в заблуждение. Поле name предназначено в первую очередь для добавляемых в репозиторий packagist библиотек, а в твоем случае оно вообще не нужно.
У тебя (вроде бы) сделано так, что таблица студентов недоступна без авторизации, но вообще в задаче она должна выводиться для любых пользователей.
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/app/Http/Controllers/Table/TableController.php#L22
Разве это правильно, что в одном случае передается переменная в шаблон, а в другом - нет?
> return view('table', ['orderBy' => $request['orderBy'], 'users' => $users, 'search' => $searchWord]);
> return view('table', ['users' => $users, 'orderBy' => $request['orderBy']]);
Также, не стоило копировать 2 раза эти строки
> $orderBy = $this->validateOrderByParam($request['orderBy']);
> $users = $this->getUsers($request, $orderBy);
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/app/Http/Controllers/Table/TableController.php#L47
Получение данных по идее должно быть в модели, а не в контроллере. Ты тут пишешь типичный "толстый контроллер".
Ты используешь в форме регистрации PUT, но ведь браузеры не поддерживают этот метод и там будет использована POST-форма с скрытым полем, а на стороне Ларавел будет сымитировано поступление PUT-запроса. Не переусложнение ли?
https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/app/Http/Controllers/Profile/ProfileController.php#L22
По условиям задачи требовалось разрешить пробелы, дефисы и апострофы в именах.
> 'birth_year' => ['required', 'string', 'regex:@^199[0-9]|200[0-5]$@iu'],
Люди старше 28 лет - не допускаются?
Далее, я попробовал запустить у себя проект с помощью встроенного в PHP веб-сервера - он показывает страницу "Whoops, looks like something went wrong" (2 раза), но подробности ошибки нигде не выводятся - ни на странице, ни в консоли (выяснилось, что надо создать .env, но я не понимаю, почему по умолчанию подробности ошибки не пишутся в консоль - как это отлаживать?).
В форме регистрации подписи к полям в нечеловекочитаемом виде вроде "second_name". Также, сообщения об ошибках почему-то на английском. Плохо смешивать разные языки в интерфейсе. В меню также надписи на английском. А где-то в форме подсказки на русском.
Также, в задаче была предложена безпарольная регистрация - ты не хочешь сделать такую же? Наверяка в Ларавель это можно настроить.
При сортировке никак не выделена колонка и направление сортировки. Нужно выводить стрелочку или треугольничек или еще как-то показать режим сортировки.
Если при поиске ничего не найдено, то надо бы выводить соответствующую надпись, а не шапку от пустой таблицы.
> protected function validator(array $data)
Имена функций обычно начинаются с глагола, сделайЧтоТо()
> `birth_year` int(11) NOT NULL
В таблице можно было бы использовать тип YEAR.
Насчет этой таблицы https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist3/blob/master/database/migrations/2014_10_12_100000_create_password_resets_table.php - разве токен сброса пароля не должен привязываться к пользователю?
Насчет форм - я вижу, ты используешь бутстрап. Так почему бы не использовать стандартные стили бустрапа для форм? http://getbootstrap.com/docs/3.3/css/#forms
Так, конечно, при использовании Ларавел тут получается очень мало твоего кода (так-то это хорошо, но у нас ведь задача научиться). На мощном фреймворке лучше было бы делать задачу вроде TestHub, где все сложнее. Ну или попробовать сделать безпарольную авторизацию, как описано в задаче.
Тебе надо освоить:
- основы командной строки, можно начать отсюда https://github.com/codedokode/pasta/blob/master/soft/cli.md
- основы линукса (почитать любой учебник для начинающих, про файловую систему, про права, про пользователей, про основные команды вроде ls или rm)
- используемый в твоем дистрибутиве пакетный менеджер (apt-get)
Тебе надо настроить виртуалку так, чтобы к программам в ней можно было подсоединяться с основной системы. Для этого придется добавить второй сетевой интерфейс. Тут это описано: https://gist.github.com/codedokode/420c8c12a1edae25f0ec (то, что про Дебиан - можешь не читать, хотя Убунта и сделана на его основе).
Чтобы "поднять домен на локалхосте", тебе достаточно в файл hosts на основной системе приписать любое доменное имя и IP-адрес виртуалки.
Чтобы "поднять сервер" в виртуалке, надо установить и настроить (отредактировать конфиги) там нужные программы (Апач + PHP либо можно исопльзовать встроенный в PHP сервер, как описано тут https://github.com/codedokode/pasta/blob/master/soft/web-server.md ).
У меня есть инфа про установку Апача, но она ориентирована на винду и не все там будет актуально: https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Итак, нужно:
- настроить второй интерфейс на виртуалке
- прописать домнен в hosts
- установить, настроить и запустить в виртуалке веб-сервер (Apache, nginx или встроенный в PHP)
После этого из браузера можно будет зайти на сайт.
Чтобы залить существующий репозиторий на гитхаб, надо сделать слудующие шаги:
- создать на гитхабе пустой репозиторий без всего
- локально добавить новый remote (git remote add origin ..), указав URL, который тебе выдаст гитхаб на первом шаге
- сделать git push origin HEAD
Подробне про работу с гитом есть учебник на русском https://git-scm.com/book/ru/v2 и глава в нем https://git-scm.com/book/ru/v2/Основы-Git-Работа-с-удалёнными-репозиториями
Тебе надо освоить:
- основы командной строки, можно начать отсюда https://github.com/codedokode/pasta/blob/master/soft/cli.md
- основы линукса (почитать любой учебник для начинающих, про файловую систему, про права, про пользователей, про основные команды вроде ls или rm)
- используемый в твоем дистрибутиве пакетный менеджер (apt-get)
Тебе надо настроить виртуалку так, чтобы к программам в ней можно было подсоединяться с основной системы. Для этого придется добавить второй сетевой интерфейс. Тут это описано: https://gist.github.com/codedokode/420c8c12a1edae25f0ec (то, что про Дебиан - можешь не читать, хотя Убунта и сделана на его основе).
Чтобы "поднять домен на локалхосте", тебе достаточно в файл hosts на основной системе приписать любое доменное имя и IP-адрес виртуалки.
Чтобы "поднять сервер" в виртуалке, надо установить и настроить (отредактировать конфиги) там нужные программы (Апач + PHP либо можно исопльзовать встроенный в PHP сервер, как описано тут https://github.com/codedokode/pasta/blob/master/soft/web-server.md ).
У меня есть инфа про установку Апача, но она ориентирована на винду и не все там будет актуально: https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Итак, нужно:
- настроить второй интерфейс на виртуалке
- прописать домнен в hosts
- установить, настроить и запустить в виртуалке веб-сервер (Apache, nginx или встроенный в PHP)
После этого из браузера можно будет зайти на сайт.
Чтобы залить существующий репозиторий на гитхаб, надо сделать слудующие шаги:
- создать на гитхабе пустой репозиторий без всего
- локально добавить новый remote (git remote add origin ..), указав URL, который тебе выдаст гитхаб на первом шаге
- сделать git push origin HEAD
Подробне про работу с гитом есть учебник на русском https://git-scm.com/book/ru/v2 и глава в нем https://git-scm.com/book/ru/v2/Основы-Git-Работа-с-удалёнными-репозиториями
Да, твое решение неудачное, так как надо на каждого ученика писать блок в if. Нужно использовать цикл по массиву таким образом:
- завести переменную и сохранить в нее 0
- взять по очереди каждого ученика, поместить его имя в $name, а рост в $height (это делает команда foreach)
- если рост текущего ученика больше роста школьника, то увеличить переменную на 1
- когда цикл закончится, в переменной будет ответ
>>52215
Вообще, мне не очень нравится идея использовать реакт для основы приложения. Как я понимаю, там придется хранить все данные приложения в сторе в виде одного гигантского объекта, при любом изменении создавать копию этого объекта (так как иммутабельность), перерендеривать все вью и это будет наверно не очень быстро работать. Хотя, тут надо тестировать. Сделал бы кто-нибудь задачу про SPA на реакте...
По мне, так он бы больше подошел именно как вью, управляющий каким-то одним экраном или попапом. При смене экранов можно уничтожать старое реакт-приложение и создавать новое. Ну это просто идея, не проверенная на практике. Не знаю, как она согласуется с redux.
> Тогда нужно будет соединить его с основным приложением
По идее обращения к API должны идти в action creator. Как тут описано например: https://github.com/reactjs/redux/issues/291#issuecomment-122829159
> Можно импортировать его как модуль в каждом компоненте, где необходимо что-то отправлять или получать от api, при этом данные полученные от ApiClient отправляются компонентом в store с помощью dispatch(somAction(data));
А с какой стати компоненты должны работать с АПИ? Компоненты же просто отображают переданные им сверху (взятые из стора и пропущенные через редюсер) данные?
> Можно сделать компонент ApiClient, который имеет локальный state,
Зачем работу с АПИ делать компонентом Реакта? Реакт это просто View, библиотека для отображения данных.
> Тут такая религия, store един.
Ну если мы решим, что у нас за каждый экран отвечает свой стор (и свое реакт-приложение), то уже получается не един.
> С помощью react мы можем сделать модальное окно, используя кнопки и поля ввода, для которых мы уже создали компоненты. Если даже это и не удобно, то во всяком случае соблюдается единый стиль описания html элементов.
Так в моем вариант тоже, просто попап будет отдельным независимым реакт-приложением со своим стором.
> DOM не обязательно перерисовывается при изменении store,
Я не про DOM. А про компоненты реакта, которые имеют метод render() и генерируют объекты виртуального DOM. Представь что у тебя чат, слева список из 100 контактов (каждый как компонент), справа - 100 сообщений. Плюс еще скрытые компоненты разных попапов. То есть куча компонентов реакта. При выполнении любого действия со стором все это дерево компонентов обходится, вызывается метод render, генерируется огромный виртуальный DOM, сравнивается с предыдущей версией? Или нет?
Сделал бы кто-нибудь что-нибудь сложное на реакте с кучей форм и таблиц, можно было бы потестить.
Как я понимаю из https://reactjs.org/docs/optimizing-performance.html#avoid-reconciliation оптимизацию надо включать вручную - либо наследуюясь от PureComponent, либо вручную определяя, изменится ли представление компонента.
> Even though React only updates the changed DOM nodes, re-rendering still takes some time. In many cases it’s not a problem, but if the slowdown is noticeable, you can speed all of this up by overriding the lifecycle function shouldComponentUpdate,...
> In most cases, instead of writing shouldComponentUpdate() by hand, you can inherit from React.PureComponent. It is equivalent to implementing shouldComponentUpdate() with a shallow comparison of current and previous props and state.
Я бы еще обратил внимание на "shallow comparison" - это доабвляет свои подвохи, которые там описаны ниже: https://reactjs.org/docs/optimizing-performance.html#the-power-of-not-mutating-data
Да, твое решение неудачное, так как надо на каждого ученика писать блок в if. Нужно использовать цикл по массиву таким образом:
- завести переменную и сохранить в нее 0
- взять по очереди каждого ученика, поместить его имя в $name, а рост в $height (это делает команда foreach)
- если рост текущего ученика больше роста школьника, то увеличить переменную на 1
- когда цикл закончится, в переменной будет ответ
>>52215
Вообще, мне не очень нравится идея использовать реакт для основы приложения. Как я понимаю, там придется хранить все данные приложения в сторе в виде одного гигантского объекта, при любом изменении создавать копию этого объекта (так как иммутабельность), перерендеривать все вью и это будет наверно не очень быстро работать. Хотя, тут надо тестировать. Сделал бы кто-нибудь задачу про SPA на реакте...
По мне, так он бы больше подошел именно как вью, управляющий каким-то одним экраном или попапом. При смене экранов можно уничтожать старое реакт-приложение и создавать новое. Ну это просто идея, не проверенная на практике. Не знаю, как она согласуется с redux.
> Тогда нужно будет соединить его с основным приложением
По идее обращения к API должны идти в action creator. Как тут описано например: https://github.com/reactjs/redux/issues/291#issuecomment-122829159
> Можно импортировать его как модуль в каждом компоненте, где необходимо что-то отправлять или получать от api, при этом данные полученные от ApiClient отправляются компонентом в store с помощью dispatch(somAction(data));
А с какой стати компоненты должны работать с АПИ? Компоненты же просто отображают переданные им сверху (взятые из стора и пропущенные через редюсер) данные?
> Можно сделать компонент ApiClient, который имеет локальный state,
Зачем работу с АПИ делать компонентом Реакта? Реакт это просто View, библиотека для отображения данных.
> Тут такая религия, store един.
Ну если мы решим, что у нас за каждый экран отвечает свой стор (и свое реакт-приложение), то уже получается не един.
> С помощью react мы можем сделать модальное окно, используя кнопки и поля ввода, для которых мы уже создали компоненты. Если даже это и не удобно, то во всяком случае соблюдается единый стиль описания html элементов.
Так в моем вариант тоже, просто попап будет отдельным независимым реакт-приложением со своим стором.
> DOM не обязательно перерисовывается при изменении store,
Я не про DOM. А про компоненты реакта, которые имеют метод render() и генерируют объекты виртуального DOM. Представь что у тебя чат, слева список из 100 контактов (каждый как компонент), справа - 100 сообщений. Плюс еще скрытые компоненты разных попапов. То есть куча компонентов реакта. При выполнении любого действия со стором все это дерево компонентов обходится, вызывается метод render, генерируется огромный виртуальный DOM, сравнивается с предыдущей версией? Или нет?
Сделал бы кто-нибудь что-нибудь сложное на реакте с кучей форм и таблиц, можно было бы потестить.
Как я понимаю из https://reactjs.org/docs/optimizing-performance.html#avoid-reconciliation оптимизацию надо включать вручную - либо наследуюясь от PureComponent, либо вручную определяя, изменится ли представление компонента.
> Even though React only updates the changed DOM nodes, re-rendering still takes some time. In many cases it’s not a problem, but if the slowdown is noticeable, you can speed all of this up by overriding the lifecycle function shouldComponentUpdate,...
> In most cases, instead of writing shouldComponentUpdate() by hand, you can inherit from React.PureComponent. It is equivalent to implementing shouldComponentUpdate() with a shallow comparison of current and previous props and state.
Я бы еще обратил внимание на "shallow comparison" - это доабвляет свои подвохи, которые там описаны ниже: https://reactjs.org/docs/optimizing-performance.html#the-power-of-not-mutating-data
Этот тред закрыт.
Если я кому-то не ответил, напомните о себе в новом треде.
$result = $pdo->query("SELECT mail FROM users WHERE mail='$mail'");
if (!$result){
$reg = $pdo->query("INSERT INTO users VALUES('$name','$mail','$password','0')");
}else {
MessageSend (1, 'Пользователь с таким E-mail адресом уже существует!');
}
Что не так делаю?
у меня почему-то всё работало
Это копия, сохраненная 25 марта 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.