Это копия, сохраненная 19 июля 2016 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Это не чат! Пожалуйста не флудите, а старайтесь постить только вопросы, решения и ответы. Сколько лет вы не можете найти работу никому не интересно. Высказывайтесь одним большим постом а не цепочкой мелких
Это тред для начинающих. Не написал за свою жизнь ни одной программы? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Netbeans PHP или PhpStorm (с ним будет удобнее).
Предыдущий тред был тут: >>753595 (OP)
Что самое главное для программиста? Умение аккуратно оформлять код (читай второй пост прежде чем писать код).
Почему PHP? Потому что фейсбук и википедия на нем написаны, и вакансий море, и учить легко.
Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка 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/Yii2: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование
- Если ты все решил, переходи к Symfony 2/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
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания 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://gist.github.com/codedokode/10539213
Что почитать
- Мануал по 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
Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
Подскажи сайты для поиска работы, я не умею гуглить? — hh.ru, geekjob.ru, moikrug.ru (склеен с brainstorage.me), fl.ru, upwork.com (бывший одеск). Имей в виду, что кроме фриланса есть еще постоянная удаленная работа (remote job) когда тебе не надо тратить время на поиск заказов и переговоры с неадекватными заказчиками.
Шапка треда: http://pastebin.com/mP2aPRBb
Если тебе лень выравнивать код руками, закачай его на 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/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Давай удочку, а не рыбу
Лучше не давать готовое решение проблемы, а рассказать как его искать. Может дать ключевые слова для гугла или ссылку. Но помогай, а не пытайся показать превосходство. Если даешь ссылки на нерусскоязычные статьи, упомяни об этом.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Не придирайся к знанию английского языка.
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Не придирайся к знанию английского языка, анон пишет как умеет.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
Если тебе лень выравнивать код руками, закачай его на 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/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Давай удочку, а не рыбу
Лучше не давать готовое решение проблемы, а рассказать как его искать. Может дать ключевые слова для гугла или ссылку. Но помогай, а не пытайся показать превосходство. Если даешь ссылки на нерусскоязычные статьи, упомяни об этом.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Не придирайся к знанию английского языка.
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Не придирайся к знанию английского языка, анон пишет как умеет.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
Отображает из бд всё норм, но, вот хочу сделать кнопку добавления поста (пока все значения, кроме заголовка забиты руками в запрос. Заголовок в текстбоксе рядом). Две строки, я думаю можно сюда закинуть. Так вот, ну типа если нажата кнопка сабмит, то делаем то, что ниже.
title <input type="text" id="titlel" name="title"><br>
$add = mysql_query('INSERT INTO blog VALUES (NULL, ($_POST[title]), '2016-06-11', 'Hello!'')');
//run/$add;
Не добавляется короч значение в бд, если указан вот этот заголовок ($_POST[title]). Пробовал разные виды кавычек, скобок и т.п. Если туда такое же значение забитое руками в запрос написать, то всё ок, а если из текстбокса, то всё, не добавляется. Причём, если это значение просто на странице вывести, то выводится. А в бд не добавляется.
Вот собственно вопрос - меня смущает вот это //run/ - это действительно всегда так должна выглядеть операция запуска запроса?
Дело в том, что вы отправляете $_POST['title'] обычным текстом, то есть не отправляете значение переменной, а просто сам код.
Должно быть вот так, думаю:
Html с формой:
<form action="post.php" method="post">
<input type="text" name="title">
<input type="submit">
</form>
Сам файл post.php
mysql_query("INSERT INTO 'blog' VALUES (NULL, ".$_POST[title].", '2016-06-11', 'Hello!')");
> IMVU’s backend had been written in PHP from the beginning. Startup code is always gross, but after years of learning PHP’s ins and outs, we bent it to our will. Part of me looks back and says “It wasn’t that bad”, and indeed, it has a lot of great properties. But then I remember the horror.
> The terrible straight-line performance, the lack of concurrent IO, the insane memory usage. Once the codebase reached about a million lines, the latency on our REST service response times was over half a second and in the worst case several second
> In fact, one weekend, Andy went home with the explicit goal of proving that Haskell was stupid and not good for writing production software.
> Andy came back on Monday glowing. “Haskell is perfect for web services! We should use it! It’s fast and safe and concurrent!” We smiled and nodded (sometimes Andy gets enthusiastic about new things) and went on with our daily work. But in the evenings and weekends he plugged away, and built a prototype web service that was 1) dramatically faster than the corresponding PHP services 2) actually quite short in implementation and 3) surprisingly clear
> https://chadaustin.me/2016/06/the-story-of-haskell-at-imvu/
>>769722
Мне интересно, сколько надо времени для переписывания миллиона строк. пару человеко-лет?
Алсо возможно пхп код писали не очень опытне специалисты, а для хаскелл версии выбрали старичков.
Расширение mysql устарело. Пора изучать PDO уже. Данные надо вставлять не напрямую (скл-инъекция), а через плейсхолдеры:
$q = $pdo->prepare("INSERT ... VALUES(:title)");
$q->execute([':title' => $_POST['title']);
Алсо статья и уроки про работу с формами:
https://github.com/codedokode/pasta/blob/master/forms.md
https://github.com/codedokode/pasta/blob/master/soft/web-server.md
На домене у меня https, а на субдомене http
На домене я сделал редирект с http на https
А сделать, чтобы если заходят по ссылке вида
https://субдомен перебрасывало на http://субдомен не получается, выдает ошибку безопасности. Я думаю, там даже не доходит до обработки моего .htaccess
Как быть?
Ideone
нет. Во первых не успеешь выучить (если только нет большого опыта в других языках) А во вторых для фриланса надо пару лет опыта работы в офисе
И рекомендую удалёнку а не фриланс
Ок, а если по законам страны я несовершеннолетний? у меня в жопе мира 21 год совершеннолетие Там же вроде договор нужен и тому подобное. Можешь, если не трудно, рассказать как вообще дела в этой сфере обстоят?
$date = date('m.Y',$randomStamp);
$arr = explode(".", $date);
$month = $arr[0];
$year = $arr[1];
rtrim($month, '0');
$d = date('l m Y', mktime(0, 0, 0, $month+1, 0, $year));
приходится к нему единицу прибавлять.
Такой вопрос - для того, чтобы обрезать номера типа "888-888-888-8 позвать люсю" я пользовался постановкой флагов /^ $/
Есть какой-нибудь другой способ ограничить регулярку? Мол, мне нужно только 10 символов и точка, все, что больше - мимо?
В сентябре начал потихоньку изучать php, в том числе и с помощью треда. Болеменее вкатился в ООП, поигрался с фреймворками(Laravel с Eloquent в основном) и отправил резюме в пару контор, у которых в описании было нормальное отношение к джуниорам. На следующий же день дали тестовое задание в одной и после решения позвали на интервьюирование, после которого пригласили на работу. Задавайте ответы если интересно + буду мб потихоньку репортить о выдаваемых задачах. (Кун из мухосранска)
ну надо же, а я три года пишу на пхп, жаве и жс, знаю весь веб стек со фреймворками и цмс. сейчас делаю вот эту шизозадачу >>772631
и скорее всего мне опять перезвонят. сижу на шее у мамки.
(тоже из мухосрани)
Если несовешеннолетний, так какого чёрта дёргаешься. Сиди у мамки на шее и учись потихоньку
На удалёнку часто можно устроиться вообще безо всякого оформления, но рискованно. Могут кинуть на месячную ЗП
Но правда, без опыта работы в офисе на нормальную удалёнку тяжело устроиться. Придётся с работы за доширак начинать.
Учись не спеша. Основы ПХП -> фреймворки -> пару серьёзных учебных проектов -> продвинутое ООП. Где то год-полтора если совсем нуля. ПОтом свои учебные проекты показываешь потенциальным работодателям, ищущим студентов на удалёнку за доширак. Работаешь. Как опыта наберёшься - прыгаешь на проеткы получше.
Но надо натурально задрачивать
20к
Можно ли вьюшки заключать внутрь статических методов модели (html, само собой, хранить в отдельных файлах)? Контроллер дёргает одну вьюшку, а та уж пусть что хочет, то и делает, включая вызов других вьюшек.
Правда в этом случае Model получается не fat, а fat & ugly.
____________
Обоснуйте где я неправ
Ты неправ в том месте, где ты начинаешь изобретать какой то ебучий велосипед.
- Берёшь фрейморк (Yii, Laravel, Symfony).
- Читаешь к нему мануал. В том числе, там написано, как в данном фреймворке правильно обращаться с моделями.
- Делаешь как там написано
- Профит.
Если реально интересно и нравится - значит есть хорошие шансы, что всё получится. Дерзай
Понял, в чём проблема.
Оп тут? Есть пара вопросов...
Да, я изобретаю велосипед для своей ЦМСки. Я поработал с Yii, и мне очень понравилось как там сделана система вьюшек. На каких-нибудь сайтах-блогах (абстрактном Дваче) они не нужны, но когда у тебя база данных со связанными сущностями, то вьюшки (и их реиспользование) это очень и очень и очень удобно. И я хочу сделать также. Но я не хочу заводить отдельный engine на реализацию вьюшек и также не хочу хранить код вьюшек отдельно от модели. Я вижу вьюшки как производную от моделей, а потому закономерно спрашиваю "а не должен ли код вьюшек храниться в моделях?"
Даже такие страницы как "главная страница сайта" можно загнать в метод какого-нибудь отдельного класса, который уже будет рендерить (на дваче) три таблицы: список последних тредов, список последних загруженных файлов, список последних постов в тредах.
Так вот, где я неправ?
Ты неправ в том месте, где тебе надо будет работать над проектом вместе с верстальщиками, нифига не смыслящими в программировании.
Будешь учить их ПХП, когда им надо будет переверстать HTML какой нибудь модели?
А какая разница, если в том же Yii вьюшки это php-файлы с перемешкой php с html? По крайней мере мне достался проект на работе в таком виде. А этой системой пользовалось куча народа по всей России, и она приносила миллионы хозяевам компании
> Будешь учить их ПХП
Нет, они будут верстать html, а натягивать всё равно придется мне, это нормально
> PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'Name' for key 'nick'' in ...
Почему так?
Если где-то совсем уж говнокод - покажите, пожалуйста.
Да я не могу сформулировать просто.
Есть таблица в БД, в которой поле nick - unique.
Я пытаюсь добавить в таблицу строку с неуникальным полем nick (т.е. такой ник уже есть в таблице).
Мне должна прийти ошибка, что такой ник уже есть и добавить строку не удалось. Собственно, онa и приходит, но почему-то не обрабатывается в catch.
[code]$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);[/code]
Вроде бы такое есть..
Ты ж внутри немспейса Users находишься
catch (PDOException $s)
PHP воспринимает как
catch (\Users\PDOException $e)
надо
catch (\PDOException $e)
Кстати код неплох, но только уж если используешь ООП - иди до конца. Зачем глобальную функцию getBase() используешь?
Правильно всю работу с БД оформить через отдельный класс.
А внутри класса User этот класс или с помошью паттерна "синглетон" получать, через вызов статического метода (нубский способ; почитай в инете как делается)
Или с помошью Dependency Injection (как настоящие папки делают)
Точно, спасибо.
Я хотел сначала сделать через класс, но потом переменные настроек стали выёживаться, я психанул и сделал всё одной функцией.
Раз тот неплох, тогда вот действительно говнокода.
В нижнем файле с формой, нужно всё как у меня - выводить через echo, или лучше закрыть php ?> и вывести просто html-кодом?
В верхнем файле, если всё в ООП переводить, то это ведь в ООП не перевести никак, так оставлять?
>>773241
И, namespace. Я их на самом деле добавил только потому, что помощник ругался, если без namespace (тот, который снизу на первом скрине).
Мне для каждого класса что-ли делать отдельный namespace? Ну, там
namespace Posts;
class Post{}
В другом файле
namespace DataBases
class DataBase{}
Или для всех файлов один namespace Site;
Или он вообще тогда не нужен, если мне не нужен?
Конечно же закрыть тег
Внутри тегов ПХП оставить только реквайры хедера и футера
В них, кстати, вообще голый HTML должен быть
Неймспейсы в современном
ПХП нужны для автозагрузки классов. ПОэтому они повторяют структуру папок, по которым у тебя распиханы файлы классов.
А уж как там файлы классов по папкам сортировать - это .... ну как правило это определяется структурой фреймворка, в котором пишешь проект.
Да-да, на голом ПХП никто ничего уже лет 12 не пишет.
В учебном проекте распихивай файлы по папкам как тебе удобно. МОжешь группировать классы по смыслу, можешь работающие в связках классы ложить поближе друг к другу
>>773283
Спасибо.
А это, так оставлять?
>В верхнем файле, если всё в ООП переводить, то это ведь в ООП не перевести никак, так оставлять?
В твоем случае - оставлять как есть
Потом знакомься с MVC фреймворками (начни со Slim) - там увидишь как правильно.
Если коротко - все запросы попадают на входной скрипт - роутер запросов, который смотрит, что там в адресной строке введено. И в зависимости от введённого адреса, обращается к тому или иному классу-контроллеру, внутри которых и пишется код, типа того, что ту тебя в верхнем файле.
Примерно понял, спасибо.
Я очень давно писал всякие на пхп, но уже ничего не помню. Тяжело ли вспоминать?
Хочу запилить 1 сайт.
>>773582
Катитесь-ка в другой тред с такой манерой общаться.
>>773283
Они не для автозагрузки. У меня в уроке написано, что они придуманы для борьбы с конфликтами имен классов и длинными именами: https://github.com/codedokode/pasta/blob/master/php/autoload.md
Автозагрузка была и до неймспейсов.
>>773272
Читай урок про неймспейсы и PSR-4 выше.
>>773263
Не используй echo в шаблоне, это же очень неудобно. Плюс, ты еще и форму неправильно обрабатывваешь, почитай урок https://github.com/codedokode/pasta/blob/master/forms.md
> В верхнем файле, если всё в ООП переводить,
То это все пойдет в класс контроллера.
>>773155
> вижу вьюшки как производную от моделей,
И это неправильно. Вью это просто кусок страницы, он может соответствовать модели, их сочетанию или ничему (например статический текст).
> Даже такие страницы как "главная страница сайта" можно загнать в метод какого-нибудь отдельного класса, который уже будет рендерить (на дваче) три таблицы
Какой кошмар. Всю разметку надо выносить в шаблоны и не смешивать с логикой.
>>773028
У тебя поставлено условие что цикл выполняется только если $x больше или равно 120. Очевидно что он не выполнится ни разу так как в начале $x равно 100.
>>772928
Вью это штука которая получает какие-то данные на вход и отображает их. На практике это шаблон либо на php либо на шаблонизаторе вроде twig. Не функция и не класс, а просто файл с кодом.
> Вьюшка это функция без сайд эффектов, которая принимает какие-то параметры и возвращает строку.
Если это надо, всегда можно написать функцию которая вызывает шаблон и перехватывает его вывод, но зачем...
> Можно ли вьюшки заключать внутрь статических методов модели
У тебя непонимание идеи MVC. Идея как раз в том что компоненты разделены и модель ничего не знает про вью. Хотя бы потому, что мы можем всегда добавить новый вью к существующей модели, не меняя ее.
Плюс нарушается принцип единой ответственности. Ответственность модели - хранить информацию о какой-то сущности, а не выводить ее на экран.
А твой подход - отказаться от MVC и савлить все в кучу.
И вообще по моему ты что-то не о читал или не так понял. Я советую тебе сделать например задачу про студентов чтобы разобраться. Или изучить фреймворк.
>>773582
Катитесь-ка в другой тред с такой манерой общаться.
>>773283
Они не для автозагрузки. У меня в уроке написано, что они придуманы для борьбы с конфликтами имен классов и длинными именами: https://github.com/codedokode/pasta/blob/master/php/autoload.md
Автозагрузка была и до неймспейсов.
>>773272
Читай урок про неймспейсы и PSR-4 выше.
>>773263
Не используй echo в шаблоне, это же очень неудобно. Плюс, ты еще и форму неправильно обрабатывваешь, почитай урок https://github.com/codedokode/pasta/blob/master/forms.md
> В верхнем файле, если всё в ООП переводить,
То это все пойдет в класс контроллера.
>>773155
> вижу вьюшки как производную от моделей,
И это неправильно. Вью это просто кусок страницы, он может соответствовать модели, их сочетанию или ничему (например статический текст).
> Даже такие страницы как "главная страница сайта" можно загнать в метод какого-нибудь отдельного класса, который уже будет рендерить (на дваче) три таблицы
Какой кошмар. Всю разметку надо выносить в шаблоны и не смешивать с логикой.
>>773028
У тебя поставлено условие что цикл выполняется только если $x больше или равно 120. Очевидно что он не выполнится ни разу так как в начале $x равно 100.
>>772928
Вью это штука которая получает какие-то данные на вход и отображает их. На практике это шаблон либо на php либо на шаблонизаторе вроде twig. Не функция и не класс, а просто файл с кодом.
> Вьюшка это функция без сайд эффектов, которая принимает какие-то параметры и возвращает строку.
Если это надо, всегда можно написать функцию которая вызывает шаблон и перехватывает его вывод, но зачем...
> Можно ли вьюшки заключать внутрь статических методов модели
У тебя непонимание идеи MVC. Идея как раз в том что компоненты разделены и модель ничего не знает про вью. Хотя бы потому, что мы можем всегда добавить новый вью к существующей модели, не меняя ее.
Плюс нарушается принцип единой ответственности. Ответственность модели - хранить информацию о какой-то сущности, а не выводить ее на экран.
А твой подход - отказаться от MVC и савлить все в кучу.
И вообще по моему ты что-то не о читал или не так понял. Я советую тебе сделать например задачу про студентов чтобы разобраться. Или изучить фреймворк.
А, и еще. Если ты думал что MVC поразумевает наличие ровно 3 классов (контроллер, модель, вью) то это тоже неверно.
>>772843
Полгода-год
>>770079
По идее нет. Но у нас "фронтенд разработчиками" себя часто называют неосиляторы, которые еле-еле освоили основы хтмл и ксс, им без него будет трудно устсроиться на работу.
В моем понимании фронтенд-специалист, это тот, кто знает как решить задачу про SPA из ОП-поста. А не копировать кривые плагины на джейквери или делать хелловорлды на реакте и воображать что он что-то умеет.
Ты за 3 года открыть мануал не нашел времени? http://php.net/manual/ru/function.mktime.php - тут ответ на твой вопрос.
>>772645
>Такой вопрос - для того, чтобы обрезать номера типа "888-888-888-8 позвать люсю" я пользовался постановкой флагов /^ $/
Так и надо, только это не флаги, а assertions по моему. То есть они не ищут какой-то символ, а проверяют условие. По умолчанию регулярка не обязана соответствовать всей строке, достаточно только части, потому надо дополнительно ставить эти символы.
пробел это не спецсимвол, перед ним не надо ставить бекслеши.
> (\\(|\\)|\\ |\\-)
Это короче записать через квадратные скобки.
В остальном верно.
>>770113
Изучать почему ошибка. Например сертификат не распространяется на поддомен.
Присматриваюсь к задаче про SPA, хочу попарктиковаться в ангуляре
Такой вопрос:
Вот у меня есть проект на ангуляре. В нём куча JS файлов со всякими сервисами-компонентами
Как всё это вместе сливают в одно приложение?
- понятно, что все JS файлы подключать по отдельности к странице - не вариант, ибо их десятки будут, если не сотни.
- воспользоваться чем-то вроде requireJS, который будет те же фалы подключать автоматически, по мере необходимости
- с помошью какого нибудь webpack слить все JS файлы проекта в 1 большой фаил, и заодно его минифицироваать. По идее тогда и RequireJS в проекте не нужен.
Какой вариант использовать? Как вообще это дело в промышленных проектах делают? Мельком видел какие-то странные связки из webpack + requireJS, непонятно только, если всё влито в 1 фаил - нафига require
Ну и слияние всего в 1 фаил - она же не даст использовать отладчик в браузере. Подозреваю, что тут как-то надо разные окружения заюзать. Типа, в dev окружении всё по отдельным файлам, а в prod - один слитый минифицированный фаил? Но как это на практике реализовать - пока совсем неясно...
webpack наверно на сегодня лучшее решение. Вообще, я не очень знаю, ты бы сравнил преимущества и недостатки.
> Ну и слияние всего в 1 фаил - она же не даст использовать отладчик в браузере.
Так оптимизации надо делать только на продакшене. На дев-сервере удобнее подключать файлы по отдельности (у webpack должен быть такой режим, если нет, то используй что-нибудь другое или самописный велосипед)
> Присматриваюсь к задаче про SPA, хочу попарктиковаться в ангуляре
Ангуляр там максимум дает 25% решения. Мне он вообще не нравится тем, что это не библиотека, а фреймворк.
> Но как это на практике реализовать - пока совсем неясно...
Начни с изучения документации по webpack/requirejs
>>773829 ООО Вектор от 30 мая
>>773648 https://github.com/someApprentice/Students
>>769949https://github.com/timrene/php-link-list/blob/master/решение задач.md
>>768780 https://github.com/nsdvw/TestHub
>>767215 https://github.com/foobar1643/filehosting
зайдите, посмотрите, вдруг на ваш вопрос ответили.
Если я вам не ответил - напомните о себе в этом треде
>Они не для автозагрузки. У меня в уроке написано, что они придуманы для борьбы с конфликтами имен классов и длинными именами: >https://github.com/codedokode/pasta/blob/master/php/autoload.md
>Читай урок про неймспейсы и PSR-4 выше.
Да, читал. Но, я задавал вопрос, как лучше использовать неймспейсы мне, если у меня всего полтора класса.
> Не используй echo в шаблоне, это же очень неудобно. Плюс, ты еще и форму неправильно обрабатывваешь, почитай урок https://github.com/codedokode/pasta/blob/master/forms.md
> То это все пойдет в класс контроллера.
Ну, анон выше, в принципе, так и пояснил. А форму только создал, чтобы научиться с бд работать, поэтому еще никак не обрабатываю.
Но, все равно спасибо.
>как лучше использовать неймспейсы мне, если у меня всего полтора класса.
Бери spl_autoload_register, для таких целей тебе этой функции с головой хватит.
Сделал то же самое вот так http://ideone.com/3MoT8V
Я стал быдлокодером с самого начала?
ОП, тут в /b дискасс полыхал, мне очень интересно твое мнение. Ответь пожалуйста развернуто, если можешь. Почему именно PHP, ну, для себя почему ты выбрал его и учишь здесь ему? Мог бы взять пайтон и ебашили бы игрушки, мат.расчеты, скрипты для никсов и не только для никсов, приложения десктопные на pyqt, статистика и дата майнинг? Потолка нет, приложения ограничены лишь фантазией. А пхп - это какие-то бесконечные сайты для пиццерий, круды, плагины к вордпрессу, сайты для пиццерий, круды, плагины к вордпрессу, сайты для пиццерий, круды, плагины к вордпрессу... С соответствующим потолком зарплаты и перспективами карьерного роста вникуда.
Тебе проще всего сделать по PSR-4, то есть неймспейсы определяются вложенностью файлов:
src/Model/Student.php -> namespace Model
src/Service/Valudator.php -> namespace Service
> игрушки,
На Питоне из игр разве что визуальные новеллы. Игры пишут на Си++ + OpenGL/DirectX. По крайней мере квейки, думы, халф лайфы на нем написаны
в наше время есть еще Юнити с C#.
> мат.расчеты,
скучно и неоплачиваемо
> скрипты для никсов
ну это вообще не работа, а так, что-то для себя за 5 минут набросать.
> дата майнинг
новомодное словечко из булшит бинго.
> какие-то бесконечные сайты для пиццерий, круды, плагины к вордпрессу
Это зависит от уровня, если ты ничего не знаешь то да, только плагины к вордпрессу и остается делать. Ты забыл, на каком языке программирования написаны фейсбук и википедия?
Вот ты говоришь Питон, а скажи-ка, есть ли в Питоне:
- работающие тайп-хинты в функциях
- private/public и вообще нормальный ООП
- компиляторы вроде HHVM
- библиотеки на Си
- фреймворки и библиотеки в больших количествах
Питон сложнее в установке и настройке. с пхп все просто - скачал Апач и mod_php, создал текстовый файлик и у тебя работающее приложение. А с Питоном? Надо лезть в глубины линуксовой консоли чтобы только что-то заработало.
Питон формально поддерживает винду, но многие расширения требуют для установки компилятор и окружение из линукса и под виндой либо не заведутся либо надо качать многогигабайтную тормозную visual studio.
Насчет зарплат - я не знаю, может действительно питонисты в силу своей малочисленности умудряются продавать меньший набор знаний за большие деньги. Но выбор вакансий для пхп по моему больше.
А когда я начинал, Питон вообще мало где использовался.
Сам по себе Питон в общем неплохой язык, но мне кажется что он используется меньше.
Так что твой вопрос странный. Логичнее было бы спрашивать например почему я выбрал пхп вместо Явы. Ява -серьезный и взрослый язык и Питон с ним даже близко поставить нельзя.
> перспективами карьерного роста вникуда.
Расскажи, какие переспективы карьерного роста есть с питоном? Старший борщехлеб в разваливающемся НИИ?
> игрушки,
На Питоне из игр разве что визуальные новеллы. Игры пишут на Си++ + OpenGL/DirectX. По крайней мере квейки, думы, халф лайфы на нем написаны
в наше время есть еще Юнити с C#.
> мат.расчеты,
скучно и неоплачиваемо
> скрипты для никсов
ну это вообще не работа, а так, что-то для себя за 5 минут набросать.
> дата майнинг
новомодное словечко из булшит бинго.
> какие-то бесконечные сайты для пиццерий, круды, плагины к вордпрессу
Это зависит от уровня, если ты ничего не знаешь то да, только плагины к вордпрессу и остается делать. Ты забыл, на каком языке программирования написаны фейсбук и википедия?
Вот ты говоришь Питон, а скажи-ка, есть ли в Питоне:
- работающие тайп-хинты в функциях
- private/public и вообще нормальный ООП
- компиляторы вроде HHVM
- библиотеки на Си
- фреймворки и библиотеки в больших количествах
Питон сложнее в установке и настройке. с пхп все просто - скачал Апач и mod_php, создал текстовый файлик и у тебя работающее приложение. А с Питоном? Надо лезть в глубины линуксовой консоли чтобы только что-то заработало.
Питон формально поддерживает винду, но многие расширения требуют для установки компилятор и окружение из линукса и под виндой либо не заведутся либо надо качать многогигабайтную тормозную visual studio.
Насчет зарплат - я не знаю, может действительно питонисты в силу своей малочисленности умудряются продавать меньший набор знаний за большие деньги. Но выбор вакансий для пхп по моему больше.
А когда я начинал, Питон вообще мало где использовался.
Сам по себе Питон в общем неплохой язык, но мне кажется что он используется меньше.
Так что твой вопрос странный. Логичнее было бы спрашивать например почему я выбрал пхп вместо Явы. Ява -серьезный и взрослый язык и Питон с ним даже близко поставить нельзя.
> перспективами карьерного роста вникуда.
Расскажи, какие переспективы карьерного роста есть с питоном? Старший борщехлеб в разваливающемся НИИ?
> работающие тайп-хинты в функциях
Есть, хотя он не такой, как в пыхе(хотя, ввести в пыхе тайп хинтинг и не ввести возвращаемое void значение -- это мощно)
> private/public и вообще нормальный ООП
Там он не нужен, ибо философия другая(есть плюсы и минусы такого подхода, правда). Если хочешь показать, что что-то приватно -- юзай underscore как префикс.
> компиляторы вроде HHVM
Ну это вообще смешно. PyPy, Jython?
> библиотеки на Си
Имеешь в виду интероп? Если да, то сам знаешь ответ.
> фреймворки и библиотеки в больших количествах
Pypi - 82744 packages here
В новой версии php хотят сделать viod
> Там он не нужен, ибо философия другая
Правила, которые утверждаются на уровне языка лучше договоренностей. ООП в php лучше. А в Питоне по моему даже интерфейсов нет.
Видимо просто традиционно на Питоне ничего сложного не пишут.
Вот например, тот же Майскрософт сделал для себя TypeScript. Почему? Потому что серьезные проекты писать на слишком динамически типизируемом языке тяжело. Тратишь время на исправление дурацких опечаток и ошибок которые можно увидеть еще на этапе компиляции.
> Ну это вообще смешно. PyPy, Jython?
не работал, не знаю, но судя по вики, в pypy много чего не поддерживается.
>>774618
Точка с запятой после foreach. Тело цикла надо заключать в фигурные скобки.
ЗАРАБОТАЛО, ССУКА! Спасибо, анон
Да, именно так первый анон и посоветовал, спасибо.
А вообще, я потихоньку MVC стал разбирать, вот там неймспейсы очень кстати.
>>774291
Не ОП, но пару дней назад даже линукс поставил, чтобы начать учить и писать сайты на Питоне, так как считал, что php хуже червя-пидора, хуже js.
Но потом появились догадки, что для сайтов на питоне обычные хостинги не подойдут, а нужно искать специальные Так ли это?, а значит они дороже. Плюс в php С-подобный синтаксис. А потом оказалось, что тут еще и ООП есть. Да и работы, думаю, для php побольше будет. Вот я и тут.
А для всего остального есть С++.
>
а зачем тебе foreach ?
можно ведь просто нарандомить элемент массива http://ideone.com/pAkJUv
Чем более важным, чем программирование, может быть занята твоя вторая рука во время кодинга?
Ты там на свой код оргазмируешь?
И вообще, ты допускаешь глупейшую ошибку, прося посоветовать Х, но не указывая что конкретно тебе от этого Х нужно. Таким как ты обычно советуют играть в Battletoads первый и смотреть Boku No Pico.
>>774686во время программирования может быть занята твоя вторая рука, что во время программирования для тебя является более важным
Что может быть хуже JS?
Сбивающие с толку null и undefined, когда в PHP есть isset и is_null/empty, неочевидные правила превращения переменных, нет привычного ООП, класс и ассоциативный массив - одно и то же, тысяча фреймворков, сменяющих друг друга с калейдоскопической быстротой.
Всегда использовал первый попавшийся текстовый редактор, потому не знал, что существует такое многообразие.
А зачем хранить в сессии если можно хранить сразу в куках? Сессия ведь тоже куки использует. Выгоды просто не вижу.
Так да, недостаток что сессии временные, по умолчанию по моему после 30 минут неиспользования удаляются.
Человек который ведёт проект просто категорически против добавления лишней информации в куки и поднимает вой каждый раз
Гугли "конкатенация переменных PHP".
>Видимо просто традиционно на Питоне ничего сложного не пишут.
Вот это тролльное очень утверждение(приводить примеры огромных проектов приводить не буду, сам гугланёшь). А вот огромных проектов на пыхе я чот не видел, потому-что она часто используется в серверном фронтенде(фейсбук, например юзает для серьёзных задач скалку). ООП в пыхе -- это калька с джавы, где на каждый чих нужны интерфейсы и абстрактный фабрики(пыха в этом плане выигрывает ибо динамика). Как я говорил -- ООП питона позволяет решать задачи нестандартно, без анальной ёбли(тестирование, миксины, прототипы). А интерфейсы в динамической типизации -- просто очень бредовая идея, которая демонстрирует странную логику архитекторов пыхи(ортогональность в функциях стандартной библиотеки тоже). Так что говорить, что же лучше тут однозначно нельзя. У этих подходов есть и плюсы и минусы.
P.S. Void появился в 7.1. И да, я не хуй с горы, который пришёл похейтить пыху и довелось с ней работать и я знаю анальную боль, которая приносит работа с пыхой.
>фейсбук, например юзает для серьёзных задач скалку
http://stackshare.io/facebook/facebook
Где она тут?
Огромные проекты на PHP конечно есть.
Только появляются они не потому что кто-то хотел делать большой проект на PHP, а так получилось - делали домашнюю страничку, хуяк-хуяк, и вот у нас Фейсбук с миллионами строк на PHP, с которым ничего уже не сделать - остается только делать его компилятор и подставлять другие костыли и перематывать изолентой.
Сорян, спутал с твиттером. У них юзается хачкель, эралнг, джавка и куча всего.
Установи на сервере PowerPoint, передавай ему презентацию через COM, вытаскивай картинку.
https://ideone.com/FsPyrH
>Что может быть хуже JS?
>тысяча фреймворков, сменяющих друг друга с калейдоскопической быстротой.
От это точно. Тут мне на работе,кроме бекенда на PHP+Symfony2 пытаются фронт на Ангуляре подсунуть - это пиздец, товарищи
Такого говна я ещё ни разу не видел. Даже самые днищепроекты на PHP куда лучше этого
Процедурный код. Предыдущий писака об ООП, инкапсуляции и разделении ответственности даже не слышал.
Ни малешей структуры файлов, всё перемешано в какую то кашу. Что откуда вызывается, и что откуда приходит - понять невозможно.
IDE в этой мешанине, ничего, естественно, подсказать не может. Автодополнение? Автоподсказки? Доки на JSDoc? - забудьте!
Ну и как вишенка на торте - просто ДЕСЯТКИ использванных либ и каких-то инструментов. Походу мудаку просто хотелось попробовать всю хипстерскую хуйню, про которую он в инете слышал.
Один только Gulp одновременно с webpackом чего стоят...
Через пол года, если не дурак, и будешь активно учиться всё это время - будешь стоить больше, но сьебнуть или попросить повышение - не сможешь. На то и рассчет
С БД особо-то дел никогда не имел, поэтому: соединение может быть только одно Тогда и нужен синглeтон?, закрывать тогда его не нужно, ибо сам закроется, когда все запросы выполнятся и потеряются ссылки, а когда снова понадобится - откроем.
Или для каждого запроса открывать соединение и после его выполнения зарывать?
Я тут в MVC вникаю. Мне что-то подсказывает, что Dependency Injection для БД тут использовать не получится Так как тогда объект БД нужно будет создавать в контроллере и передавать в качестве аргумента в модель, но контроллер ведь для этого не предназначен, тогда создавать объект логичней все же в модели?
>соединение может быть только одно
да
Алгоритм такой:
- браузер делает запрос. Запускается PHP скрипт.
- Скрипт открывает ОДНО соединение с БД. Соединение упаковано в синглетон, и ты его в любую часть скрипта можешь подтянуть, гогда тебе в этом месте надо обратиться к БД
- Закрывать соединение руками не нужно, скипт закончит своё исполнение - обьект, в который упаковано соединение уничтожится, и соединение само закроется.
Таким образом - на один запрос браузера открывается 1 соединение с БД. На другой запрос - будет запущен другой скрипт, там будет открыто другое соединение.
Предваряя вопрос - соединение, открытое в одном скрипте, ты в другой скрипт передать не сможешь - ПХП так не работает.
Спасибо.
Синглтон это антипаттерн. DI тут использовать можно.
- браузер делает запрос. Запускается PHP скрипт.
- Скрипт открывает ОДНО соединение с БД.
- скрипт создает классы работы с БД и передает в них это соединение
С DI всё чуток посложнее. Для того, чтоб им нрмально пользоваться, тебе нужна хрень, под названием DI Container. Ты туда ложишь соединение при старте скрипта, а потом, когда оно тебе нужно, достаешь его оттуда.
Посмотри как container в Slim`е устроен, там очень простое и очень крутое устройство.
И, если делать всё по всем правилам ООП, то передавать руками соединение в модель при её создании.... ну можно в принципе, но лучше для таких дел создать фабрику моделей, которая и будет создавать их, попутно доставая из DI контейнера соединение с БД и засовывая её в модель.
А сама фабрика, в свою очередь, тоже должна лежать в DI контейнере.
А в контроллере ты лезешь в DI конейнер, к фабрике, говоришь ей, чтоб она выдала тебе юзера, а она там внутри шаманит, и юзера тебе возвращает, с уже лежащим внутри соединением.
Пишу тут, и думаю, что тебе лучше пока не забивать этим голову. Это продвинутое ООП, к нему лучше переходить сильно позднее. Пока с синглетоном всё просто сделай
>Синглтон это антипаттерн.
Не забивай начинающим голову этой хренью. Сам-то хоть сможешь обьяснить, почему это антипаттерн?
> Для того, чтоб им нрмально пользоваться, тебе нужна хрень, под названием DI Container.
нет. Вот пример DI без контейнера:
$pdo = new PDO(....);
$userDataGateway = new UserDataGateway($pdo);
$validator = new Validator($userDataGateway);
DI не требует контейнера. Ты наверно путаешь общий принцип DI и какую-то реализацию DI которую ты видел.
> И, если делать всё по всем правилам ООП, то передавать руками соединение в модель при её создании.... ну можно в принципе, но лучше для таких дел создать фабрику моделей
Не надо придумывать велосипеды, это все уже давно известно и описано например в уроке https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
>>775397
В уроке пытался (раздел про глобальные переменные и статические методы): https://github.com/codedokode/pasta/blob/master/arch/di.md
Согласись, кстати, что вопросы их того урока хорошо бы пошли на собеседовании: чем плохи глобальные переменные (и чем хороши), чем плохи статические вызовы. Мало кто может на них ответить. Я сталкивался с тем что у людей большой опыт программирования, но они плохо понимают ООП, исключения, обработку ошибок, общие принципы повышения качества кода.
ТАК НА ХАБРЕ НАПИСАЛИ РЯЯЯЯЯЯЯЯЯ!!!!11111 У кого свое мнение есть, тот в других тредах сидит.
Заебись. И сидишь ты такой на пятом уровне иерархии, пытаясь разобраться в методе с десятью параметрами, в которых передаются зависимости. Зато чистота, хуле.
Функция там большая, это схематичный вид и интересует меня лишь ИФ.
У меня там при двух случаях джойница одна таблица, но потом действия для этих случаев расходятся, вот.
Да, не требует.
Но без него все классы, где используется композиция, надо собирать руками, а это весьма муторное занятие, ибо иногда там бывает дофига уровней вложенности
В простом приложении классов совсем немного. И контейнер не обязателен. И тебе не надо ничего разбирать так как в конструкторе обычно стоят тайп-хинты:
__construct(SomeService $service, SomeOtherService $someOtherService)
Наглядно и понятно, что именно нужно этому классу для работы. Гораздо нагляднее чем спрятанный где-то в коде статический вызов о котором ты можешь и не знать.
Вот ты зря урок не прочел. Там написано про достоинства и недостатки разных подходов.
>>775433
По моему ты ничего не понял. Алсо, больше 4-5 аргументов делать не рекомендуется.
Смотрите, какую приколюху нашёл: https://github.com/PHPointless/monolol
>Я сталкивался с тем что у людей большой опыт программирования, но они плохо понимают ООП, исключения, обработку ошибок, общие принципы повышения качества кода.
Ох, с ООП действительно беда. Я ХЗ, похоже все, понимающие зачем реально ООП нужно кодят на джаве. Хотя из их лагеря я тоже регулярно слышу стоны на эту тему.
Блядь, где все нормальные программисты-то?
Ато вот щас достался проект системы электронного документооборота на PHP+Symfony2, но при этом с процедурным кодом внутри (всё свалено в огромные классы с иманами что-то-там-Serivce, где по 20-30 публичных методов, в каждом из которых по 50-400 строк кода. Простыни по 4 экрана в среднем...). Это пиздец, товариши. Какие-то клоуны слышали, что Symfony2 луший фреймворк для сложных проектов, но как им пользоаться - понятия не имели.
И вот как теперь с этой хренью работать??
Зря ты думаешь, что не прочел. Давным-давно уже...
Кстати пешы исчо, у тебя талант излагать сложные вещи так, что любой дурак поймёт
>Блядь, где все нормальные программисты-то?
Раньше они составляли 10% от общего количества, сейчас 0.01%, вот тебе и кажется что их нет.
Людей всем не хватает, берут любую макаку, лишь бы цикл умела написать.
В начале девяностых так с бухгалтерами было - двухмесячные курсы и готов новый главбух для "рогов и копыт".
>>775458
Могу даже следующую темку подкинуть.
Про DDD тебе бы изложить, хотя бы про самые основы, и ссылки на книги, где развёрнуто почитать
странно, мне было бы приятно, ибо я такого таланта напрочь лишен. Обьяснять просто - совсем не умею
ОП, книгу не думаешь написать?
>>774442
>>774686
Спасибо, анончики. А такой вот вопрос: есть мнение, что в случае PHP ты достигаешь условного потолка в 150к/мес и дальше только из страны валить или искать другую работу, а с питоном/жабой/шарпом ты можешь вроде как перерасти в инженера, аналитика, руководителя и т. д. да и потолок зарплат за счет энтерпрайзности. Или это тоже не совсем так?
И еще.
>тысяча фреймворков, сменяющих друг друга с калейдоскопической быстротой.
Разве это не относится к PHP? Вот смотрите: у Ruby - Rails. У Python - Django, Flask, aio. У С# - .Net. У java - EE. У С++ - Boost + любой фреймворк гуя. У PHP - Yii/Yii2, Symfony 2/Doctrine 2, игнитер, ларавель, кохана, зенд, фалькон, кейк, ну и конечно же джумла, друпал и вордпрес. Ну нихуя, блядь, себе! То есть, для руби я учу рельсы и иду работать, а для пхп я должен покопаться во всех этих сортах или даже хорошо их все знать? А если на работу требуется игнитер, а я учил симфонию? Не возьмут же.
Ну смешно же!
На самом деле сегодня на рынке только 3 фреймворка: Yii, Laravel и Symfony
Если есть вакансии по другим фреймворкам - то это, почти всегда, поддержка старого Legacy-говня
Ну а wordperss и joomla - это и программированием-то тяжело назвать
> У С# - .Net. У java - EE.
Ну ты обобщил, конечно. Там дальше просто огромные разветвления идут.
> То есть, для руби я учу рельсы и иду работать
Тебе в любом случае нужно будет знать достаточно много, чтобы взяли именно тебя, а не остальных, кто наивно полагает, что с умением крудить на одном фреймворке они будут по-настоящему ценными сотрудниками. Если один фреймворк - значит знать его нужно досконально.
>А если на работу требуется игнитер, а я учил симфонию?
На джуна будет достаточно одного-двух фреймворков с головой, если в остальных потребуют разобраться - то разберёшься за недельку. И symfony никуда не денется в ближайшее время, а вот JS-фреймворки именно сменяют друг друга.
мимо-с-дивана
Так обычно и бывает.
Мне почему-то напомнило путешественников из российских мухосраней, которые восхищаются любыми заграницами, а там бывают только в столицах или на курортах. И при этом заявляют, что в России всё-всё плохо - и так далее, хотя сами в Москве или Петербурге бывали только проездом.
Тред не успел начаться, а уже 129 постов, воу, воу, палехчи!..
Заграницей и в маленьких городах ахуенно, а в Рашке только ДСы нормально выглядят и только в центре.
Лень даже спорить, извини, бро.
>Не возьмут же.
Возьмут, игнетер плохой пример.
Но с хорошего фремворка на хороший ты будучи не тупым быстро перекатишься, это просто.
Люди вон с языка на язык скачут, а тут всего лишь фреймворк, важнее показывать гибкость ума и знание основ.
решаю задачу со списком абитуриентов https://github.com/codedokode/pasta/blob/master/student-list.md
застрял на формах - а именно, на выводе ошибок при незаполненном поле(валидность по другим признакам пока что не трогаю) и вставке уже заполненных полей при выводе этих самых ошибок.
Проблемная часть кода - http://pastebin.com/YTHLqCng.
По-моему, я выдумываю велосипед, как можно улучшить код?
json_decode("42"); // => 42
json_decode("null"); // => NULL
json_decode("xxx"); // => NULL - WTF?
Собственно вопрос: как в шаблонизаторе "PHP" распознать, что json_decode возвращает NULL из-за невалидности JSON? В языках программирования обычно кидается исключение. А как с этим обстоят дела в шаблонизаторе "PHP"?
азаза, траль в треде, все в монаду!
О, нашел ответ. В шаблонизаторе "PHP", как и ожидалось, исключений как таковых нет, надо дергать json_last_error. Ну, в принципе неплохо. Хотя бы что-то. Не сравнится, конечно, с языками программирования. Но для "PHP" как шаблонизатора тоже неплохо.
Ну так чего ты хотел от шаблонизатора в котором AST появилось в 7 версии. А вообще, это не очень хорошо, что ты тут так жирно всё это высказываешь, у вас же есть свой загон с бананами и линзами, не(я хоть и не люблю пыху очень и писать приходится иногда, но такого жирного траллинга себе тут не позволяюй)? А ещё меня вы радуете своим раздутым ЧСВ, которое не соответствует скиллу практическому. Ни один не показал проект на хачкеле/эрланге/кложуре крупный и гитхуб свой не выкладывал. Может ты похвастаешься.
P.S. Забайндил монаду тебе за категорию, проверяй.
Код здесь:
http://pastebin.com/W5QKAHCf
> как в шаблонизаторе "PHP" распознать, что json_decode возвращает NULL из-за невалидности JSON? В языках программирования обычно кидается исключение. А как с этим обстоят дела в шаблонизаторе "PHP"?
Легко, гугли set_error_handler. Создаётся глобальный error handler в котором выбрасывается ErrorException в случае возникновения ошибки. В последний раз я в зк видел точно такую же претензию к PHP от чувака, который яро агитировал всех перекатываться на JS. А в этом треде как раз критиковать этот язык начали. Не выдержал?
> Вот только проблема в php я полный ноль
Ну учи тогда. Ты палец о палец не ударил для решения задачи и хочешь, чтобы тебе на серебряном блюдечке подали ответ.
1. Написать регулярку для поиска чисел в тексте.
2. Находить число и переводить его в строку.
2. С помощью mb_strlen в цикле отрывать по символу с начала строки и присоединять спереди к переменной, содержащей пустую строку: $result += $letter.
3. После завершения цикла выводить $result.
4. Повторить с другим найденным числом.
Для этого надо изучить несколько тем: циклы, массивы (не обязательно именно для этой задачи, можно обойтись), регулярные выражения.
бамп вопросу.
В лолифайерах. Мне больше всего нравится лолифайер "YOLO".
То руководство Сафронова - я не могу даже плагин для Композера установить битый час...
Почему на Windows в cmd всё работает в любой версии, в любом виде, а тут какая-то непролазная ЗАДНИЦА в изменениях, почему так всё неудобно и непонятно?..
Бугурта на вас нет, ироды проклятые...
Нет, в данном случае не сработает, так как json_decode не генерирует ошибку. В данном случае надо написать свою функцию, которая будет проверять реудльтат и json_last_error и выкидывать исключение.
>>775752
Почитай про обработку форм https://github.com/codedokode/pasta/blob/master/forms.md
>>775582
Установить 2 соединения с двумя БД и в каждом делать INSERT . Но вообще это по моему плохая идея использовать 2 БД, так как будут расхождения. Тебе тогда по идее надо еще писать скрипт который будет запускаться по расписанию, проверять списки в обоих базах и выявлять расхождения.
>>775823
Ну без публикации подробностей ошибки ты будешь ее еще не один час искать.
С использованием менеджера распределенных транзакций.
Улучшить код можно добавлением ООП. Сейчас у тебя код весь написан в скрипте и его нельзя повторно использовать. Например, нельзя вызвать проверку правильности введенных данных из другого скрипта, нельзя вызвать вставку в базу данных из другого скрипта.
далее, тут неправильно:
> switch ($value) {
> case (empty($value['name'])):
как это по твоему должно работать? В case пишется не выражение, а значение, которому должно быть равно value, например case 1: ....
При ошибке логичнее писать не единицчку, а сразу сообщение с причиной.
> INSERT INTO abitList VALUES ('', ?, ?, ?, ?, ?, ?)
Надо указывать названия полей. Непонятно куда и зачем ты вставляешь пустую строку.
> $value[$element] = isset($value[$element]) ? $value[$element] : '';
Слева должна стоять просто переменная, а не элемент массива
> value="<?=regOutValue($value, 'name')?>
Читай урок про XSS, данные надо корректно экранировать
Проверки у тебя только на то, заполнено ли поле, надо проверять более тщательно. Например чтобы не ввели фамилию '123' или '???'.
Код такой:
<?php
$letters = array(
'ко',
'и',
'дзу',
'ми',
'са',
'ку',
'ра',
'да',
'чи',
'ки',
'ри'
);
$name = '.';
for ($i = 1; $i <= 4; $i ++) {
$random = array_rand($letters, 1);
echo "vipalo chislo {$random}, slog {$letters[$random]}\n";
$slogi = array();
$slogi[] = $letters[$random];
}
$slovo = implode("", $slogi);
echo "$slovo";
Код такой:
<?php
$letters = array(
'ко',
'и',
'дзу',
'ми',
'са',
'ку',
'ра',
'да',
'чи',
'ки',
'ри'
);
$name = '.';
for ($i = 1; $i <= 4; $i ++) {
$random = array_rand($letters, 1);
echo "vipalo chislo {$random}, slog {$letters[$random]}\n";
$slogi = array();
$slogi[] = $letters[$random];
}
$slovo = implode("", $slogi);
echo "$slovo";
>Ну без публикации подробностей ошибки ты будешь ее еще не один час искать.
Да, не подумал, извинения прошу. Просто ИЗЛИЛСЯ в тред...
Ну вот
<-----
В руководстве указано: "Обратите внимание, что эту команду (несмотря на наличие аргумента под названием global) не нужно выполнять с правами администратора, иначе далee вы не сможете установить шаблон приложения из-за недостаточых прав доступа".
Запускать пробовал из разных директорий, под root тоже пробовал.
Сначала не увидел, что ошибки в самой команде - так скопировал. Потом набрал руками - без разницы.
Стоп, там же нужно быть залогиненным на Github? Или нет?
Ну как всегда - только спросишь, как сразу появляются идеи...
>composer .phar
Что за файл такой - .phar? Ты вообще понимаешь, что ты копируешь?
>>775968
Нет. Пакеты тянутся в основном с этого сайта: https://packagist.org/
И зачем в корень ФС переходить? В PATH что у тебя? Зачем тебе компоненты Symfony?
У нас есть i, которое доходит до 4-х,
присваиваем переменной слог четыре раза;
переносим каждую новую строку, в них пишем выпавшее число и слог;
Дальше я хотел массив сделать, в который записывались бы выпавшие слоги, а потом всё это вывелось бы в одну строку - вот тут и косяки
Тут советовали для понимания попробовать совладать с Gentoo/Arch по их всеобъемлющим и исчерпывающим мануалам, но тут вряд ли за это кто-то возьмётся, так что советую статьи проще и короче: https://habrahabr.ru/post/99041/
Я там ошибся, потом уже исправил.
На скрине наползло ещё то, что я вышел из той директории.
>Пакеты тянутся в основном с этого сайта: https://packagist.org/
То есть мне надо в source.list его как-то добавить, как я добавлял dotdeb.com?
>>775977
>И зачем в корень ФС переходить? В PATH что у тебя? Зачем тебе компоненты Symfony?
У меня вроде юзер в PATH (если я понимаю, о чём ты). ВОт сейчас так попробовал
<-----
Переводит в /home/user/ сразу.
>>775986
Спасибо, придётся вникнуть, похоже.
Но вот такое вызывает неописуемое жжение пониже спины:
>Если вы уже использовали Linux ранее, то наверняка знаете, что после входа в систему вас приветствует приглашение, которое выглядит примерно так:
>$
>На практике приглашение, которое вы видите, может немного отличаться. Например, оно может содержать имя хоста, имя текущей рабочей директории, или все вместе
>и того и другого, и можно без хлеба, ведь до пятницы я совершенно свободен
И так там во всём, с чем я уже успел столкнуться...
Под root - установилось. Под юзером - получил красным предупреждением по лбу.
А если под root, то потом не удастся установить сам проект, как написано в руководстве.
Хотя там много чего написано, а работает уже не только лишь всё. Вернее, работает всё, но мало именно благодаря тому, что там написано. (с) Виталий Кличко.
Проиграл. Анончик, почитай то, что скинули выше по линуксу. Файл composer.json - это файл, в котором указываются зависимости для проекта, зависимости скачиваются в папку vendor. И так для каждого отдельного проекта. У тебя выходит, что содержимое корня файловой системы - твой проект. Твой пользователь не может писать в корень фс, а root может. Короче, вот задание: создай папку в /var/www/, например foo/, перейди в эту папку, оттуда вызови composer require (...) и выведи содержимое папки. Всё делай через консоль.
Ну я понимаю, что смешно выгляжу, как дитё малое, которое делает первые шаги.
Но я создавал как-то папки через консоль.
Вот сейчас сделал
<-----
Вроде это то, что было нужно?
Теперь ls / показывает прежние папки, как будто они просто перенеслись в этот каталог. Всё верно сейчас?
Мне всего лишь надо было вспомнить про sudo, стукнутый я по голове...
Попробую установить Yii2 чуть позже.
Какая боль, какая боль: консоль Linux против филолога - 5:0.
Bower ещё нужен, что ли. Я думал, в плагине Asset он уже есть, я когда его устанавливал.
А вообще:
СМОТРЮ В РУКОВОДСТВО
@
ИЩУ РАБОТАЮЩИЕ АНАЛОГИ КОМАНД
Я мог бы так и на cmd делать вполне.
1) ты плохо скопировал команду и добавил в нее лишние пробелы и бекслеши
2) не надо от рут запускать композер. Не надо вообще сидеть под рутом
Кстати, ты читал мой гайд по командной строке из Оп поста?
Набери php -h (и прочитай этот раздел http://php.net/manual/ru/features.commandline.options.php ). Тогда тебе станет понятна причина части ошибок.
Еще: http://php.net/manual/ru/features.commandline.usage.php
>>775968
Нет. Куки же хранятся в браузере и композер ничего не знат про то где ты залогинен.
>>775978
Ты не полностью описал что делают эти строки. Ты не написал, что делают последние две:
\t$random = array_rand($letters, 1);
\techo "vipalo chislo {$random}, slog {$letters[$random]}\n";
$slogi = array();
$slogi[] = $letters[$random];
Попробуй объяснить последние 2 строки, если забыл особенности работы массивов то в уроке по массивам вроде есть примеры кода с пояснениями.
Также, ты не очень точно описываешь порядок выполнения действий. Ты пишешь "присваиваем переменной слог четыре раза;. переносим каждую новую строку, в них пишем выпавшее число и слог; ", можно подумать что сначала делается первое действие 4 раза, а потом второе, но правильный порядок такой:
4 раза повторяем последовательность действий: {
- присваиваем переменной слог
- пишем выпавшее число и слог;
- .... что-то делаем с массивом ....
}
>>775986
Неплохо, такие мануалы и нужны, только там он совсем маленький.
>>775991
> То есть мне надо в source.list его как-то добавить, как я добавлял dotdeb.com?
Нет. sources.list это конфиг менеджера пакетов apt. Композер это отдельная программа у которой свои конфиги и особенности.
>>775992
Скорее всего проблема либо в версии пакета composer-asset-plugin (может уже давно вышла новая) либо в том, что он помечен как "нестабильный", а ты не указал опцию разрешающую ставить нестабильные пакеты.
Проверить актуальную версию плагина можно тут: https://packagist.org/search/?search_query[query]=composer-asset-plugin
На этой странице https://packagist.org/packages/fxp/composer-asset-plugin написана команда которой он ставится.
1) ты плохо скопировал команду и добавил в нее лишние пробелы и бекслеши
2) не надо от рут запускать композер. Не надо вообще сидеть под рутом
Кстати, ты читал мой гайд по командной строке из Оп поста?
Набери php -h (и прочитай этот раздел http://php.net/manual/ru/features.commandline.options.php ). Тогда тебе станет понятна причина части ошибок.
Еще: http://php.net/manual/ru/features.commandline.usage.php
>>775968
Нет. Куки же хранятся в браузере и композер ничего не знат про то где ты залогинен.
>>775978
Ты не полностью описал что делают эти строки. Ты не написал, что делают последние две:
\t$random = array_rand($letters, 1);
\techo "vipalo chislo {$random}, slog {$letters[$random]}\n";
$slogi = array();
$slogi[] = $letters[$random];
Попробуй объяснить последние 2 строки, если забыл особенности работы массивов то в уроке по массивам вроде есть примеры кода с пояснениями.
Также, ты не очень точно описываешь порядок выполнения действий. Ты пишешь "присваиваем переменной слог четыре раза;. переносим каждую новую строку, в них пишем выпавшее число и слог; ", можно подумать что сначала делается первое действие 4 раза, а потом второе, но правильный порядок такой:
4 раза повторяем последовательность действий: {
- присваиваем переменной слог
- пишем выпавшее число и слог;
- .... что-то делаем с массивом ....
}
>>775986
Неплохо, такие мануалы и нужны, только там он совсем маленький.
>>775991
> То есть мне надо в source.list его как-то добавить, как я добавлял dotdeb.com?
Нет. sources.list это конфиг менеджера пакетов apt. Композер это отдельная программа у которой свои конфиги и особенности.
>>775992
Скорее всего проблема либо в версии пакета composer-asset-plugin (может уже давно вышла новая) либо в том, что он помечен как "нестабильный", а ты не указал опцию разрешающую ставить нестабильные пакеты.
Проверить актуальную версию плагина можно тут: https://packagist.org/search/?search_query[query]=composer-asset-plugin
На этой странице https://packagist.org/packages/fxp/composer-asset-plugin написана команда которой он ставится.
Не, так не пойдет. Ты набираешь команды вслепую не понимая что они делают и не понимая почему происходят ошибки.
- Во-первых прочти гайд ОПа из ОП поста по командной строке (целиком)
- Затем страницы мануала пхп про командную строку
- Затем прочти документацию или статьи по композеру: https://www.google.ru/search?q=композер+документация&newwindow=1&gbv=1&sei=70hpV9irO8itsgHhlYn4Aw (увы, официальная документация только на английском, на русском только небольшие статьи)
- затем нагугли и прочти про структуру файловой системы лиункса, например: http://help.ubuntu.ru/wiki/разделы_и_файловые_системы_linux
- и вот это еще тоже http://www.k-max.name/linux/fajlovaya-sistema-linux-i-struktura-katalogov/
- прочти про систему разрешений (привилегий) для доступа к файлам в линуксе: https://www.opennet.ru/base/sys/file_access.txt.html
- http://help.ubuntu.ru/wiki/стандартные_права_unix
В качестве упражнения посмотри на запощенные тобой скриншоты и объясни, что и почему на них пошло не так.
>>776054
Можно без bower. Добрые люди сделали возможность ставить пакеты бовера через композер напрямую: https://asset-packagist.org/
Для этого тебе не нужен assets-composer-plugin. Это если тебе это нужно для своего проекта.
Если ты что-то устанавливаешь через assets-composer-plugin то придется еще ставить ноду, npm и bower.
Код можно запускать из командной строки
Тебе наверно надо прочесть это:
- https://github.com/codedokode/pasta/blob/master/soft/php-install.md
- гайд по командной строке https://github.com/codedokode/pasta/blob/master/soft/cli.md
- урок про веб-сервер https://github.com/codedokode/pasta/blob/master/soft/web-server.md
Какой кошмар, а попроще нельзя? Чтобы кнопочку нажимаешь в нотпаде, открывается консоль, вводишь, выводишь.
1,5 литра перорально ежедневно.
Задача: скачать по нажатию на кнопку эту папку.
Как это реализовать? Мне нужно как-то архивировать эту папку и скачивать архив? Скачивать по одному файлу не подойдет.
Можно.
Нельзя.
Можно вообще без вышки, лишь бы уровень компетенции был достаточный.
>>776073
Спасибо, ОП.
>Не, так не пойдет. Ты набираешь команды вслепую не понимая что они делают и не понимая почему происходят ошибки.
Эх, я же только в Yii2 хотел разобраться, в консоли - постольку-поскольку...
Ну придётся понемногу разбираться.
>Во-первых прочти гайд ОПа из ОП поста по командной строке (целиком)
Я прочитал как раз перед первой установкой Yii2 на Windows 8, потом перечитал уже под Linux, сейчас посматриваю ещё и тот гайд с Хабра, который подкинул братишка.
Спасибо, сохраню все ссылки и сообщение.
Сейчас, честно говоря, начал изучать генерируемые Gii файлы, чтобы лишний раз посмотреть на структуру MVC, хотя вроде в ней уже разобрался.
Это у меня в приоритете было изначально.
Но консоль нужна, Linux и cmd, всё осилю, постараюсь, спасибо, ОП.
Зацените, за 2 дня сделал, для себя.
Что посоветуйте? Как обновлять динамически? Почему так долго грузится сайт, я знаю почему, но как исправить, почему страниц не может асинхронно загружаться?
Рейт крч. Впервые что-то пишу на PHP, это мой первый hello world. Странно, что я так долго не писал на ПХП, наверно потому что я люблю нативный десктоп-кодинг.
Забавно. Для фагов нормально.
Нужна возможность добавлять самому своих богинь и следить за ними.
Но тут вряд ли взлетит, потому что таких богинь почти нет.
Для фагов Карины - ЗБС-СПС.
Покажи код
https://ideone.com/yem5e6
Есть методы getStudentById и getStudentByName, которые возвращают хеш студента со полями инфы о нём. Разница в них только в том, какой столбец сравнвается в WHERE запроса.
А кошерно ли сделать метод getStudent, а в аргумент ему передавать либо id (целоцисленный) либо строку (имя стулента), а в методе распарсить её регуляркой и если это число (ну напрмиер так /^\d+$/ ) то вызывать метод getStudentById а если это не число, то вызывать метод getStudentByName
Кошерно ли это с точки зрения ООП как такового?
Знак "точка с запятой (semicolon)" используется как символ окончание инструкции и для разделения выражений в "шапке" цикла for. В гугле и в официальном руководстве нет перечисления всех способов использования данного знака.
Как быть точно уверенным что точка с запятой больше нигде не используется в синтаксисе? Выучить весь синтаксис и методом исключения определить места где используется этот символ?
ОП называет выражения в скобках после ключевого слова for "шапкой". Где в официальном руководстве сказано что так можно называть эту часть конструкции? У неё вообще есть официальное название?
завершил инструкцию - поставил точку с запятой, что не ясно?
Подскажите, есть ли годные видео уроки по php js css? Годные, в плане полезные и актуальные.
Да.
>>776813
Да.
>"My name is ".$this->name;
Зачем использовать конкатенацию, если в строку из двойных кавычек можно вставлять переменную вот так "My name is {$this->name}". Вот с одинарными - да, нужно конкатенировать.
Ты шапку ОП-поста чем читал? Неужели ты думаешь, что настолько уникален в своих вопросах и поисках?
> видео уроки
Ой, не заметил. Тебе именно видеоуроки нужны? Можешь сразу дропать программирование, если другие источники знаний не устраивают.
>А кошерно ли
Очень кошерно
>>776877
>а в аргумент ему передавать либо id (целоцисленный) либо строку (имя стулента), а в методе распарсить её регуляркой и если это число (ну напрмиер так /^\d+$/ ) то вызывать метод getStudentById а если это не число, то вызывать метод getStudentByName
А не проще ли сделать запрос в котором имя колонки будет браться из аргумента?
public function getStudentByСolumn($column, $value)
{
$query = "SELECT * FROM students WHERE {$column}={$value}";
...
}
https://github.com/revuls/SlimMVC/blob/master/routers/user.router.php вот смотрю сюда и чего-то не понимаю.
Колбек функции в роутах заменяют тебе контроллеры.
Можно и без контроллеров, но вряд ли это можно назвать хорошей практикой. В доках просто нужно изложить информацию кратко, поэтому и пихают всё в один файл. Ну и вот есть же возможность использовать контроллеры: http://www.slimframework.com/docs/objects/router.html#container-resolution
>>777251
Нет желания объяснять очевидные вещи. Тебя водят за руку, что не даёт ничего кроме false sense of accomplishment. А потом когда задача выходит за рамки разжёванного в видеоуроках, в треде появляется куча нубских вопросов от практикующих youtube-driven-development, ведь неоткуда бездумно скопировать.
>>777281
Там как бы последний коммит 3 года назад. И с чего ты взял, что его коду нужно следовать?
У тебя SQL инъекция. Имя колонки надо проверять по белому списку либо еще как-то, значение подставлять через плейсхолдер.
> А не проще ли сделать запрос в котором имя колонки будет браться из аргумента?
Если у тебя есть необходимость искать по разным колонкам (скорее всего нет) то можно.
>>776877
> А кошерно ли сделать метод getStudent, а в аргумент ему передавать либо id (целоцисленный) либо строку (имя стулента), а в методе распарсить её регуляркой и если это число (ну напрмиер так /^\d+$/ ) то вызывать метод getStudentById а если это не число, то вызывать метод getStudentByName
Это плохой и опасный подход. Плохо когда аргумент функции может быть разных типов так как легко ошибиться, передать что-то не то, а функция за счет своей всеядности проигнорирует ошибку. Да и в коде функции ошибку легко допустить если аргумент может быть разных типов.
Да, почему бы и нет. можно например смотреть и подмечать ошибки и неточности в объяснениях.
Но учиться методом повторения действий лектора вряд ли получится. Надо понимать что ты делаешь, каждое слово и каждый символ в своей программе.
>>777260
При исплоьзовании Слим контроллеры это анонимные функции-обработчики роутов (хотя если хочется, в новом Слиме вроде поддерживаются классы-контроллеры).
>>777294
Слим предназначен в первую очередь для маленьких приложений где все контроллеры тоже маленькие и умещаются в один файл.
> Как быть точно уверенным что точка с запятой больше нигде не используется в синтаксисе? Выучить весь синтаксис и методом исключения определить места где используется этот символ?
да. Но мануал по ситаксису не такой и огромный, 2-3 дня максимум на тщательное изучение.
> ОП называет выражения в скобках после ключевого слова for "шапкой". Где в официальном руководстве сказано что так можно называть эту часть конструкции? У неё вообще есть официальное название?
Я встречал слова вроде "заголовок цикла". Вот например что гугл выдает на запрос "for loop header":
http://stackoverflow.com/questions/28506401/which-for-loop-header-performs-better
https://www.arduino.cc/en/Reference/For
Можно поискать и на русском: https://www.google.ru/search?q=заголовок+цикла+for&btnG=Поиск&newwindow=1&gbv=1
Поиск по "шапка цикла for" выдает всякую ерунду. Неужели это я сам придумал такое название?
В общем вот:
<tag>Текст</tag> далее.
Был в 1 строке?
Что за тэг заюзать?
>>Это плохой и опасный подход
Полиморфизм не вышел :(
вычёркиваем этот метод
Хотя по-моему это удобно было бы. Что "не то" там можно передать по сути? Всё приведено к строке, оттримлено как полагается...
Модельки то есть и можно было бы вручную сделать новые.
Но, может быть, есть возможность из них автоматически сгенерировать таблицы?
Поверхностно погуглив не нашел ничего внятного, хелп
Doctrine может генерить таблицы, если прописаны сущности. Гугли orm:schema-tool:create и что для неё нужно
Помню в 2004-ом году мне было 17 лет. Я второй год изучал программирование. Интернета тогда не было. Компьютера не было. Денег на учебники тоже не было. Я каждый день ходил в библиотеку и читал одну книжку о программировании. Конспектировал и тут же составлял программы в тетрадке. Набирал код на уроках информатики. Мой код был в 10 раз сложнее кода сверстников и весь урок информатики уходил лишь на то чтобы успеть перепечатать с тетрадки код и показать на проверку преподавателю. Об отладке не могло быть и речи, жизнь заставляла меня писать сразу правильно.
Я, просто, не изучаю цсс и пхп, а в программе 1 надо сделать так. Я никакие теги и из свойства не знаю совершенно, а ради простенькой задачки в мимопрограмме учить цсс и пхп было бы странным.
Тоже склоняюсь к мысли, что всюду открытые двери - не всегда хорошо. Художник должен быть голодным.
По-настоящему начинаешь ценить время и рационально распоряжаться им только тогда, когда ощущаешь его нехватку.
>>777461
Люди в таких случаях используют гугл, формулируя запрос на английском языке. Не говоря уже о том, что есть более подходящие треды для твоего вопроса.
Ест-но не зная цсс я смогу сформулировать вопрос? А ладно.
Я проводил все свободное время в библиотеке. Вечера, выходные, два лета. Мои сверстники гуляли, ездили отдыхать, играли в любовь, а я сидел в библиотеке. Я получил отлично, так же как и те кто просил меня написать им программы в рамках курса. Мне было несложно помочь, времени уходило 10 минут. Свой же код я кропотливо писал часами. Если подумать, то можно прийти к выводу что наша система оценок в образовании несправедлива. Думаю я заслужил 50 баллов из 5. Просто отбивает все желание развиваться дальше.
сеймщит, учил сам (фронтенд/seo мой конек), seo заебало, а учить обоссаный жс дальше жквери мне было откровенно в падлу.
Посидел в треде, полистал книжечки, сейчас туплю юниором в одной небольшой компании
Сейчас использую yii2. Говорят должны быть толстые модели и тонкие контроллеры, но не перечит ли это здравому смыслу? Ведь многие таблицы связаны и стоит поменять логику в одной из связанных модели, как связь пойдет по пизде. Может быть есть примеры грамотных приложений, чтобы я посмотрел как работают нормальные люди.
Пришел ли я к успеху? Я отлично провел молодость. Клубы, девки, алкоголь, трава, рок-н-ролл сутками напролет. Под конец я вроде бы уже опомнился что хватит гулять, но попал в лютую аварию во время стритрейсинга. ЧМТ, головные боли, таблетки, деменция. Мое IQ упало со 135 до 89. После таблеток вроде 115 стало. Да. Я пришел к успеху.
Чем занимаюсь? Пытаюсь вкатиться после 30.
Прикол в том что у нас бюджетные места распределялись по среднему баллу. Пока я занимался информатикой, я запустил на четверки некоторые гуманитарные предметы. В итоге я по рейтингу оказался на 4-ом месте после тех кому я помогал с задачами. Специальности распределялись по принципу одна специальность на одного человека. 3 человек впереди меня собрали все компьютерные науки. Мне пришлось навсегда отказаться от затеи быть программистом. В те года никто бы не поверил что появятся самообразованные в интернетах джуны, которым даже диплом специалиста не понадобится. Они будут пользоваться гуглом, и смеяться над выпускниками вузов.
ОП-няша, скажи пожалуйста, нет опасений, что нода с питоном повытеснят PHP из его ниши? Вот, жирнота в прикрепленном PHP "шаблонизатором, а не языком" называет, но вообще с JavaScript и его многочисленными фреймворками все так носятся, на TIOBE рейтинг PHP падает ниже некуда, вакансий по JS/Python/Ruby все больше, а по PHP как-то не прибавляется. Особенно пугает JS с его идеей фулстак девелопмента, максимум асинхронности и всего такого. Ты-то перекатишься легко, а те, кого ты учишь? Да и зарплаты у них у всех как-то зачастую повкуснее Какие вообще перспективы и видение будущего в связи с описанным? Извини пожалуйста, если платина.
>Есть у него, открой задачу про студентов в ОП-посте или просто поищи в репозитории pasta на GitHub.
О чем ты, человек?
Лично я больше опасаюсь конструкторов сайтов. Все эти настраиваемые блоки, пошаговые мастера, модули расширения уже позволяют Васяну из 7-б клепать полноценные порталы. Кто-нибудь скоро додумается оптимизировать и объединить все это дело. Вот тогда каюк. Вот тогда песец.
Вообще ноль в этом вашем програмировании, прошу помочь
Вот этого двачну. Лично я сейчас параллельно учу питон на всякий случай. Он мощный и мало чем отличается, плюс он будет куда более востребованным, ящитаю, со временем. К тому же простой оче, на нем что-то написать на выброс - как два пальца обоссать. Если питон не попрет, то нет проблем выучить какой-нибудь C#/Java, тем более зная синтаксис php.
JS не взлетит. Очень много костылей, очень мало tools для работы, они тоже костыльные, все приходится писать руками (js проходит ту же стадию, что пхп лет 10 назад). Короче, единственное, чего реально надо бояться - конструкторов сайтов. Алсо, JS не стоит трогать, т.к. это один большущий костыль.
Не очень вариант, ИМХО.
От питона к джаве довольно сложно, обычно наоборот. Питон ООЧЕНЬ упрощает проганье. Обычно советуют учить базу c/c++/java, а уже после переходить к другому.
Очень полезно понимать про указатели, байты, блокировки.
Сейчас набегут кукоретики, но это необходимо знать, если ты хочешь стать крутым профи.
А, пардон, ты вообще сказал, что можно выучить джаву, зная пхп. Ну это довольно смешно, если честно.
>>777344
Ой, это наверно не имеет отношения к треду и вообще мы тут не обсуждаем программы для постинга в соцети, доски объявлений и тд. Берите АПИ, читайте документацию и делайте как там написано.
>>777413
Не понял вопрос. Что значит "был в одной строке"? Советую все же изучить основы HTML и CSS.
>>777432
Ну сам подумай как ты можешь нормально писать код если в переменной $x у тебя может быть число, массив чисел, строка или объект? Да и к тому же это не полиморфизм по моему.
>>777445
Но у него не доктрина
>>777442
Да вручную проще сделать если там немного моделей.
>>777476
Посмотри тут, точно есть: https://github.com/codedokode/pasta/
>>777491
не знаю. Почитай документацию по фреймворкам. Или реши гнашу задачу про студентов - к ней написано много подробных комментариев.
Толстые модели это в общем верно. Код в контроллере 1) нельзя повторно использовать 2) имеет доступ к слишком многим вещам. Мы хотим в идеале иметь какие-то функции с минимумом зависимостей и побочных эффектов, и в контроллере их нельзя сделать.
И я не очень понял про "если поменять логику". Вот у тебя допустим есть функция лайканья поста в модели addLike(Post $post, User $user). Ты можешь как угодно менять в ней логику, лишь бы она делала то, что написано в названии.
Правда в Yii своя атомсфера, они там исплоьзуют актив рекорд и у них очень много всего совмещено в одном классе модели - хранение данных, работа с БД, валидация, то что в других фреймворках разнесено по нескольким классам.
>>777344
Ой, это наверно не имеет отношения к треду и вообще мы тут не обсуждаем программы для постинга в соцети, доски объявлений и тд. Берите АПИ, читайте документацию и делайте как там написано.
>>777413
Не понял вопрос. Что значит "был в одной строке"? Советую все же изучить основы HTML и CSS.
>>777432
Ну сам подумай как ты можешь нормально писать код если в переменной $x у тебя может быть число, массив чисел, строка или объект? Да и к тому же это не полиморфизм по моему.
>>777445
Но у него не доктрина
>>777442
Да вручную проще сделать если там немного моделей.
>>777476
Посмотри тут, точно есть: https://github.com/codedokode/pasta/
>>777491
не знаю. Почитай документацию по фреймворкам. Или реши гнашу задачу про студентов - к ней написано много подробных комментариев.
Толстые модели это в общем верно. Код в контроллере 1) нельзя повторно использовать 2) имеет доступ к слишком многим вещам. Мы хотим в идеале иметь какие-то функции с минимумом зависимостей и побочных эффектов, и в контроллере их нельзя сделать.
И я не очень понял про "если поменять логику". Вот у тебя допустим есть функция лайканья поста в модели addLike(Post $post, User $user). Ты можешь как угодно менять в ней логику, лишь бы она делала то, что написано в названии.
Правда в Yii своя атомсфера, они там исплоьзуют актив рекорд и у них очень много всего совмещено в одном классе модели - хранение данных, работа с БД, валидация, то что в других фреймворках разнесено по нескольким классам.
Вообще, ты поднял интересную тему. Я вижу очень нездоровую пропаганду всяких хипстерских технологий. Сидит человек на работе, пишет солидное серьезное приложение на Яве, и поскольку ему скучно, начинает смотреть всякие альтернативные технологии вроде нод, ангуларов, монго и тд, лишь бы они были не похожи на то что он на работе видит.
Вот например статья, как стать веб-разработчиком: https://vc.ru/p/how-to-became-developer (при внимательном изучении можно увидеть что она скорее напоинает рекламу одного сайта).
Автор старательно избегает упоминания php в положительном ключе, вместо этого рекламирует ноду, в которой:
- нет нормального ООП
- нет фреймворков
- нет ORM
- нет тайп хинтов
- нет нормальной поддержки windows
И монгу в которой:
- нет SQL
- нет транзакций
- нет согласованности и надежности
- нет поддержки windows (?)
--cut--
Вот такого я вижу очень много, эти технологии именно активно пиарят, особенно в ориентированных на новичков статьях.
Отдельно хочу заметить что абсурдно новичкам, не понимающим ничего в архитектуре, давать ангуляр. Без полного понимания как он работает, получится гора неподдерживаемой лапши. Ангуляр не для начинающих. Как и SPA в общем. Не верите - почитайте мою задачу на СПА в ОП посте и подумайте, можете ли вы ее сделать.
Вообще, ты поднял интересную тему. Я вижу очень нездоровую пропаганду всяких хипстерских технологий. Сидит человек на работе, пишет солидное серьезное приложение на Яве, и поскольку ему скучно, начинает смотреть всякие альтернативные технологии вроде нод, ангуларов, монго и тд, лишь бы они были не похожи на то что он на работе видит.
Вот например статья, как стать веб-разработчиком: https://vc.ru/p/how-to-became-developer (при внимательном изучении можно увидеть что она скорее напоинает рекламу одного сайта).
Автор старательно избегает упоминания php в положительном ключе, вместо этого рекламирует ноду, в которой:
- нет нормального ООП
- нет фреймворков
- нет ORM
- нет тайп хинтов
- нет нормальной поддержки windows
И монгу в которой:
- нет SQL
- нет транзакций
- нет согласованности и надежности
- нет поддержки windows (?)
--cut--
Вот такого я вижу очень много, эти технологии именно активно пиарят, особенно в ориентированных на новичков статьях.
Отдельно хочу заметить что абсурдно новичкам, не понимающим ничего в архитектуре, давать ангуляр. Без полного понимания как он работает, получится гора неподдерживаемой лапши. Ангуляр не для начинающих. Как и SPA в общем. Не верите - почитайте мою задачу на СПА в ОП посте и подумайте, можете ли вы ее сделать.
Спам фильтр не пропустил абзац:
....
Почему? Что хорошего в отказе от SQL который существует уже лет 40? Все эти но не потому что они лучше, а потому что проще устроены и быстрее реализуются. Как только появились доступные SQL базы, все пересели на них - еще бы, одним запросом стало можно сделать то, для чего надо было писать много строчек кода.
....
....key value с индексами - они ведь были и до SQL,....
>при внимательном изучении можно увидеть что она скорее напоинает рекламу одного сайта
У них там всё так. Их статьи не стоит принимать близко к сердцу. Там поголовное большинство - непрофессионалы или люди, сорвавшие куш в своё время, а теперь вещающие, как правильно заниматься бизнесом, инвестировать (в их проекты или фонды) и так далее.
Эдакие Павлы Дуровы среднего пошиба, оказавшиеся в нужное время в нужном месте.
Так нет. Как ты думаешь, все ли сейчас так радужно, как было раньше? JS тот же вкатывается в backend. Питон с джавой рядом и тп.
Во многих статьях или туториалах можно увидеть такое. В dev режиме у них как правило советуют либо запускать сборку вручную при изменении файла, либо перезапускать сервер, либо применять костыли вроде тормозных watch скриптов (watch скрипт не может работать без задержки принципиально) или livereload.
Пример статьи: http://frontender.info/getting-started-with-gulp-2/ - тут и watch и livereload. Больше костылей богу костылей!
Сборка ресурсов нужна только для продакшена. Для дев сервера сборка не нужна и нужные скрипты можно грузить напрямую с диска. Это достигается либо настройкой загрузчика скриптов либо написанием своего велосипеда.
Бывают конечно случаи, когда это малореально, например, компилируемые/транспилируемые языки. даже тут гулп и грант подкладывают свинью: в отличие от make который придуман в 80-х годах и умееет перекомпилировать только измененные файлы, они перекомпилируют все файлы целиком. Если только вы не извернетесь и не найдете обходной путь.
Однако у многих разработчиков в статьях вы можете увидеть упоминание этих watch скриптов в гулпе итд. Удивительно что я, не написавший ни одного сайта на ноде, лучше их понимаю как в данной ситуации надо поступать. при том что у меня нет столько звезд на гитхабе и фолловеров в твиттере.
Для сравнения в php вам не нужен никакой гулп. Вы просто обновляете страницу в браузере и новый код сам собой подключается и выполняется. И компилировать тоже ничего не надо. Наша технология в этом плане лучше их.
А, еще нода плохо работает под виндой. Попробуйте найти библиотеку работы с xml. Она потребует libxml. Где взять libxml под виндоуз? для этого вам предлагают скачать и установить многогигабайтовый тяжеленный несвободный ужасный visual studio что-то там и мучаться с его настройкой. В отличие от них, для php многие модули под виндоуз доступны в виде готовой dll.
Выбирайте что вы хотите: качать тяжелый visual studio или получить dll которая идет в комплекте с пхп.
>>777514
> Особенно пугает JS с его идеей фулстак девелопмента, максимум асинхронности и всего такого
Это все технологии которые очень сложны (если поставить цель качественно сделать сложное приложение). Например посмотри на задачу про СПА - ее не так-то просто решить. У меня такое ощущение, что у большинства там знания на уровне хелло ворлда. Тем более что хороших курсов по написанию сложных приложений на JS нигде нет. Возможно потому что там фреймворки меняются каждые полгода и туториалы устаревают раньше чем их напишут.
Вот кстати нашел пример сайта на ноде: https://github.com/iliakan/javascript-nodejs
Ну-ка, анонимные эксперты, оцените технологию. Илья Кантор все-таки профессионал, может у него можно что полезное подметить.
> я. Особенно пугает JS с его идеей фулстак девелопмента, максимум асинхронности и всего такого.
> Ты-то перекатишься легко, а те, кого ты учишь?
А я запрещаю кому-то учить ноду? Задачи по JS у меня есть, а дальше сами доучите чего вам не хватает. Если хотите, можем еще задачи на сетевое программирование порешать и тд.
Во многих статьях или туториалах можно увидеть такое. В dev режиме у них как правило советуют либо запускать сборку вручную при изменении файла, либо перезапускать сервер, либо применять костыли вроде тормозных watch скриптов (watch скрипт не может работать без задержки принципиально) или livereload.
Пример статьи: http://frontender.info/getting-started-with-gulp-2/ - тут и watch и livereload. Больше костылей богу костылей!
Сборка ресурсов нужна только для продакшена. Для дев сервера сборка не нужна и нужные скрипты можно грузить напрямую с диска. Это достигается либо настройкой загрузчика скриптов либо написанием своего велосипеда.
Бывают конечно случаи, когда это малореально, например, компилируемые/транспилируемые языки. даже тут гулп и грант подкладывают свинью: в отличие от make который придуман в 80-х годах и умееет перекомпилировать только измененные файлы, они перекомпилируют все файлы целиком. Если только вы не извернетесь и не найдете обходной путь.
Однако у многих разработчиков в статьях вы можете увидеть упоминание этих watch скриптов в гулпе итд. Удивительно что я, не написавший ни одного сайта на ноде, лучше их понимаю как в данной ситуации надо поступать. при том что у меня нет столько звезд на гитхабе и фолловеров в твиттере.
Для сравнения в php вам не нужен никакой гулп. Вы просто обновляете страницу в браузере и новый код сам собой подключается и выполняется. И компилировать тоже ничего не надо. Наша технология в этом плане лучше их.
А, еще нода плохо работает под виндой. Попробуйте найти библиотеку работы с xml. Она потребует libxml. Где взять libxml под виндоуз? для этого вам предлагают скачать и установить многогигабайтовый тяжеленный несвободный ужасный visual studio что-то там и мучаться с его настройкой. В отличие от них, для php многие модули под виндоуз доступны в виде готовой dll.
Выбирайте что вы хотите: качать тяжелый visual studio или получить dll которая идет в комплекте с пхп.
>>777514
> Особенно пугает JS с его идеей фулстак девелопмента, максимум асинхронности и всего такого
Это все технологии которые очень сложны (если поставить цель качественно сделать сложное приложение). Например посмотри на задачу про СПА - ее не так-то просто решить. У меня такое ощущение, что у большинства там знания на уровне хелло ворлда. Тем более что хороших курсов по написанию сложных приложений на JS нигде нет. Возможно потому что там фреймворки меняются каждые полгода и туториалы устаревают раньше чем их напишут.
Вот кстати нашел пример сайта на ноде: https://github.com/iliakan/javascript-nodejs
Ну-ка, анонимные эксперты, оцените технологию. Илья Кантор все-таки профессионал, может у него можно что полезное подметить.
> я. Особенно пугает JS с его идеей фулстак девелопмента, максимум асинхронности и всего такого.
> Ты-то перекатишься легко, а те, кого ты учишь?
А я запрещаю кому-то учить ноду? Задачи по JS у меня есть, а дальше сами доучите чего вам не хватает. Если хотите, можем еще задачи на сетевое программирование порешать и тд.
До SQL только они и были. Модель CODASYL и до нее.
Только и они были с транзакциями, а не как в Монге и находили то что в базе есть, а не то ближе лежало - https://engineering.meteor.com/mongodb-queries-dont-always-return-all-matching-documents-654b6594a827#.s3ko3vfnx
Посмотрите ради любопытства когда транзакции появились в Оракеле - в какой его версии.
>Квалифицированный специалист будет востребован в любой области. На чём хочешь зарабатывать - то и выбирай для изучения.
Все очень относительно.
>>777575
> рекламирует ноду, в которой:
> И монгу в которой:
Тут скорее особенности. JS тот же позиционируется как язык для всего, в противовес чему PHP - "шаблонизатор для домашних страничек". Перспектив больше, направлений деятельности больше, приложения усилий. Ну и интегрированность. Типа "зачем учить какой-то там php и все равно учить javascript, если можно учить только последний и иметь при этом больше возможностей, не ограничиваясь бекэндом и веб-программированием вообще". Фреймворков для сети в js таки есть, не только голая нода.
>>777584
Вот, вопрос был и в этом. Меня очень пугает то, что я вижу здесь
http://www.tiobe.com/tiobe_index
или вот здесь
https://github.com/blog/2047-language-trends-on-github
Кроме того, за всем этим хайпам стоит js-движок гугла, а это значит, что перспектив у него уже больше, чем у "каких-то там" растов, го и питонов.
Сконструируй мне вконтакте на нем. Эка новость, CMS были всегда, сколько я работаю в этой сфере.
>>777540
xdebug это модуль (расширение) php, так что без php ставить его нет смысла.
ты не написал даже какая у тебя ОС. Как тут помочь?
>>777584
Питон с джавой? Разве что как язык для вспомогательных скриптов для чистки репозитория.
>Если хотите, можем еще задачи на сетевое программирование порешать и тд.
А было бы охуенно. Вообще, о разном.
Ты на стороне PHP идеологически и из-за его фишек, которые тебе субъективно кажутся удобнее, приятнее, или все-таки по коммерческим и прагматическим каким-то причинам? Есть же еще Python, Java - это уже не хипстота.
>Питон с джавой? Разве что как язык для вспомогательных скриптов для чистки репозитория.
Подожди. Ну ладно еще Питон, хотя на нем сейчас много чего крутого делают, не только скрипты. Но Джава-то всегда была самым энтерпрайзным, самым серверным языком для самого хайлоада, она-то как же?
JS не для начинающих и не для новичков.
Возьмем простые примеры файлов:
1) https://github.com/iliakan/javascript-nodejs/blob/master/gulpfile.js
2) https://github.com/iliakan/javascript-nodejs/blob/master/bin/server.js
3) https://github.com/iliakan/javascript-nodejs/blob/master/modules/application.js
Как ты думаешь, сколько библиоетк надо изучить и мануалов перечитать, чтобы понять что там написано?
В пхп все просто: скрипт запустился, сгенерировал страницу, умер. В JS тебе надо понимать сложные концепции асинхронного программирования. Расскажи-ка про обработку исключений в асинхронном сервере? По умолчанию непойманное исключение ложит все приложение.
Посмотри код. Ты уверен что он простой? Это не джейквери скрипт уровня $(..).click(() => $(...).hide());
Также, посмотрите структуру кода по ссылкам. Из-за отстутсивя нормального ООП код там представляет просто кучу функций, хаотично разбросанных по огромному количеству файлов. В Яве есть свои правила, в пхп есть PSR-4, а у них каждый пишет как хочет. Они действительно сейчас на том уровне, где пхп был 10 лет назад.
Я не представляю чем эта каша из функций, скобок и 100 кривых библиотек с гитхаба лучше пхп.
>Джава-то всегда была самым энтерпрайзным, самым серверным языком для самого хайлоада
И сейчас неплохо смотрится - undertow в особенности https://www.techempower.com/benchmarks/#section=data-r12
Прагматическим. Переход на другой язык требует тратить время (неоплачиваемое!) и силы и ничего не даст мне. У меня нет цели получить одобрение от завсегдатаев /pr или hacker news. У меня нет желания разбираться в горе кривых библиотек с гитхаба.
Плюс, в php у меня большой опыт, а на других платформах естественно я поначалу буду слоупочить. И это разумеется не может не отразиться отрицательно на доходе.
>Они действительно сейчас на том уровне, где пхп был 10 лет назад
Это близко к истие. Только был ли сравним PEAR тех времен с сегодняшними npm-репозиториями?
> Я не представляю чем эта каша из функций, скобок и 100 кривых библиотек с гитхаба лучше пхп
Тем же, чем она лучше и всего остального в сегодняшнем мире - нужно знать только один язык, и этого достаточно для всего (с React Native - совсем для всего)
Ну-ка, те, кто считает что нода простая, объясните хотя бы такой простой пример кода:
https://github.com/iliakan/javascript-nodejs/blob/master/modules/application.js#L50
waitBootAndListen(host, port) {
yield this.waitBoot();
yield (callback) => {
this.server = this.listen(port, host, callback);
};
this.log.info('Server is listening %s:%d', host, port);
}
Зачем тут yield, да еще и несколько раз?
>Как ты думаешь, сколько библиоетк надо изучить и мануалов перечитать, чтобы понять что там написано?
Хм. Но
https://ru.wikipedia.org/wiki/PHP#.D0.A4.D1.80.D0.B5.D0.B9.D0.BC.D0.B2.D0.BE.D1.80.D0.BA.D0.B8_.D0.B8_.D1.81.D0.B8.D1.81.D1.82.D0.B5.D0.BC.D1.8B_.D1.83.D0.BF.D1.80.D0.B0.D0.B2.D0.BB.D0.B5.D0.BD.D0.B8.D1.8F_.D1.81.D0.BE.D0.B4.D0.B5.D1.80.D0.B6.D0.B8.D0.BC.D1.8B.D0.BC
+ PEAR + API всяких Wordpress и не только их + всякие GD2, ImageMagiки...
>В пхп все просто: скрипт запустился, сгенерировал страницу, умер
Не накладывает ли это некоторых ограничений на, собственно, хайлоадную хуйню, асинхронную подгрузку инфы "в реальном времени", создании тех же SPA?
Исплоьзование ноды само по себе не сделает твой сайт высокопроизводительным. Чтобы писать хайлоад сайты нужен такой багаж знаний который у нододетей вряд ли есть. То же касается СПА, если мы говорим про настоящие Single Page Application вроде того что в ОП посте а не хелло ворлд на ангулар, там нужен серьезный уровень знаний и широкий кругозор которого у нододетей нету. максимум они могут что-то сделать на готовом фреймворке вроде meteor при условии что задача лежит в рамках его ограничений и приложением пользуется не больше нескольких человек.
Анон, пардон, не нашел в шапке о xdebug'e, это нужная вещь? Сам недавно начал совсем.
Сколько ты получаешь зависит (не только от уровня знаний, но и) от того, где ты работаешь. Потому спрашивать меня бесполезно - посмотри сайты вакансий и увидишь сколько и где ты (а не я) сможешь заработать. Можешь добавить некоторую надбавку из предположения что со временем, если ты хорошо справляешься, тебе будут периодически повышать зарплату, давать премии и тд (кстати премии - важная вещь, про них не пишут в вакансии, но в одних компаниях их раздают охотнее, а в других нет). Там, где можно больше зарабатывать, я работать не хочу. Я вообще работать не хочу так как это неинтересно и мне жалко тратить на это свое время.
Это экосистема, порожденная венчурным капиталом. Задачи сделать что-то работоспособное чаще всего не стоит. Когда встает - зовут тех кому похер на чем делать хайлоад, хоть на Фортране (http://fortran.io lol), лишь бы платили хорошо и сдельно.
Все жители страны веченого детства мечтают запилить прототип, пойти к VC и получить лимон зелени. Или 10.
Весь LA забит wannabe-актерами, каждый официант "берет классы актерского мастерства". Все мечтают стать звездами. Звездами становятся единицы, но миллионы продолжают работать официантами и ходить по кастингам.
В южной калифорнии свои игры - в актеров, в северной свои - в цукербергов.
>$2-3
В России? Или это уровень аппворка?
>>777629
Какой ты правильный няша, еще и анончиков учишь. Хотел бы таким быть.
https://github.com/iliakan/javascript-nodejs/blob/master/modules/iprotect/index.js
>>777634
Это видимо уровень макдональдса в котором работает автор того поста.
Можешь посоветовать бесплатный хостинг с php, чтобы не было лимитов по трафику и скорость более-менее? Плюс нужно, чтобы давал свой не совсем уебищный домен <25 уровня или хотя бы возможность прописать dns от какого-нибудь бесплатного. Под http-proxy, так что не в России. FTP доступ там, все дела. А еще хорошо, если какая-нибудь такая же впска будет, помню, были халявные балтийские, в Литве что ли. Там, естественно, лимиты уже будут, но хорошо, если будет рут по ссш и возможность накатить свой дистр. Это уже для тренировки.
>Это видимо уровень макдональдса в котором работает автор того поста.
Я думаю, это имелось ввиду в тысячах долларов, выглядит реалистично.
>>777635
Ну тут тебя бы столкнуть с разбирающимся адептом этой самой ноды или питонщиком Получился бы интересный срач, а то так все хаят других перед новичками и обвиняют в этом друг друга.
В каком макдональдсе платят три К зелени? Адрес, телефон? Что спрашивают на собеседовании?
NodeJS захватывает энтерпрайз тем временем. На картинке - Netflix
https://blog.risingstack.com/node-js-examples-how-enterprises-use-node-in-2016/
Новички внутрь ноды не лазят. И внутрь реакта. Оно для них магический черный ящик. Берут тьюториалы и ебошат, периодически бегая на StackOverflow с вопросами.
Попробуй сам и реши, что тебе удобней. Разработчик самого популярного PHP-фреймворка - Laravel - использует ST с плагинами. Вроде бы комплексная и навороченная система с огромной иерархией классов, тем не менее обходится без IDE.
Это не исходник ноды, а исходник проекта на ноде. Если ты хочешь писать на ноде ты должен в этом разбираться.
>>777641
У меня есть ощущение что это продиктовано не практическими соображениями, а личными предпочтениями или им просто скучно.
>Если ты хочешь писать на ноде ты должен в этом разбираться
Это нормальное мнение для меня или для тебя.
Это совершенно сумасшедшая, дурацкая и нахрен не нужная затея с точки зрения любого джуниора этой борды.
Они там отвечают на вопросы почему и зачем..
>Они там отвечают на вопросы почему и зачем..
Язык для всего, самодостаточный язык, единство синтаксиса и семантики, реализация всего на свете в каком-нибудь очередном фреймворке, язык будущего, язык асинхрона.
Не только.
> From the business perspective: the teams can reuse some of the modules and templates for example, and some of the libraries as well. It’s great from both the developers and from the managerial perspective.
> Also, Node has a noticeable effect on the positions and responsibilities of the engineers as well.
> Big companies like Capital One will definitely need pure back-end engineers for some of the projects in the future, but more and more teams employ ninjas who can do front-end, back-end, and a little bit of DevOps too - so the teams are becoming smaller.
> Instead of two teams, one is a pure back end, and one is a pure front end - consisting seven people overall - a ninja team of five can do both.
> “That removes a lot of overhead in communication because now you have fewer people, so you need fewer meetings, and you actually can focus more on the work, instead of just wasting your time.”
> Because of the way Node works we can attach debuggers, and set breakpoint steps through the code. If you wanted to debug these groovy scripts in the past, you would make some code changes upload it to the edge layer, run it, see if it breaks, make some more changes, upload it again, and so on.”
> It saves us tens of minutes to test, but the real testament to this project is: all of our engineers who are working on the clients are asking: when do we get to use this instead of the current stack? - told Yunong.
> I use node.js for a web backend. I'll provide the one and only one valid counterpoint to this otherwise correct set of articles
> The node.js ecosystem is full of incredibly well maintained modern stuff that lets you write a modern web app and ship it right now.
> My favorite example is passport.
> "npm install passport passport-twitter passport-facebook passport-google passport-local"
> hack for ten minutes
> Okay, now my site has both internal local authentication and OpenID authentication for the three most popular OpenID providers. I did not have to write a low-level OpenID provider myself and the learning curve was very shallow and easy.
> My users want Github?
>"npm install passport-github"
> hack for two minutes
> Okay, now they've got GitHub logins. Next!
> When I saw that stuff I picked node even though the language sucks.
>В пхп все просто: скрипт запустился, сгенерировал страницу, умер
Вы тут php.exe через CGI штоле запускаете на каждый реквест? Иначе это опасная иллюзия
> PHP seems like shared-nothing, but its default configuration actually cheats in a non-obvious way: It locks on session-data, so all requests with the same session-ID are forced to run sequentially on a server!
> If you change your session handler (such as to let sessions migrate between multiple hosts) or if you force-release the session early, sometimes you'll find many different symptoms of formerly-latent race-conditions bubbling up from your code. This is especially true if there are lots of AJAX requests, people double-clicking on buttons, many simultaneous tabs, etc.
> The sequencing is not a bad capability to have, but it's definitely worth deliberate decisions about where and how to apply it. Avoid sessions altogether? Store/update them differently? Even just closing them ASAP when you don't need to alter $_SESSION can make multi-request (AJAX, iframe) scenarios considerably more snappy.
> Unfortunately, that's how things get popular, it seems. Someone makes something that only takes a few minutes to get going, past that you're on your own and it's riddled with bugs and unimplemented features. So people start implementing what's missing and fixing the bugs. And each generating more bugs for others to fix. Along the way, a thousand guys have had reason to put their name on github and write a blog post that gets pageranked. Of course, it's all built on shaky foundations and band-aids, but that's more reason for people to blog and debug and write books etc etc.
> Compare that with the situation where an expert puts a finished, mature, practically bug-free piece of perfection that leaves nothing for those guys to do. So many such great quality projects exist online that hardly anybody hears about.
И сравним с PHP
> Created in 1994 by Rasmus Lerdorf, the very first incarnation of PHP was a simple set of Common Gateway Interface (CGI) binaries written in the C programming language. Originally used for tracking visits to his online resume, he named the suite of scripts "Personal Home Page Tools"
> Early PHP was not intended to be a new programming language, and grew organically, with Lerdorf noting in retrospect: "I don’t know how to stop it, there was never any intent to write a programming language. I have absolutely no idea how to write a programming language, I just kept adding the next logical step on the way."
Объяснение картинки - http://trimbo.blogspot.ru/2014/04/why-node-is-future-of-web-tier.html
tldr - frontend becomes more sophisticated and contains more logic, the Back End folks are no longer interested in writing a simple DAL/CRUD web-tier for Front End people to call into. That kind of work is a solved problem, and if the real interesting application logic lives in Javascript, it's no fun. Rather, they're more interested in working on scalable internal services and systems that the lightweight web tier can call back into and work on
Бэкенд остается нужен и никуда не денется (но в нем нет места PHP, там серьезные СУБД и серьезные сервисы)
Веб-бэкенд нафиг не нужен, потому что все чем он занимается с момента появления сложной логики в клиентском браузере - это бессмысленный пердолинг JSON-CRUD-ORM. С появлением GraphQL бессмысленность веб-бэкенда приблизилась к 100%.
Просто открываешь файл с помощью PHP, записываешь его содержание в переменную и потом в этом же скрипте выводишь его пользователю. Странно что ты об этом не подумал, с основой на крестах-то.
Открыть файл можно с помощью fopen - http://php.net/manual/en/function.fopen.php
Как вывести переменную на экран средставми PHP я надеюсь ты знаешь.
Вот демагогию развели. Сейчас даже на делфях что-то делают, а вы говорите пыха умрет. Лолирую с вас. Лет 10 минимум ещё живее всех живых будет. Можете скринить.
Про пхп я вообще ничего не знаю. Даже не представляю как хело ворлд написать. Видел только пару раз пхп скрипт в составе веб странички и всё. Но это же не серверная часть получается. Спасибо за ответ, буду читать.
>>В каком макдональдсе платят три К зелени? Адрес, телефон?
Поддвачну вопрос
>> Что спрашивают на собеседовании?
Пять врагов фритюра
>Веб-бэкенд нафиг не нужен
Чё-т в голосяку!
Скажите это огромной куче сервисов, которые не могут существовать лишь в браузере пользователя.
Скажите это сайту, на котором мы все сейчас сидим.
Бэкенд не нужен, ahahaha, oh wow!..
Парни, кто-нибудь рубит в mysql?
У меня есть таблица, стоки которой каждую минуту обновляются.
1. Я удаляю все строки.
2. Я заполняю их новыми данными.
По сути там всего 3 строки, но существует промежуток времени (где-то секунда) в течение которого в таблице нет строки или 1 или 2. И эта секунда будет критичной, если клиент обратиться к базе в этот момент.
Есть какие-то пути исправления? Может есть какая-то возможность сначала заполнить, потом удалить? Хер знает. Помогите!
Там же крупными буквами выделено, не нужен только веб-бэкенд, а не любой бэкенд.
Вечер. Едет автобус.
На первом сиденье сидят двое. У них коэффициент интеллекта (IQ) 180:
- Знаете, я вчера Гамлета в оригинале читал. Такое эстетическое наслаждение...
На другом сиденье сидят ещё двое. У них IQ=140:
- Я вчера посмотрел "Андалузского пса" и нашёл коррелят с ранними картинами Пикассо...
На другом сиденье сидят двое. У них IQ=100:
- Мы с другом час назад посмотрели "От заката до рассвета". Как там Т. говорит тёлке, что...
На другом сиденье сидят другие двое. У них IQ=80:
- Слышь, братуха! Помнишь, какое пойло мы в меpсе пили, когда ноги какой-то бляди торчали в окне...
А на задней площадке стоят двое с IQ=40:
- Ну вот, значит, компилю сорцы в студии...
И еще посмотри, пожалуйста, код, я стараюсь использовать ООП, но понимаю, что мне становиться тяжело читать код, а значит я что-то делаю неправильно.
https://jsfiddle.net/97rk90jp/
В общем я хочу сделать сервис, который бы сохранял фотографии с финдфейса. То есть я бы открыл финдфейс, задал запрос по фотке, получил страницы девушек, а сервис бы прошел по всем выданным результатам и сохранил все фотки с каждой странички.
Ну или как-нибудь по-другому с таким же эффектом. Желательно чтобы я мог запустить это на денвере и сохранять сразу на пеку.
>не нужен только веб-бэкенд
У сервисов в сети какой бэкенд, во-Вашему, сударь? Веб-бэкенд или просто бэкенд?
Что вообще означает выражение "веб-бэкенд"? Есть сервер, на нём вся серверная часть хранится - это бэкенд и есть.
Тебе нужно просто скачать картинки со страницы? Хватит скрипта на Simple HTML DOM и функции file_put_conents.
>сайту, на котором мы все
Он может.
Децентрализованные борды на джаваскрипте без бэкендов давно открыли.
>хранится - это бэкенд и есть
Правильно.
А веб- бэкенд - это то что между бэкендом и клиентом.
Веб - это когда исключительно для браузера. Согласен с аноном, что он не нужен. Нужно делать REST сервис, его можно юзать откуда угодно, хоть в игорях через TCP сокеты.
Это единственный верный способ переформатировать результат таймстемпа из базы?
Вообще покачто PHP top1 на всех биржах вакансий/фриланса.
Ну а в целом, перекат с языка на язык, дело не самое сложное
>>777545
Все сайты уже написаны, закрывайте тред.
>>777535
Если уж на цмс стараются не писать сайты, то про это вообще лучше не говорить
>>777554
Ни одна из существующий массовых ЦМС не удовлетворяет потребностей крупных заказчиков и серьезных проектов.
Да считай у всех пишущих на фреймфорках есть свои ЦМСки, но это как правило более гибкие и менее монструозные вещи чем всякие ВордПрессы
>>777566
>>777564
>>777567
Важно понят основы программирования и построение алгоритмов в целом, базовые патерны и приемы.
Умные люди говорили что у ТРУъ прогера перекат на язык может занять всего день(понятное дело не до уровня сенйора-помидора)
Но вообще когда хорошо освоишься в одном языке, даже в ПХП, то понимаешь что можно писать на чем угодно открыв документацию и стек оверфлоу, все осваивается быстрее.
Чем тогда когда ты учился делать циклы и классы первый раз в жизни.
Помогает избежать не красивой на вид конвертации число-строка-туда-сюда.
Но суть все же одна, чертов MySql, решайт за меня как timestamp показать, а мне ебись
Ты скажи мускуэлу что тебе надо, он тебе как надо и выдаст.
если полная хуйня - намекните как надо было сделать.
Кстати, какие еще есть способы вставить пробел между рандомными элементами массивов, помимо ," ",?
Про фритюр достаточно знать что
- масло не выкипает и не выгорает, строго говоря
- выкипает вода
- в масле окисление идет (в нем много ненасыщенных связей). Обычно окисление начинается после выкипания воды.
- чтобы масло не менять неделями, оно должно не окисляться. для этого оно должно быть насыщенное
- насыщенные масла считаются обывателями вредными, поэтому приходится идти на разные изъебства (http://www.newyorker.com/magazine/2001/03/05/the-trouble-with-fries)
Все это относится к растительному маслу, с животным все иначе, там низкий процент ненасыщенных связей, и поэтому окисление медленное. Если жарят не на сковородке, а в масле, то обязательно, так масло остается при высокой температуре долгое время, к тому же быстро загрязняется. Классические макдональдовские картошки были на https://en.wikipedia.org/wiki/Tallow но пали в борьбе роковой еще в 1983-м году http://www.westonaprice.org/know-your-fats/the-oiling-of-america/
Сейчас там гидрогенизированные растительные масла + полидиметилсилоксаны, чтобы масло не пенилось https://en.wikipedia.org/wiki/Polydimethylsiloxane#Foods
Я бы юзал просто rand() и count() если нужно;
Или shuffle().
Но это на любителя.
Обеденить потом можно через implode или array_map
Учебник ОПа
Это не знание, а мнение... анонима... с двача.
>echo $word1[$randWord1[0]]," ", $word2[$randWord2[0]]," ",$word3[$randWord3[0]],"\n";
>echo $word1[$randWord1[1]]," ", $word2[$randWord2[1]]," ",$word3[$randWord3[1]],"\n";
По сути, это повторяется. Тут можно было бы одинаковую строку два раза в цикле с for ($i = 0; $i < 2; $i++) повторить, а потом вывести третью строку.
Ну и все эти
$randWord1 = array_rand($word1, 2);
$randWord2 = array_rand($word2, 2);
$randWord3 = array_rand($word3, 2);
$randWord4 = array_rand($word4, 1);
$randWord5 = array_rand($word5, 1);
- тоже впечатление громоздкости создают.
Задача в целом решена верно, но ты подходишь к такому этапу, когда нужно стремиться сделать максимально лаконично, без лишних телодвижений и повторений кусков кода.
<?php
class NewsMapper
{
/ Загружает модель из базы имея $id */
public function getById($id) { ... }
}
А что по идее должен вернуть метод getById ?
Объект класса News по логике?
Лучше форкай прежний код, чтобы братишки видели, к чему относился твой предыдущий вопрос, как код изначально выглядел.
Ну и вот тебе в помощь:
shuffle($word1);
shuffle($word2);
shuffle($word3);
shuffle($word4);
shuffle($word5);
Хотя, я думаю, ты и так догадался.
Дай ссылку на свой код.
Просто нажать на F5 - и всё.
Может, у тебя просто ошибок там нет или ты не поставил error_reporting(-1); в самом начале кода.
збс, понял
Я про то что нет инфы где именно в коде ошибка.
/ Сохраняет данные из модели в базу, делая UPDATE или INSERT запрос */
public function save(News $news) { ... }
А как метод должен определить, UPDATE или INSERT запрос делать?
public function getStudents($limit, $offset, $sort, $order) {
$pdoStatement = $this->pdo->prepare("SELECT FROM students ORDER BY :sort :order LIMIT :limit OFFSET :offset");
$pdoStatement->bindValue(":limit", intval($limit, 10), PDO::PARAM_INT);
$pdoStatement->bindValue(":offset", intval($offset, 10), PDO::PARAM_INT);
$pdoStatement->bindValue(":sort", $sort);
$pdoStatement->bindValue(":order", $order);
$pdoStatement->execute(); /
$pdoStatement = $this->pdo->query($statement);
return $pdoStatement;
}
Оно выдает неотсортированый результат, где я недобиндил? Осло, если подставить все значения в запрос вручную то все все прекрасно сортируется. Все аргументы в функцию заходят.
Криво скопировал блин.
public function getStudents($limit, $offset, $sort, $order) {
$pdoStatement = $this->pdo->prepare("SELECT * FROM students ORDER BY :sort :order LIMIT :limit OFFSET :offset");
$pdoStatement->bindValue(":limit", intval($limit, 10), PDO::PARAM_INT);
$pdoStatement->bindValue(":offset", intval($offset, 10), PDO::PARAM_INT);
$pdoStatement->bindValue(":sort", $sort);
$pdoStatement->bindValue(":order", $order);
$pdoStatement->execute();
return $pdoStatement;
}
При подстановке через :sort подставляется не имя поля, а строка и получается
ORDER BY 'name' (взять указанную строку) вместо BY name (взять значение поля)
То есть все строки получается имеют одинаковый вес и не сортируются.
имена полей нельзя вставлять через плейсхолдер, только через переменную с проверкой по списку.
Алсо у тебя метод получитьСтудентов возвращает не студентов, а какой-то pdoStatement. Написано же в названии, что возвращает студентов, так вот пусть студентов и возвращает.
ОП, как всегда исправил большинство, кроме
>>class Manager extends Profession
>> protected $salaryRate = 500; // базовая ставка
>> public function getProduct()
>А почему одно из значений сделано абстрактным методом, а другое - полем?
>Разве не логично для всех 3 полей сделать абстр. методы? Чтобы гарантированно
>не забыли их переопределить?
Потому что эти поля (ставку, кофе) нужно переопределять походу выполнения программы, при повышении ставки для аналитика. Можно сделать как ты советовал, сделать переопределяемые поля в классе Employee, по умолчанию брать из класса Profession, а при смене профессии сбрасывать. Будет норм?
>> // Если сотрудник соответствует профессии
>> if ($employee->getProfession()->getName() == $profession) {
>Если у тебя профессия - это объект, может логично передавать для поиска не >название, а этот объект?
>Или хотя бы сделать константы для обозначений профессий.
Тогда нужно где-то хранить объекты профессии, чтобы потом их передать в качестве аргументов. А про константы не понятно, их нужно будет создавать в начале программы, а где гарантия, что при создании новой профессии программист создаст новую константу? А если объявлять константу внутри класса профессии, то какой тогда в этом смысл, если можно использовать названия класса? Корректно ли использовать такую конструкцию в качестве аргумента $departament->findEmployees(get_class (new Analyst)); ?
>> // Если таковых нет, переходим к следующему департаменту
>> if (!$analysts) continue;
>В общем-то эта строка не нужна.
Почему не нужна? Если $analysts не определен, то данная итерация прервется, и цикл перейдет к другому департаменту, и не будет выполнятся код следующий за этой строкой.
>> // Назначаем Аналитика шефом
>> $analyst->setСhief(1);
>> // Снимаем с должности текущего шефа
>> $chiefEmployee->setСhief(0);
>Это явно нарушение инкапсуляции. Разве замена босса - это не задача департамента?
Почему это ошибка именно инкапсуляции, а не логики?
Я переделал, теперь метод смены работника в департаменте, которому аргументом передают работника, который если есть в депе получает статус шефа. Но деп все также обращается к методу Employee->setСhief(0); Я исправил ошибку?
ОП, как всегда исправил большинство, кроме
>>class Manager extends Profession
>> protected $salaryRate = 500; // базовая ставка
>> public function getProduct()
>А почему одно из значений сделано абстрактным методом, а другое - полем?
>Разве не логично для всех 3 полей сделать абстр. методы? Чтобы гарантированно
>не забыли их переопределить?
Потому что эти поля (ставку, кофе) нужно переопределять походу выполнения программы, при повышении ставки для аналитика. Можно сделать как ты советовал, сделать переопределяемые поля в классе Employee, по умолчанию брать из класса Profession, а при смене профессии сбрасывать. Будет норм?
>> // Если сотрудник соответствует профессии
>> if ($employee->getProfession()->getName() == $profession) {
>Если у тебя профессия - это объект, может логично передавать для поиска не >название, а этот объект?
>Или хотя бы сделать константы для обозначений профессий.
Тогда нужно где-то хранить объекты профессии, чтобы потом их передать в качестве аргументов. А про константы не понятно, их нужно будет создавать в начале программы, а где гарантия, что при создании новой профессии программист создаст новую константу? А если объявлять константу внутри класса профессии, то какой тогда в этом смысл, если можно использовать названия класса? Корректно ли использовать такую конструкцию в качестве аргумента $departament->findEmployees(get_class (new Analyst)); ?
>> // Если таковых нет, переходим к следующему департаменту
>> if (!$analysts) continue;
>В общем-то эта строка не нужна.
Почему не нужна? Если $analysts не определен, то данная итерация прервется, и цикл перейдет к другому департаменту, и не будет выполнятся код следующий за этой строкой.
>> // Назначаем Аналитика шефом
>> $analyst->setСhief(1);
>> // Снимаем с должности текущего шефа
>> $chiefEmployee->setСhief(0);
>Это явно нарушение инкапсуляции. Разве замена босса - это не задача департамента?
Почему это ошибка именно инкапсуляции, а не логики?
Я переделал, теперь метод смены работника в департаменте, которому аргументом передают работника, который если есть в депе получает статус шефа. Но деп все также обращается к методу Employee->setСhief(0); Я исправил ошибку?
чотко!
Такое ощущение что они сами себе создают проблемы и сами же их решают. Давно придуман MVC, а они вместо этого занимаются ерундой.
>>>You don't have permission to access / on this server.
Папки, файлы /var/www с 777 правами, владелец www-data; в апаче.конф:
><Directory /var/www/>
> Options Indexes FollowSymLinks
> AllowOverride All
> Require all granted
></Directory>
в файле настройки сайта: "*:80"
Что делать?
Single Page Application
Есть ли плюсы в нём? Многие хвалят, а я документацию посмотрел и мне не очень нравится этот код (Хотя может я просто толком не разобрался)
Ещё нужно изучить симфони, но из-за него я получил травму неокрепшей, тогда ещё, психики. Ломанулся, ели освоим пхп и больно получил по носу.
> Наоборот видно что отдается объект pdostatement
Откуда видно? Из названия метода getStudents видно, что отдаётся pdoStatement?
Несоответствием названия метода и возвращаемого значения ты обманываешь программиста, который будет в этом коде разбираться. Странно, что такие вещи приходится объяснять.
Лёл, весь день ебался с этой фигнёй, оказалось в скопированном конфиге путь был /home/user/server/, а не /var/www
> "chmod -R 755 /", переустановил ось
> /var/www с 777 правами
Это комбо. Ты можешь поставить линукс, но так и останешься с мышлением виндузятника на всю жизнь.
755 - проебался, сразу же понял, но было поздно.
777 - а что еще делать, если ничего не помогает?
>что еще делать, если ничего не помогает?
Ознакомиться с документацией, выяснить причину проблемы, устранить ее, понять как не повторять впредь.
Так до интернетов еще делали - работало.
Что неясного в "ничего не помогает"? Очевидно, что несколько инструкций по установке сервера было прочитано, очевидно что вопросы гуглу по поводу проблемы были заданы. Может ты предлагаешь все доки по апачу прочитать?
Нормальная система пытается минимизировать свою работу, максимизировать результат. Я бы мог потратить несколько часов в поисках и изучению доков о необходимых правах, а мог бы за минуту дать полные права и посмотреть - исправилась ли ситуация. Если ты делаешь наоборот - ты странный. А еще ты странный, ибо приёбываешься к пустякам.
В данном же случае, мне не помогло бы и знание всех доков в мире, ибо тут проблема была в невнимательности.
Я мимокрокодил, но судя по тому, что ты пишешь, тебе не стоит заниматься программированием.
>>778210
Одна из идей ООП это Single Responsibility, то есть когда у каждого класса своя задача. Как в организации: бухгалтер отвечает за отчеты, а кладовщик - за содержимое склада. Когда кто-то просит у кладовщика выдать ему товар, он не говорит тому, где его искать - это забота кладовщика. И когда руководителю нужен отчет о расходах, он не объясняет бухгалтеру как его составлять.
В рамках этой идеи мы выносим взаимодействие с базой данных в отдельный класс. Соответственно те, кто работает с этим классом, не должны разбираться, как там устроена база данных, как идет взаимодействие с ней.
Когда ты отдаешь наружу объект pdoStatement ты нарушаешь этот принцип. Вся работа с PDO должна быть в Table fata gateway и наружу никакие объкты PDO отдаваться не должны. Получается в твоем классе кладовщик просто открывает двери склада и говорит: "а, иди вот там сам в углу поищи". Согласись, при таком подходе появляется вопрос, а зачем этот кладовщик вообще нужен.
Метод getStudents/getStudent должен возвращать модель студента или например массив таких моделей. А не предлагать самому поискать их в базе данных. Это его ответственность сохранять и загружать эти модели из базы данных.
Я не оскорбляю тебя, я просто говорю, что, возможно, стоит заняться чем-то другим.
Так как в программировании постоянное чтение документации это одна из главных составляющих обучения и работы.
А ты считаешь чтение доков к апачу каким-то нонсенсом.
Ты так красиво говоришь.
> В данном же случае, мне не помогло бы и знание всех доков в мире, ибо тут проблема была в невнимательности.
Нужно уметь пользоваться средствами для анализа и поиска причин ошибки. Не вслепую перебирать разные варианты, а разбивать проблему на части и проверять по очереди.
В твоем случае, нужно было смотреть лог ошибок веб-сервера. Там пишется путь к файлу, который не удалось открыть.
Опять же, когда ты что-то устанавливаешь, важно знать, как проверить, работает оно или нет. Ты установил какой-то пакет - как проверить что он установлен? Как проверить что веб-сервер запущен? И так далее.
>>778334
Не надо так.
>>778224
Лучше всего посмотреть и ларавель и симфони. Симфони да. сложная, но если ты будешь читать документацию, исходный код и мои уроки по темам вроде DI то со временем осилишь.
>>776112
Аяксом загружается нужная страница и заменяется часть дерева DOM. Никакого СПА там нет в помине.
>>778347
Если бы мне сказали, что файл не найден - я бы искал ошибки в путях;
Мне же сказали, что доступ запрещён - очевидное решение - дать доступ.
Где тут отсутствие анализа и слепой перебор?
>Опять же, когда ты что-то устанавливаешь, важно знать, как проверить, работает оно или нет. Ты установил какой-то пакет - как проверить что он установлен? Как проверить что веб-сервер запущен? И так далее.
Ты сначала изучаешь в подробностях доки, а только потом пишешь хеллоуворд, или наоборот? Я же даже до хеллоуворда не дошёл.
Некто не знает как из нее запустить код на похапе?
А смысл переписывать код хелло ворлда не понимая, как он работает? Я не могу работать с кодом если что-то в нем не понимаю.
>>778358
Это не иде, а текстовый редактор. Запустить пхп скрипт можно из командной строки, гайд по ней в ОП посте.
Есть некоторая вероятность, что доступ запрещен не просто так, а с какой-то целью.
Так что очевидным было бы подумать, зачем выставлены такие права на служебные папки, и что произойдет на рабочем сервере при получении общего доступа.
Или изначально у этих папок были одни права, а для работы веб-сервера нужны другие права, что более очевидней.
Подумать почему у них были изначально другие права? Вдруг эти права были выбраны не бросанием кубиков от нечего делать?
>Что неясного в "ничего не помогает"?
> несколько инструкций по установке сервера было прочитано, очевидно что вопросы гуглу по поводу проблемы были заданы. Может ты предлагаешь все доки по апачу прочитать?
Формулировка неверна. Не "Ничего не помогает", а "ничего не помогает без включения головы, а голову я включать не хочу, хочу только перебирать пошаговые инструкции для макак, пока какая-то из них не заработает, не понимая что в них написано".
Тебе-то виднее, что я делал.
>>778445
Например, эти права были выбраны из соображения нужд линукса, который о апаче ничего не знает.
https://github.com/never3ver/students_list
В свое оправдание могу сказать только то, что оно таки работает.
>из соображения нужд линукса, который о апаче ничего не знает
Ты Линупс из LFS собирал? Непохоже.
А дистрибутивы Линупса об Апаче знают.
Спасибо.
> Цель поиска работы
> Неправильно: Работа в перспективной компании с возможностью развития, самореализации и работы на благо компании.
> Правильно: хочу найти работу
Зарегался на одном из крупнейших украинских сайтов поиска работы, куча ошибок типа того что отзыв отправляется дважды, а резюме в текстовом виде отображается в неправильной кодировке. Написал в суппорт, говорят сохраняйте картинкой в pdf.
За 4 дня всего 3 отзыва, причем звонят какие-то левые манагеры, которые даже не в курсе чем занимается их фирма, предлагают заполнить какие-то километровые бланки.
Может ну их, эти ссайты поиска работы, взять список айти-компаний и заспамить им почту своим резюме? Хочется пойти в обход этой бюрократии.
Не понял, каким образом можно было брать буквы с конца. Пришлось перед циклом сделать еще 1 переменную.
btw, оглашать две переменные в действии1\менять их в действии2 это плохо ?
ака for($i = 0, $x = 0;$i <= 123;$i++, $x++){}
да
какого то хрена выводится то, что я убрал.
вот тот же самый код по другой ссылке http://ideone.com/Liri3Q
внезапно нагавнокодил решение за меньше строк, чем у ОПа. где мой фейл ?
>$i <666
Плохая попытка, ацкий сотона.
Плохой ориентир для работы цикла.
В подобных циклах лучше ориентироваться на сумму кредита: когда она становится равной нулю - прекращать цикл.
Так надёжнее да и просто логичнее.
Что за говно на пикрелейтеде? Выложи своё резюме на hh.ru. Я так сделал, два раза даже мне первому написали (правда в итоге не взяли никуда), остальное время я сам оставлял заявки на работу.
Достаточно ли подсунуть курлу/газзлу useragent, или не проканает?
(Апи платный)
Почему box-shadow перестает работать?
Не понял. Что значит "перестает работать"? Если ты про тень у большого блока, в котором находится страница, то она не исчезает. Может у тебя просто на мониторе яркость перекручена? Попробуй сделать очень контрастную тень и проверить снова.
На других языках работы в сраной и нет.
Ты оказался прав. Контрастная тень отображается. Но как же тогда тень видна на темном фоне? Очень интересный эффект.
Delphi изучай. На ней тут пишут до сих пор.
10 сообщений только за вчерашний день http://www.sql.ru/forum/delphi
ЛОЛ, мне однажды какие-то клоуны такое "тестовое задание" дали - типа надо написать скрипт, который будет к заглавной странице гугла посылать запросы, потом парсить ответ и извлекать из него полезные данные.
И примечание внизу - АПИ использовать нельзя.
Тогда я нифига не понял прикола (но задание делать не стал, к счастью). А оно вот оно что - АПИ, оказывается-то платное!
Анон, будь бдителен, не делай хитрожопым мудакам работы, которую они под видом тестовых заданий подсовывают
>>779251 Почему % делит неправильно большие числа, задача про номера телефонов, не могу запустить пхп под виндой, где почитать про работу с формами и базой, оптимизация сайта джейсоном
>>779252Поиск опечаток, $mapper->getTimers(), игра в кубики
>>779253 Ответы по https://github.com/someApprentice/Students
>>779254Где поичтать про ООП, про mysqli
---------------
Ответьте-ка, ваши задачи проверять надо? Как у вас дела с решением?
>>762502 https://github.com/foobar1643/filehosting
>>771145 https://github.com/TheSidSpears/Students
----------------
Напомню себе проверить позже:
>>774244
Вектор http://ideone.com/H5DCfT
Набросок Кошек-Мышек http://ideone.com/f1aQaw
>>774967 https://github.com/applejacky/students
>>779251 Почему % делит неправильно большие числа, задача про номера телефонов, не могу запустить пхп под виндой, где почитать про работу с формами и базой, оптимизация сайта джейсоном
>>779252Поиск опечаток, $mapper->getTimers(), игра в кубики
>>779253 Ответы по https://github.com/someApprentice/Students
>>779254Где поичтать про ООП, про mysqli
---------------
Ответьте-ка, ваши задачи проверять надо? Как у вас дела с решением?
>>762502 https://github.com/foobar1643/filehosting
>>771145 https://github.com/TheSidSpears/Students
----------------
Напомню себе проверить позже:
>>774244
Вектор http://ideone.com/H5DCfT
Набросок Кошек-Мышек http://ideone.com/f1aQaw
>>774967 https://github.com/applejacky/students
>Ответьте-ка, ваши задачи проверять надо? Как у вас дела с решением?
Мою пока нет, я замечания исправил, доделаю юнит-тесты и залью всё одним коммитом.
Пользуясь случаем задам вопрос про борьбу с XSS с помощью JS. Вот такой замены символов будет достаточно, или это неэффективный способ и его можно как-то обойти?
>comment.text = comment.text.replace(/</g, "<").replace(/>/g, ">");
>comment.text.replace(/</g, "& lt ;").replace(/>/g, "& gt ;");
Быстрофикс (в реальном варианте без пробелов, конечно).
Я там в прошлом треде пропустил твой важный пост с вопросами и сразу не ответил, вот тут вот написал ответ >>779253
Давай-ка попробуем немного разобраться с общими принципами, которых мы придерживаемся. Я не хочу чтобы у нас тут были религиозные догмы "так делать нельяз потому что ОП так сказал" или "так делать нельзя, бох накажет". Нет, мы используем инженерный подход и каждое решение на чем-то основано.
Легко ли будет поддерживать код? улучшать? защищен ли он от случайных ошибок или опечаток? Легко ли понять алгоритм его работы? Быстро ли он пишется? Нет ли копипасты?
-----------
Во-первых, разбиение кода на функции, которые можно повторно использовать. Например, мы могли бы написать код регистрации одной стеной без разбиения на функции и классы, но он скорее всего будет большим, тяжело читаемым, а при редактировании легко допустить в нем ошибку. Более того, поскольку код не разбит на функции, мы не можем использовать его или его часть где-то еще. Например мы не можем использовать алгоритм валидации данных в форме в другом месте, так как он не вынесен в отдельную функцию.
Стена кода это плохо. Человек в общем не способен воспринимать большие стены кода и ему надо разбивать их на относительно небольшие и законченные функции которые можно рассматривать по отдельности. Разумное ограничение - 1-2 экрана кода (30-50 строк) максимум. Некоторые считают что функция должна помещаться в распечатанном виде на листе A4, некоторые - что должна помещаться на экране без прокрутки.
Функции должны быть максимально независимы друг от друга, так, что изменение в одной не ломает другую. Например, функция валидации не должна думать что данные пришли из формы. Лучше написать функцию валидации, которая принимает модель студента и проверяет ее независимо от того, откуда мы ее взяли.
Не должно быть слишком много аргументов (больше 3-5) или возвращаемых значений. Если их больше то скорее всего надо сделать несколько функций или надо объединить аргументы в один. Например сделать модель студента вместо передачи каждого поля отдельной переменной.
-----------
Далее, классы. Есть принцип "единой ответственности" - каждый класс отвечает за свою часть задачи. Нормально для каждой новой задачи делать новый класс.
Нам нужно как-то хранить и передавать информацию о студенте - делаем модель Student
Нам нужно выполнять запросы к БД - берем готовый класс PDO
Нам нужно сохранять и загружать студента из БД - делаем маппер или Table Gateway. Будет у нас какая-то другая сущность и другая таблица в БД - сделаем для нее свой, отдельный маппер.
Нам нужно проверять правильно ли заполнена информация о студенте - делаем валидатор
Нам нужно хранить и обрабатывать данные формы регистрации - делаем класс соответствующий форме
Нам нужно сделать авторизацию, залогинивание/разлогинивание - делаем класс авторизации
При этом важно не перестараться. Например, ты бы мог сделать отдельно класс для поиска студентов в базе, отдельно для добавления, отдельно для изменения, но на практике это не даст никакой особой выгоды, так как эти задачи очень схожи и являютяс по сути частями задачи "надо хранить студентов в БД". Хотя если когда-то у тебя твой маппер станет очень большим - можно подумать о том как разбиить его на части и что-то вынести в отдельный класс.
Разумное ограничение - до 500-1000 строк в классе. Если больше - пора разбивать.
Бывает, что функцию некуда отнести. Например функция перевода байт в гигабайты. Не делать же ради нее отдельный класс ПереводчикБайтВГигабайты. Делаем класс Util или Helper и пихаем туда такие функции статическим методом.
Помни что классы обычно делят на "сущности" (являются моделью чего-то, например модель студента, хранят в себе данные) и "сервисы" (обычно существуют в одном экземпляре, не хранят внутри данные, кроме каких-нибудь настроек). "Сущности" условно можно поделить на "активные" (сами умеют что-то делать, например , сохранять себя в базу, записывать в файл и тд) и "пассивные" (просто хранят данные с которыми работают сервисы).
Например объект PDO это "сервис" для выполнения запросов к базе данных. Модель студента - "сущность".
-----------
Далее, у классов есть зависимости. Мапперу нужен объект PDO, валидатору нужен маппер. Решаем эту проблему с помощью dependency injection. Если ты читал урок по нему, то этот способ имеет определеные преимущества.
-----------
Слои. Сервисы часто можно разделить на "слои" по такому признаку: есть "высокоуровневые" сервисы, которые используют сервисы из более нижнего слоя. При этом управление идет сверху вниз, и сервисы из более нижележащего слоя не вызывают методы вышележащего. Также, обращение идет только к классам из нижелещащего слоя, но не из более глубоких слоев.
Например:
- контроллер вызывает сервис валидации для проверки данных в форме
- сервис валидации использует маппер чтобы проверить уникальность email
- маппер использует PDO чтобы выполнять запросы
Тут можно выделить слой взаимодействия с пользователем (его браузером) из контроллера и вида (самый верхний), слой сервисов, слой доступа к данным (мапперы + PDO). PDO я не буду выделять в отдельный слой, их и так много получилось.
Вот можно тут почитать пример: https://habrahabr.ru/post/257677/
Это конечно более актуально для больших приложений, у нас объем маленький, но даже тут выделяются "слои".
-----------
Далее, MVC. MVC подсказывает нам как именно можно
Тут идея в том, что мы разбиваем обработчик запроса пользователя на 3 части: Модель, Контроллер, Вид (представление)
Модель хранит в себе внутреннюю логику работы приложения, но не занимается взаимодействием с пользвоателем или отображением данных. Ну например, валидация студента или хранение их в базе - это ее задача, а вывод страницы или анализ кук - нет. Имея только модель мы можем получать и обрабатывать любые данные с которыми работает наше приложение (в данном случае - список студентов).
Вид просто выводит значения, которые ему передали, например в виде HTML страницы.
Контроллер управляет процессом обработки запроса от пользователя. Он анализирует запрос пользователя (например смотрит, указано ли слово для поиска по студентам или нет), затем вызывает модель чтобы получить данные или выполнить какие-то действия над ними, затем вызывает вид чтобы отобразить страницу пользователю (или делает редирект, это не принципиально).
Зачем нужен МВЦ? Ну в нашем случае он помогает нам ответить на вопрос, как именно нам разбить задачу обработки формы регистрации пользователя или вывод списка студентов на отдельные классы. Также, благодаря отделению модели от контроллеров/видов, мы можем сделать альтернативные интерфейсы приложения.
Например мы можем сделать консольную программу, выводящую список студентов в консолью Эта программа сможет повторно использовать маппер, чтобы получить список студентов, а вот вывод его - делает самостоятельно. Если бы у нас не было разделения на МВЦ, то нам пришлось бы копипастить код выборки и поиска студентов из БД.
Аналогично, мы можем сделать например REST API, предосталвяющее данные студентов в формате JSON и позволяющее их обновлять, опять же, данными из JSON. В этом АПИ будет свой набор контроллеров и видов, но модель оно будет использовать ту же самую.
То есть модель - это что-то вроде "ядра" приложения, содержащая логику работы приложения и отделенная от интерфейса.
Чем является хелпер авторизации? Очевидно что это не модель, так как модель не управляет куками и не взаимодействует с пользователем (точнее с его браузером). Очеивдно что в консоли никаких кук нет, куки есть только при взаимодействии с браузером. Значит это не часть модели.
Хелпер авторизации это скорее часть слоя контроллеров. Мы выносим в него все, что связано с залогиниванием/разлогиниванием в соответствии с принципом "каждый класс занимается своим делом" и ради того, чтобы этот код можно было испоьзовать из разных мест.
------------------
Вот первая порция принципов, которых мы бы хотели придерживаться.
Теперь задавай свои вопросы.
Я там в прошлом треде пропустил твой важный пост с вопросами и сразу не ответил, вот тут вот написал ответ >>779253
Давай-ка попробуем немного разобраться с общими принципами, которых мы придерживаемся. Я не хочу чтобы у нас тут были религиозные догмы "так делать нельяз потому что ОП так сказал" или "так делать нельзя, бох накажет". Нет, мы используем инженерный подход и каждое решение на чем-то основано.
Легко ли будет поддерживать код? улучшать? защищен ли он от случайных ошибок или опечаток? Легко ли понять алгоритм его работы? Быстро ли он пишется? Нет ли копипасты?
-----------
Во-первых, разбиение кода на функции, которые можно повторно использовать. Например, мы могли бы написать код регистрации одной стеной без разбиения на функции и классы, но он скорее всего будет большим, тяжело читаемым, а при редактировании легко допустить в нем ошибку. Более того, поскольку код не разбит на функции, мы не можем использовать его или его часть где-то еще. Например мы не можем использовать алгоритм валидации данных в форме в другом месте, так как он не вынесен в отдельную функцию.
Стена кода это плохо. Человек в общем не способен воспринимать большие стены кода и ему надо разбивать их на относительно небольшие и законченные функции которые можно рассматривать по отдельности. Разумное ограничение - 1-2 экрана кода (30-50 строк) максимум. Некоторые считают что функция должна помещаться в распечатанном виде на листе A4, некоторые - что должна помещаться на экране без прокрутки.
Функции должны быть максимально независимы друг от друга, так, что изменение в одной не ломает другую. Например, функция валидации не должна думать что данные пришли из формы. Лучше написать функцию валидации, которая принимает модель студента и проверяет ее независимо от того, откуда мы ее взяли.
Не должно быть слишком много аргументов (больше 3-5) или возвращаемых значений. Если их больше то скорее всего надо сделать несколько функций или надо объединить аргументы в один. Например сделать модель студента вместо передачи каждого поля отдельной переменной.
-----------
Далее, классы. Есть принцип "единой ответственности" - каждый класс отвечает за свою часть задачи. Нормально для каждой новой задачи делать новый класс.
Нам нужно как-то хранить и передавать информацию о студенте - делаем модель Student
Нам нужно выполнять запросы к БД - берем готовый класс PDO
Нам нужно сохранять и загружать студента из БД - делаем маппер или Table Gateway. Будет у нас какая-то другая сущность и другая таблица в БД - сделаем для нее свой, отдельный маппер.
Нам нужно проверять правильно ли заполнена информация о студенте - делаем валидатор
Нам нужно хранить и обрабатывать данные формы регистрации - делаем класс соответствующий форме
Нам нужно сделать авторизацию, залогинивание/разлогинивание - делаем класс авторизации
При этом важно не перестараться. Например, ты бы мог сделать отдельно класс для поиска студентов в базе, отдельно для добавления, отдельно для изменения, но на практике это не даст никакой особой выгоды, так как эти задачи очень схожи и являютяс по сути частями задачи "надо хранить студентов в БД". Хотя если когда-то у тебя твой маппер станет очень большим - можно подумать о том как разбиить его на части и что-то вынести в отдельный класс.
Разумное ограничение - до 500-1000 строк в классе. Если больше - пора разбивать.
Бывает, что функцию некуда отнести. Например функция перевода байт в гигабайты. Не делать же ради нее отдельный класс ПереводчикБайтВГигабайты. Делаем класс Util или Helper и пихаем туда такие функции статическим методом.
Помни что классы обычно делят на "сущности" (являются моделью чего-то, например модель студента, хранят в себе данные) и "сервисы" (обычно существуют в одном экземпляре, не хранят внутри данные, кроме каких-нибудь настроек). "Сущности" условно можно поделить на "активные" (сами умеют что-то делать, например , сохранять себя в базу, записывать в файл и тд) и "пассивные" (просто хранят данные с которыми работают сервисы).
Например объект PDO это "сервис" для выполнения запросов к базе данных. Модель студента - "сущность".
-----------
Далее, у классов есть зависимости. Мапперу нужен объект PDO, валидатору нужен маппер. Решаем эту проблему с помощью dependency injection. Если ты читал урок по нему, то этот способ имеет определеные преимущества.
-----------
Слои. Сервисы часто можно разделить на "слои" по такому признаку: есть "высокоуровневые" сервисы, которые используют сервисы из более нижнего слоя. При этом управление идет сверху вниз, и сервисы из более нижележащего слоя не вызывают методы вышележащего. Также, обращение идет только к классам из нижелещащего слоя, но не из более глубоких слоев.
Например:
- контроллер вызывает сервис валидации для проверки данных в форме
- сервис валидации использует маппер чтобы проверить уникальность email
- маппер использует PDO чтобы выполнять запросы
Тут можно выделить слой взаимодействия с пользователем (его браузером) из контроллера и вида (самый верхний), слой сервисов, слой доступа к данным (мапперы + PDO). PDO я не буду выделять в отдельный слой, их и так много получилось.
Вот можно тут почитать пример: https://habrahabr.ru/post/257677/
Это конечно более актуально для больших приложений, у нас объем маленький, но даже тут выделяются "слои".
-----------
Далее, MVC. MVC подсказывает нам как именно можно
Тут идея в том, что мы разбиваем обработчик запроса пользователя на 3 части: Модель, Контроллер, Вид (представление)
Модель хранит в себе внутреннюю логику работы приложения, но не занимается взаимодействием с пользвоателем или отображением данных. Ну например, валидация студента или хранение их в базе - это ее задача, а вывод страницы или анализ кук - нет. Имея только модель мы можем получать и обрабатывать любые данные с которыми работает наше приложение (в данном случае - список студентов).
Вид просто выводит значения, которые ему передали, например в виде HTML страницы.
Контроллер управляет процессом обработки запроса от пользователя. Он анализирует запрос пользователя (например смотрит, указано ли слово для поиска по студентам или нет), затем вызывает модель чтобы получить данные или выполнить какие-то действия над ними, затем вызывает вид чтобы отобразить страницу пользователю (или делает редирект, это не принципиально).
Зачем нужен МВЦ? Ну в нашем случае он помогает нам ответить на вопрос, как именно нам разбить задачу обработки формы регистрации пользователя или вывод списка студентов на отдельные классы. Также, благодаря отделению модели от контроллеров/видов, мы можем сделать альтернативные интерфейсы приложения.
Например мы можем сделать консольную программу, выводящую список студентов в консолью Эта программа сможет повторно использовать маппер, чтобы получить список студентов, а вот вывод его - делает самостоятельно. Если бы у нас не было разделения на МВЦ, то нам пришлось бы копипастить код выборки и поиска студентов из БД.
Аналогично, мы можем сделать например REST API, предосталвяющее данные студентов в формате JSON и позволяющее их обновлять, опять же, данными из JSON. В этом АПИ будет свой набор контроллеров и видов, но модель оно будет использовать ту же самую.
То есть модель - это что-то вроде "ядра" приложения, содержащая логику работы приложения и отделенная от интерфейса.
Чем является хелпер авторизации? Очевидно что это не модель, так как модель не управляет куками и не взаимодействует с пользователем (точнее с его браузером). Очеивдно что в консоли никаких кук нет, куки есть только при взаимодействии с браузером. Значит это не часть модели.
Хелпер авторизации это скорее часть слоя контроллеров. Мы выносим в него все, что связано с залогиниванием/разлогиниванием в соответствии с принципом "каждый класс занимается своим делом" и ради того, чтобы этот код можно было испоьзовать из разных мест.
------------------
Вот первая порция принципов, которых мы бы хотели придерживаться.
Теперь задавай свои вопросы.
Надо написать на JS аналог htmlspecialchars. Напиши и отдельно попроси проверить (ну и сам потестируй).
>>779260
Недостаточно. Не заменяется & например. Не заменяется символ кавычки который может сломать атрибут при постановки вида <input value="{x}">. Хотя ты это не делаешь, но вдруг захочешь потом.
А, еще. Есть принцип "тонкий контроллер - толстая модель". Он говорит о том, что мы должны по возможности стараться писать код в модели, а не в контроллере. Ну например, валидация студента или запись в базу должна быть в модели, а контроллер только вызывает эти методы одной строчкой.
Чем плохи "толстые" контроллеры? Почему мы не можем сделать валидацию, проверку залогиненности, и запись в базу просто отдельными методами в контроллере формы регистрации? Принцип разбиения на функции ведь соблюдается.
И еще, может тебе интересно будет почитать книгу:
Стив Макконнелл Совершенный код.
Не знаю, может она сложновата будет для тебя, но если есть время, попробуй почитать, полистать. Там многие принципы, что я кратко написал, расписываются подробно.
http://pastebin.com/Aejdtp8X а вот так?
Тестировал строками отсюда https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
Проверил штук 20, ни одна не сработала.
ОП Кошек-Мышек проверять не надо. Я выложил сюда кусок кода для того, чтобы спросить как найти ближайшую кошку и как я пытался ее найти. Ответ на этот вопрос я получил.
Это и есть тестовое (они всем однотипное шлют).
>не делай хитрожопым мудакам работы, которую они под видом тестовых заданий подсовывают
Что ты несешь?
Гугл дает бесплатно 100 запросов в день (мизерное количество). Если превысишь, то никто с тебя не будет без спроса брать деньги, гугл просто вежливо попросит приобрести премиум (5$ за тысячу запросов в сутки).
Тут на самом деле другой подвох: если скрейпить напрямую, и делать слишком большое количество запросов, гугл тебе сначала начнет выдавать капчу вместо результата, а если не угомонишься, то и забанит по айпи.
Для этого с переменным успехом используют прокси, выдерживают тайм-аут, меняют в заголовках юзер-агента, но все равно это очень сложное дело.
Вот пытаются написать универсальный парсер http://serp-spider.github.io/ , для такой задачки с не очень активным трафиком может и сойдет.
Еще подвох в том, что гугл может изменить верстку результатов выдачи, и твой парсер сломается. Короче это очень геморрное дело, странно что дают такое на собеседовании. Наверное проверяют, что человек умеет не только копипастить чужой код, но и думать головой.
> гугл может изменить верстку результатов выдачи, и твой парсер сломается
А как именно может поменять? Xpath-запросы позволяют парсить страницы без привязки к классам/id/атрибутам. Можно обойтись исключительно привязкой к последовательности тегов.
Тащемта тут ничего сложного. Просто садишься и без задней мысли пишешь код.
Разбей задачу на подзадачи (регистрация, валидация, работа с БД) и решай каждую отдельно.
Да я каждую отдельно могу решить. Но как мне начать-то? Я ща понял, что хоть и писал до этого контроллеры с моделями на фреймворке, то нихуя не знаю как начать писать подобную прилажуху с 0 на pure-php.
Вот думаю захярить класс-дворецкий, который будет смотреть что у нас с куками и уже подсовывать нужный контроллер юзеру, либо на вход/регистрацию, либо на его страницу.
Как с 0 роутинг писать блджад?
Стало быть я пишу что-то в духе
abstract class Yoba () {
public function start() {
...
}
}
и потом в коде просто пишу Yoba::start();
и всё у меня запускается??
Я конечно понимаю, что у меня класс абстрактный, но нельзя ли как-то туда конструктор еще заебенить?
Что бы оно вообще само кароче всё запускалось.
Прочитай этот пост вначале: >>779261
Также, в задаче про студентов очень подробные пояснения. Прочитай их тоже.
Начинать проще наверно с проектирования базы данных и вывода списка, потом регистрация, потом редактирование.
>>779548
Плохо что не можешь.
Я вижу 2 варианта роутинга:
- роутинг за счет разных имен файлов. То есть у нас есть допустим файл index.php, выводящий список и файл profile.php, обрабатывающий форму регистрации/редактирования. В этом случае роутингом по сути занимается Апач.
- написать свой кастомный роутинг. То есть анализировать URL, если он равен / то выводим список, если /profile то форму редактирования. То ест использовать паттерн Front Controller - контроллер, который запускается первым и решает какой контроллер дальше вызвать.
>>779594
У тебя по моему проблемы с пониманием ООП.
1) почему abstract? abstract это класс объекты которого нельзя создавать.
2) почему статические методы?
> который будет просто управлять. Объект не нужен ему
Нужен. Ведь мы можем захотеть сделать 2 таких класса и чтобы один никак не влиял на другой. И вообще, статические методы это плохо, я уже объяснял в уроке по DI это.
Прочитай этот пост вначале: >>779261
Также, в задаче про студентов очень подробные пояснения. Прочитай их тоже.
Начинать проще наверно с проектирования базы данных и вывода списка, потом регистрация, потом редактирование.
>>779548
Плохо что не можешь.
Я вижу 2 варианта роутинга:
- роутинг за счет разных имен файлов. То есть у нас есть допустим файл index.php, выводящий список и файл profile.php, обрабатывающий форму регистрации/редактирования. В этом случае роутингом по сути занимается Апач.
- написать свой кастомный роутинг. То есть анализировать URL, если он равен / то выводим список, если /profile то форму редактирования. То ест использовать паттерн Front Controller - контроллер, который запускается первым и решает какой контроллер дальше вызвать.
>>779594
У тебя по моему проблемы с пониманием ООП.
1) почему abstract? abstract это класс объекты которого нельзя создавать.
2) почему статические методы?
> который будет просто управлять. Объект не нужен ему
Нужен. Ведь мы можем захотеть сделать 2 таких класса и чтобы один никак не влиял на другой. И вообще, статические методы это плохо, я уже объяснял в уроке по DI это.
>1) почему abstract? abstract это класс объекты которого нельзя создавать.
Так мне и не нужен объект.
Мне нужен просто класс инициализатор например, который будет запускать всю движуху в скрипте.
Зачем мне создавать объект только ради движухи?
>Нужен. Ведь мы можем захотеть сделать 2 таких класса и чтобы один никак не влиял на другой.
Я ничего не понял, ты имел в виду 2 объекта?
>DI
что такое DI?
Ты плохо понимаешь ООП. abstract значит что это базовый класс для создания других классов на его основе. Тут он не применим.
Не вижу никаких проблем создать объект.
Урок по DI https://github.com/codedokode/pasta/blob/master/arch/di.md
// Данный файл всегда будит "включаться" в другие файлы
// директивой include поэтому следует запретить его самостоятельный вызов
// из строки запроса путём указания его имени
// Если не определена константа IN_ADMIN – завершаем работу скрипта
if(!defined("IN_ADMIN")) die;
Сервера, апач, как запускать свои скрипты на сервере и т.д?
Представляю сколько глистов у этих кошатниц.
Который раз уже это пишешь, а запятые ставить так и не научился..
> Ответьте-ка, ваши задачи проверять надо? Как у вас дела с решением?
TheSidSpears. Если проверять вот прямо сейчас - то, наверное еще рановато. Я переписываю, сижу каждый день, но еще не все исправил согласно твоим замечаниям.
Всяко, можешь и на изменения глянуть. Я там контроллеры в классы загонял
Всегда считал, что анимубляди пишут на этом японском бейсике... Как его там, Сапфир штоле?
Все 4 языка - диалекты Бейсика. В Perl вон даже ключевое слово SUB осталось.
Хотя в PHP зачем-то C/C++ синтаксис.
sub в Perl это, скорее, наследие баша.
inb4 баш это диалект бейсика
>Хотя в PHP зачем-то C/C++ синтаксис.
А еще джаваподобное ООП. Я же говорю, анимубляди. Типа как в типичном веобушном медиа-продукте: понадергали отовсюду понемногу, в результате никакой целостности, сплошной кластерфак.
Про баш не знаю. Виндовый скриптовый язык очень похож на Бейсик.
А PHP возможно создавался под влиянием JavaScript, это объясняет синтаксис и ООП.
А жс под влиянием чего? Вот-вот.
Олсо, считаю большим упущением отход от практики совмещения html и php кода. Ведь такая-то киллер фича.
> А жс под влиянием чего? Вот-вот.
Он был создан для пиара самой Java вместе с апплетами. Такой младший брат.
> Олсо, считаю большим упущением отход от практики совмещения html и php кода. Ведь такая-то киллер фича.
А что в этом хорошего? Я считаю, что и html с js в одном файле смешивать плохо. Данные (тем более интерфейс) и код должны храниться отдельно.
>А что в этом хорошего?
Можно запихнуть прямо в хтмл код какую-нибудь логику. Собственно, для большего PHP и не нужен.
Зачем все держать в одном файле? Потом заебешься же искать эту логику.
Мне вообще кажется, должна быть такая штука, которая рисует таблички, где видно, где какой объект, какого класса и какие там методы и свойства
Graphviz. Только не знаю, работает ли он нормально под Windows или нет.
http://chapman.id.au/generate-php-class-inheritance-diagrams-in-graphviz тут есть скрипт на баше который из вывода Graphviz делает картинки.
> Тут в папку свалены разные классы, часть из которых точно не модели - например, FrontController никак моделью не является. Роутер явно не является частью модели. И вообще, MVC не значит что у тебя должно быть ровно 3 папки view, controller и model. Это деление приложения на 3 части, а не файлов на 3 папки.
Я просто переименовал models в classes. Просто рассовывать по папкам 9 файлов - только путаницы больше будет
>Далее, ты разбиваешь УРЛ на части и берешь последнюю, а что если УРЛ имеет вид /a/b/c/d/e/f - ты берешь только f, а остальные игнорируются?
Да, в данном коде у меня только последнее - модуль, остальное путь до индекса http://localhost/students/public/main
> if($currentPage<=0){$currentPage=1;}
> Тебе надо лучше форматировать код. Иф пишется в 3 строки, а не в одну. Также, тут можно было обойтись функцией max.
Не понял зачем и как
Хочу запустить скрипт по скачиванию картинки на денвере и не знаю через какой метод.
Могу предложить работу, не регулярную, можете рассматривать как подработку.
Создание преимущественно интернет-магазинов. Знание распространённых цмс (битрикс, хостцмс и т.д. приветствуется) В будущем битрикса не будет, только зарубежные заказы.
daniilsergeewichnazarK+zowANUSgmai~UZlPUNCTUMcnA:om
миморетард с файлообменника психологически находящийся на стадии задачек с ideone
Есть, но такие уже работают.
js, css, img - в публичной папке, от них вреда нет, там же index.php
В index.php только автозагрузчик классов, загрузчик конфигурации и загрузчик роутера, которому конфигурация передается через Dependency Injection. Сам роутер и конфигурация не лежат в паблике, они там же где и все остальные классы. Темплейты в html тоже не в паблике, потому что там можно код включать.
Можно же последовательность тегов поменять.
Правильно хоть что-то делаю?
Столкнулась с тем, что $title не меняется. Есть догадка, что операции, которые я считаю переопределением переменной, на самом деле создание новой, с ограниченной областью видимости. Вне зависимости от того, какое действие произведено, её значение всегда остаётся "Contact Us", Как мне сделать заебись?
> return self::html($url);
> Почему функция makeUrl вызывает self::html? А что если нам нужен исходный неискаженный УРЛ (например мы хотим редиректить на него)?
А редирект на htmlspecialchars($url) не сработает разве?
> https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php#L57
> foreach ($blockedParams as $key => $value) {
> $url.=$key."=".$value."&";
>Что если в value содержится символ &, #, ? или какой-то еще, имеющий специальное значение в УРЛ?
Так ничего ж не происходит. Если юзер в url шнягу пишет localhost/students/public/search?page=1&find=%D0%A5%D0%B8#&sortBy=grou?&p_num&orderBy=a#sc, то скрипт выдаёт страницу c значениями этих переменных по умолчанию, сбрасывает параметры сортировки и поиска
> $token= (isset($_COOKIE['token'])) ? $_COOKIE['token'] : Util::randHash(20);
> setcookie('token',$token,time()+3600,'/',null,false,true);
> Не лучше ли работу с CSRF кукой вынести в отдельный класс? Как ты повторно исплоьзуешь этот код в другом месте? Надо сделать универсальный класс, позволяющий бороться с CSRF в любом контроллере.
На данный момент у меня кука token используется в Edit- и ReadController'е, а прописана она в абстрактном ERController'е. Все еще надо создавать отлельный класс ради 2х строчек?
Cуп, посоны, думаю вот начать изучать похапеили сишарп продолжить или плюса - но это другая история - возможно подрабатывать фрилансом, может просто, вот думаю. Сколько времени нужно изучать, чтобы начать хоть что то зарабатывать фрилансом типа "запилить интернет-магазин", на что язык PHP похож, и сложен ли MySQL?
В трёх точках - внизу, в середине и вверху - возьми пипеткой цвет, проставь в настройках градиента.
И что там такого идеального? В упор не вижу, простой тёплый красный, видно, что градиент, по превьюшке.
> public function getData()
> {
> include_once 'database.php';
Бред же. Тебе ООП дан, чтобы таких конструкций не было. В класс все должно передаваться через DI, чтобы явно были зависимости видны.
>return null;
Это зачем?
>$base = Database::getConnection();
Тоже самое, юзай DI.
>$this->nick = $this->verifyNick($nick, $errors);
Verify функция ставит значение переменной класса? Тоже очень бредово. Verify функция должна возвращать true/false, а в вызывающем коде уже на основе полученного ответа принимается решение, кидать исключение или продолжать работу. У тебя это уже не verify функция, а нечто непонятное, код запутывается сразу.
>возьми пипеткой цвет
Какой цвет из 16 млн?
>И что там такого идеального?
То же что и у желтого яндекса. Такие цвета наверное подбирают сканированием коры головного мозга у группы людей. Определяют сколько дофамина вырабатывается.
>isExist($arrayValues){
Учи инглиш, или словарь хоть юзай, непонятно же сразу что за isExist. Правильно назвать было, судя по коду функции - valuesAreNotEmpty($arrayValues).
> if ($arrayValues[$i] == '') {
if (!isset($arrayValues[$i] || empty($arrayValues[$i]))
>То же что и у желтого яндекса
>То же что и у желтого яндекса
>То же что и у желтого яндекса
АртЁмий, что же вы делаете, АртЁмий!
Что же вы делаете с людьми.
А как же голубой у Гугла, фиолетовый у Яху и серый на Макабе?
> private function verifyMail($mail, &$errors)
>array_push($errors, 'Адрес eMail некорректен.');
> $mail = htmlspecialchars($mail);
Плохо, функция выполняет две совершенно разных вещи, причем из названия это непонятно. Разнеси на 2 функции - одна mailIsValid($mail), которая возвращает true/false, а $mail = htmlspecialchars($mail) перенеси, где она нужна, видимо в registerUser перед вставкой в БД.
Язык PHP похож на объектно-ориентированный язык, учить по-разному, в зависимости от способностей. Поделай уроки ОПа вводные, сразу понятно станет. MySql сложен, читай доки, делай упражнения на sql-ex.ru, помогает, и ясность появляется, но времени уходит много. Запилить интернет-магазин можно вообще без всего этого, достаточно какой-нибудь готовый фреймворк или cms для интернет-магазинов подключить, в принципе все новички так бабло и рубят, хуяк-хуяк и в продакшн. Но это будет плохой магазин для мелких конторок, с кучей дыр и ограниченным функционалом, ничего серьезного ты конечно так не сделаешь, и на работу тебя тоже с такими скиллами не возьмут. А чтобы взяли - делай задания ОПа, из тех, что посложнее, на ООП, про студентов.
>А как же голубой у Гугла, фиолетовый у Яху и серый на Макабе?
Гугл бутстраповат.
Яху всрат.
Макаба (дефолтный цвет фона сообщений на двоще) охуенна, но старперна.
Фуллстак это вообще-то называется. И их сейчас везде хотят. Чистым фронтендом сложнее устроиться, и зарплата меньше будет.
>2 секундочки, сделаю за 5 минут, от силы полчаса
>существует миллион <sameshitname>
А я уже давно говорю что людей, которые преувеличивают и преуменьшают, надо убивать нахуй.
>https://github.com/3DsYND/Dreams/blob/master/public_html/index.php#L2
Это за тебя может сделать Composer.
>https://github.com/3DsYND/Dreams/blob/master/public_html/index.php#L5
Это можно прописать в .htaccess или указать в локальном/глобальном php.ini
Вообще там очень много замечаний, тебе нужно почитать пасты ОПа, про паттерны для работы с БД (твоя модель студента очень раздутая), про неймспейсы, DI. Да и почему бы вместо этого проекта не сделать студентов? ОП, думаю, охотнее проверит.
>>780094
Тебе преподу показать что ли? Диаграммы не для того придуманы, чтобы генерировать их на основе готового кода. Алсо, неужели есть генераторы, которые показывают ещё и типы отношений между классами, не только генерализацию, а агрегацию, композицию, зависимость, арность (1:*, 1:1 и так далее)? Генератор, предложенный >>780099-
этим аноном, ограничивается лишь генерализацией, просто потому, что она явно указывается в коде строчками "Foo extends BaseFoo".
>>780326
Если у тебя есть список готовых URL с картинками, то хватит просто file_put_contents
>>780861
>А я уже давно говорю что людей, которые преувеличивают и преуменьшают, надо убивать нахуй.
"Я ненавижу 2 вещи: расизм и негров."
Напоминаю: для тебя тут отдельный пост написан >>779261
>>780584
Чем у тебя занимается класс User? Определи задачи, которые он решает и подумай, что тут не так.
Также, прочти этот пост >>779261
Также, прочти про PSR-4 и автозагрузку https://github.com/codedokode/pasta/blob/master/php/autoload.md
Лучше называть файлы по PSR-4
> public function getData()
> {
> include_once 'database.php';
>return null;
Это код из примера MVC, я не знаю, как он сюда попал. Удалю.
>Тоже самое, юзай DI.
Мне что-то в данном случае он не совсем нравится, ну раз ты говоришь - попробую.
>valuesAreNotEmpty
Примерно так изначально и было, но так как-то красивей. Что-нибудь придумаю. В оправдание скажу, что названия переменных длиной более 8 символов медленнее работают.
>if (!isset($arrayValues[$i] || empty($arrayValues[$i]))
>>>empty - Переменная считается пустой, если она не существует или её значение равно FALSE.
Нужно ли тогда isset, если empty и так проверяет на null?
>Разнеси на 2 функции
Плодить функции тоже не очень-то хорошо, но что-нибудь придумаю.
display_errors тут, имхо, удобней, или есть другие причины прописывать в .htacess или php.ini? Про Composer не совсем понял.
Я пока сложные запросы делать не собираюсь, поэтому хватит и двух методов select, insert. Зачем тогда делать для каждой сущности свой DataMapper, если можно обойтись и, грубо говоря, одним. Да по-моему, и сложные запросы не так уж и сложно в моём случае реализовать. А если не выйдет - тогда и перейду на каноничный паттерн. Переписывать всё сначала я уже привык, хоть это и плохо.
Спасибо.
>>780899
Работает с пользователем, чем.. Если ты про verify, то я несколько раз выносил его в отдельный класс, а потом снова объединял, остановился на этом. Или ты не про это?
> public function getData()
> {
> include_once 'database.php';
>return null;
Это код из примера MVC, я не знаю, как он сюда попал. Удалю.
>Тоже самое, юзай DI.
Мне что-то в данном случае он не совсем нравится, ну раз ты говоришь - попробую.
>valuesAreNotEmpty
Примерно так изначально и было, но так как-то красивей. Что-нибудь придумаю. В оправдание скажу, что названия переменных длиной более 8 символов медленнее работают.
>if (!isset($arrayValues[$i] || empty($arrayValues[$i]))
>>>empty - Переменная считается пустой, если она не существует или её значение равно FALSE.
Нужно ли тогда isset, если empty и так проверяет на null?
>Разнеси на 2 функции
Плодить функции тоже не очень-то хорошо, но что-нибудь придумаю.
display_errors тут, имхо, удобней, или есть другие причины прописывать в .htacess или php.ini? Про Composer не совсем понял.
Я пока сложные запросы делать не собираюсь, поэтому хватит и двух методов select, insert. Зачем тогда делать для каждой сущности свой DataMapper, если можно обойтись и, грубо говоря, одним. Да по-моему, и сложные запросы не так уж и сложно в моём случае реализовать. А если не выйдет - тогда и перейду на каноничный паттерн. Переписывать всё сначала я уже привык, хоть это и плохо.
Спасибо.
>>780899
Работает с пользователем, чем.. Если ты про verify, то я несколько раз выносил его в отдельный класс, а потом снова объединял, остановился на этом. Или ты не про это?
Подскажите годные видео курсы по пхп, чтобы как можно быстрее вкатиться в пыху и начать пилить что-то свое (ну а потом и джуном на работку).
Заранее спасибо анонам.
Правда?
Ну тогда держи:
foreach ($classmates as $name => $height) {
echo "Имя: {$name}, рост: {$height} см.\n";
if ($height>$anonHeight) / Тут надо добавить проверку, выше или ниже этот человек, чем анон,
и подсчитать число тех, кто выше /
{$number++;}
}
Лениво, да и внемоготу им лендосы рисовать. Надо жир как придумать с них срисовывать за поддержку интернетов и хайпа их хреноподелий.
Ты, скорее всего, не понимаешь что такое циклы. Попробуй загуглить "циклы в PHP" и реши задачу попроще - выведи 20 раз своё имя с помощью цикла.
>>781169
>Из опыта - делфи 2 года назад.
Cлишком размыто.
>видео курсы
>годные
Поделил на 0.
>>781444
Поэтому и живём в дерьме, ведь у каждого цель обмануть, да покрупнее. Если ты компетентен в какой-то узкой отрасли, то это не повод считать всех за дураков, люди не могут быть компетентны во всём.
> Они занимаются строкой, сваркой ворот
Вот они так же само обманут тебя с ценой за сварку ворот. Не они, так кто-то другой, ты же не разбираешь абсолютно во всём? Это круговая порука, избавиться от неё можно только начав с себя.
Лучше бы ты скиллы программирования качал.
>>>781444
ОП, ты - хороший человек. Проверь задачи, пожалуйста. Я ремесленникам не собираюсь палки в колеса вставлять, они как я, и я как они. Надо лишь высчитать оптимальный кэш за неудобства с моей стороны.
ОП проверит, когда будет время. Я так же как и ты жду проверки. Делай следующие задания.
Лол. Просто пиздец, как проиграл.
https://github.com/3DsYND/Dreams/blob/master/application/models/user.php
Переписал полностью модель User, сделал всё же DataMapper, сделал обработчик сообщений не знаю как называть посмотрите тоже, не сошёл ли я с ума.
Вроде бы и лучше стало, а вроде бы и хуже.
Почему? Если имеешь ввиду, что не должна в бд лезть, то в бд лезет отдельный Database\User.
Я сам в упор не понимаю, как запускать проекты с Github.
Вечно навертят хер пойми чего и где, разбираться еще в этом.
Хоть бы в readme.txt писали, как запускать.
А по сути тестового - явно кидануть тебя хотят:
>4 дня назад принято выполненное тестовое задание
>2 часа назад только попыталась запустить
Оптимизируй свой производственный цикл так, чтобы твои затраты были меньше денег за заказ. Например, покупай готовые шаблоны с версткой, используй заранее настроенную личную сборку твоей любимой CMS.
Где-то на хабре была статья - по моему, студия веб-канапе - они умудряются делать сайты как раз в том же ценовом сегменте и при этом оставаться в плюсе.
Ну либо переходи в другой сегмент, где проблем с бюджетом нет.
И я тебе сразу советую перестать называть клиентов "дебилами". По твоему, они дебилы, но почему тогда ты работаешь на них, а не они на тебя? Это очень неконструктивный подход.
>>781461
> Вот они так же само обманут тебя с ценой за сварку ворот
А, это везде. Начиная от служб по ремонту и заканчивая медициной. Там любят непрозрачное ценообразование, когда кажется что услуга будет стоить одну сумму, а по факту другую.
Недавно читал например как клиентам автосалона после подписания договора на поставку договор на продажу делали на 100-200 тысяч дороже. А если отказываешься от покупки - то все равно должен неустойку.
>>781444
Маркетинг в любом случае не относится к теме нашего треда и здесь обсуждаться не будет.
>>781569
README.md
Вот смотри как делает анон: https://github.com/foobar1643/filehosting пункт Install
Напиши ридми такого вида:
1) название проекта
2) (1 абзац) что это такое и для чего нужно
3) установка по шагам. Протестируй установку на чистом сервере или виртуалке. Опиши какие программы и библиотеки необходимо предустановить, какие версии ОС поддерживаются.
4) по шагам - как пользоваться программой
Насчет настройки веб-сервера - надо приложить либо конфиг виртуального хоста либо .htaccess (что может быть удобнее).
Ну и ты технический специалист, неужели ты объяснить внятно не можешь что ты сделал? Тогда ты вряд ли сможешь работать в команде.
>>781609
Ты прочел мою пасту про принцип единой ответственности? Каждый класс занимается своим делом. Ты пишешь в ответ на "чем занимается твой класс"
> Работает с пользователем, чем..
Но это не ответ. В магазине почти все сотрудники работают с товарами, но каждый отвечает за свою часть: кладовщик, грузчик, консультант, кассир.
Так и у тебя. У тебя в классе собраны функции:
- хранение информации об одном пользователе
- проверка авторизации (тут мы обращаем внимание что функция возвращает результат в случае успеха в каком-то странном ненормальном формате. Логично при отсутсиви ошибок возвращать пустой массив)
- регистрация
- экранирование html-символов (что это делает в модели?)
- валидация
Это слишком много для одного класса. Ты все свалил в кучу.
Если приглядеться, проблемы с твоим подходом видны сразу. Для того, чтобы делать регистрацию, нам достаточно иметь один объект, им можно зарегистрировать сколько угодно пользователей. Нет никакого смысла делать 2 таких объекта. Но в твоем случае если пользователей несколько, у тебя будет несколько моделей User.
Также, ты используешь странные формы представления данных. Вот у тебя есть задача: закодировать сообщение об ошибке, содержащее имя поля и вид ошибки. Как это можно сделать? Ну очевидно, одним из 2 способов:
- объектом
- массивом
Массив быстрее писать, так как не надо описывать класс, но объект лучше документирован и понятнее в использовании, а также на него можно добавлять методы.
Ты почему-то вместо этого используешь как-то странно закодированную строку. Никто кроме тебя про это не знает.
Также, у тебя есть объект, представляющий пользователя (User). Но в функции ты почем-то предпочитаешь передавать поля по отдельности. Это не масштабируемый подход, когда у пользователя станет больше свойств, работать с ними по отдельности будет неудобно.
А ты кстати решал задачи про Вектор и Кошки-Мышки? Они помогают чуть лучше разобраться с ООП.
Вот еще пример неправильного представления данных:
> $ans = $database->getPassByNick($this);
> if ($ans[0] != '#DB-Succes') {
Что это за ерунда? Для ответа да/нет есть true/false. Вот как угадать, что значит эта строка и какие еще варианты есть? И почему ты возвращаешь ее еще и завернутой в массив.
То есть можно вернуть false или true
А ты выбрал вариант вернуть ['#Db-Error'] или ['#DB-Succes'] (с одной буквой s вместо двух). Какая выгода от такого усложнения?
Если надо вернуть больше 2 вариантов, есть константы. Например
return Model::STATUS_NOT_REGISTERED;
return Model::STATUS_USER_BLOCKED;
Константы защищают от опечаток, видно какие варианты констант есть, их названия более информативны.
В общем, класс надо переделывать. Тут в каждой второй строке нарушаются принципы написания надежного, понятного, самодокументируемого кода.
Оптимизируй свой производственный цикл так, чтобы твои затраты были меньше денег за заказ. Например, покупай готовые шаблоны с версткой, используй заранее настроенную личную сборку твоей любимой CMS.
Где-то на хабре была статья - по моему, студия веб-канапе - они умудряются делать сайты как раз в том же ценовом сегменте и при этом оставаться в плюсе.
Ну либо переходи в другой сегмент, где проблем с бюджетом нет.
И я тебе сразу советую перестать называть клиентов "дебилами". По твоему, они дебилы, но почему тогда ты работаешь на них, а не они на тебя? Это очень неконструктивный подход.
>>781461
> Вот они так же само обманут тебя с ценой за сварку ворот
А, это везде. Начиная от служб по ремонту и заканчивая медициной. Там любят непрозрачное ценообразование, когда кажется что услуга будет стоить одну сумму, а по факту другую.
Недавно читал например как клиентам автосалона после подписания договора на поставку договор на продажу делали на 100-200 тысяч дороже. А если отказываешься от покупки - то все равно должен неустойку.
>>781444
Маркетинг в любом случае не относится к теме нашего треда и здесь обсуждаться не будет.
>>781569
README.md
Вот смотри как делает анон: https://github.com/foobar1643/filehosting пункт Install
Напиши ридми такого вида:
1) название проекта
2) (1 абзац) что это такое и для чего нужно
3) установка по шагам. Протестируй установку на чистом сервере или виртуалке. Опиши какие программы и библиотеки необходимо предустановить, какие версии ОС поддерживаются.
4) по шагам - как пользоваться программой
Насчет настройки веб-сервера - надо приложить либо конфиг виртуального хоста либо .htaccess (что может быть удобнее).
Ну и ты технический специалист, неужели ты объяснить внятно не можешь что ты сделал? Тогда ты вряд ли сможешь работать в команде.
>>781609
Ты прочел мою пасту про принцип единой ответственности? Каждый класс занимается своим делом. Ты пишешь в ответ на "чем занимается твой класс"
> Работает с пользователем, чем..
Но это не ответ. В магазине почти все сотрудники работают с товарами, но каждый отвечает за свою часть: кладовщик, грузчик, консультант, кассир.
Так и у тебя. У тебя в классе собраны функции:
- хранение информации об одном пользователе
- проверка авторизации (тут мы обращаем внимание что функция возвращает результат в случае успеха в каком-то странном ненормальном формате. Логично при отсутсиви ошибок возвращать пустой массив)
- регистрация
- экранирование html-символов (что это делает в модели?)
- валидация
Это слишком много для одного класса. Ты все свалил в кучу.
Если приглядеться, проблемы с твоим подходом видны сразу. Для того, чтобы делать регистрацию, нам достаточно иметь один объект, им можно зарегистрировать сколько угодно пользователей. Нет никакого смысла делать 2 таких объекта. Но в твоем случае если пользователей несколько, у тебя будет несколько моделей User.
Также, ты используешь странные формы представления данных. Вот у тебя есть задача: закодировать сообщение об ошибке, содержащее имя поля и вид ошибки. Как это можно сделать? Ну очевидно, одним из 2 способов:
- объектом
- массивом
Массив быстрее писать, так как не надо описывать класс, но объект лучше документирован и понятнее в использовании, а также на него можно добавлять методы.
Ты почему-то вместо этого используешь как-то странно закодированную строку. Никто кроме тебя про это не знает.
Также, у тебя есть объект, представляющий пользователя (User). Но в функции ты почем-то предпочитаешь передавать поля по отдельности. Это не масштабируемый подход, когда у пользователя станет больше свойств, работать с ними по отдельности будет неудобно.
А ты кстати решал задачи про Вектор и Кошки-Мышки? Они помогают чуть лучше разобраться с ООП.
Вот еще пример неправильного представления данных:
> $ans = $database->getPassByNick($this);
> if ($ans[0] != '#DB-Succes') {
Что это за ерунда? Для ответа да/нет есть true/false. Вот как угадать, что значит эта строка и какие еще варианты есть? И почему ты возвращаешь ее еще и завернутой в массив.
То есть можно вернуть false или true
А ты выбрал вариант вернуть ['#Db-Error'] или ['#DB-Succes'] (с одной буквой s вместо двух). Какая выгода от такого усложнения?
Если надо вернуть больше 2 вариантов, есть константы. Например
return Model::STATUS_NOT_REGISTERED;
return Model::STATUS_USER_BLOCKED;
Константы защищают от опечаток, видно какие варианты констант есть, их названия более информативны.
В общем, класс надо переделывать. Тут в каждой второй строке нарушаются принципы написания надежного, понятного, самодокументируемого кода.
1) Напиши проверяльщик ссылок. Программе через командную строку передаются несколько ссылок, например:
node checker.js 'http://example.com/1.png' 'http://example.com/2.png'
Программа должна параллельно проверить каждую ссылку на валидность путем отправки HTTP-запроса типа HEAD и вывести (по мере поступления ответов) статус проверки и MIME тип ответа в таком формате:
200 text/html http://example.com/2.png
404 - http://example.com/1.png
Failed to resolve name: invalid.domain http://invalid.domain/1.png
Резолвинг DNS тоже надо бы делать асинхронно и параллельно.
Дополнительные пункты:
- добавить ограничение числа параллельных запросов на 1 домен верхнего уровня . Например если у нас есть ссылки http://1.example.com/ и http://2.example.com/ то они должны обрабатываться по очереди, так как там один домен (example.com)
- сделать кеш DNS. Если у нас несколько ссылок с одним и тем же доменом, незачем отправлять несколько запросов. Достаточно отправить только 1 DNS запрос
Постарайся грамотно разбить программу на независимые модули.
Для тестирования я советую использовать либо сервис вроде http://httpbin.org/ либо какой-нибудь локальный скрипт где ты можешь выставлять задержку ответа и его тип.
2) Напиши сервер мемкеша. Мемкеш - это сервис, который позволяет хранить данные в памяти, сохранять их туда и доставать. Реализуй протокол мемкеша (описание есть в сети). Все команды реализовывать не надо - ограничься простейшими вроде GET, SET, STAT и еще несколькими.
Предусмотри разумные ограничения: на объем потребляемой памяти, число ключей, длину ключа.
Проведи нагрузочное тестирование. Сколько запросов выдерживает твой сервис? С помощью утилит вроде iotop, iftop, htop, и других попытайся понять, во что упирается производительность и есть ли какие-то способы преодолеть ограничение. Если ты можешь организовать профайлинг или хотя бы примитивный сбор статистики (какие операции сколько времени заняли) - вообще хорошо будет.
Пиши, если есть вопросы.
1) Напиши проверяльщик ссылок. Программе через командную строку передаются несколько ссылок, например:
node checker.js 'http://example.com/1.png' 'http://example.com/2.png'
Программа должна параллельно проверить каждую ссылку на валидность путем отправки HTTP-запроса типа HEAD и вывести (по мере поступления ответов) статус проверки и MIME тип ответа в таком формате:
200 text/html http://example.com/2.png
404 - http://example.com/1.png
Failed to resolve name: invalid.domain http://invalid.domain/1.png
Резолвинг DNS тоже надо бы делать асинхронно и параллельно.
Дополнительные пункты:
- добавить ограничение числа параллельных запросов на 1 домен верхнего уровня . Например если у нас есть ссылки http://1.example.com/ и http://2.example.com/ то они должны обрабатываться по очереди, так как там один домен (example.com)
- сделать кеш DNS. Если у нас несколько ссылок с одним и тем же доменом, незачем отправлять несколько запросов. Достаточно отправить только 1 DNS запрос
Постарайся грамотно разбить программу на независимые модули.
Для тестирования я советую использовать либо сервис вроде http://httpbin.org/ либо какой-нибудь локальный скрипт где ты можешь выставлять задержку ответа и его тип.
2) Напиши сервер мемкеша. Мемкеш - это сервис, который позволяет хранить данные в памяти, сохранять их туда и доставать. Реализуй протокол мемкеша (описание есть в сети). Все команды реализовывать не надо - ограничься простейшими вроде GET, SET, STAT и еще несколькими.
Предусмотри разумные ограничения: на объем потребляемой памяти, число ключей, длину ключа.
Проведи нагрузочное тестирование. Сколько запросов выдерживает твой сервис? С помощью утилит вроде iotop, iftop, htop, и других попытайся понять, во что упирается производительность и есть ли какие-то способы преодолеть ограничение. Если ты можешь организовать профайлинг или хотя бы примитивный сбор статистики (какие операции сколько времени заняли) - вообще хорошо будет.
Пиши, если есть вопросы.
Вряд ли тебе нужно множественное наследование. Трейты можно использовать, но в других случаях (добавление простых часто используемых функций в разные классы), хотя часто можно обойтись просто добавлением объекта в приватное поле.
>>781016
> Нужно ли тогда isset, если empty и так проверяет на null?
Не нужно
> Зачем тогда делать для каждой сущности свой DataMapper, если можно обойтись и, грубо говоря, одним
Потому что так удобнее. Неудобно когда несколько классов склеены в один.
>>781016
Композер может реализовать автозагрузку если ты следуешь PSR-4, в моем уроке по неймспейсам это было. Также он позволяет подключать сторонние библиотеки.
>>780855
Потому что "чистым фронтендщиком" обычно называют себя те кто с горем пополам научился писать простейшие конструкции на jquery
>>780833
Экранирование должно делаться при выводе, а не в модели.
>>780824
Не придирайся к знанию английского. У нас не филологический тред тут все же. Анон я думаю сам это понимает и в свободное время подучивает язык, читает hacker news и reddit, смотрит аниме с английскими субтитрами.
>>780823
Цвета подбираются путем проб и ошибок. У Лебедева на сайте студии есть раздел "процесс" где видно какие варианты перепробовали, прежде чем найти финальный.
>>780813
Я наверно слепой, с ходу не очевидно, градиент все же довольно нерезкий. Ну и экран у меня не из лучших.
>>780627
> А редирект на htmlspecialchars($url) не сработает разве?
index.php?a=1&b=2
index.php?a=1& amp ; b = 2
Ну-ка, сравни-ка как распарсит php первый и вторй УРЛ (можешь проверить функцией http://php.net/manual/ru/function.parse-str.php )
> Так ничего ж не происходит. Если юзер в url шнягу пишет
Дело не в юзере. Есть правило сборки query string из частей и я не вижу причин по которым стоит отказываться от экранирования тут. Проще всегда делать праивльно чем гадать вызовет это ошибку или нет.
Урок https://github.com/codedokode/pasta/blob/master/network/urls.md
> Все еще надо создавать отлельный класс ради 2х строчек?
Если это отдельная задача то почему бы и нет. Ну если совсем не хочется то можно сделать просто 2 функции, но мне кажется отдельный класс все же удобнее.
И там не 2 строчки. Я вижу как минимум:
- установка/генерация токена
- проверка токена
> а прописана она в абстрактном ERController'е
Я не смотрел код но подозреваю что наследование тут применять не стоило бы.
Вряд ли тебе нужно множественное наследование. Трейты можно использовать, но в других случаях (добавление простых часто используемых функций в разные классы), хотя часто можно обойтись просто добавлением объекта в приватное поле.
>>781016
> Нужно ли тогда isset, если empty и так проверяет на null?
Не нужно
> Зачем тогда делать для каждой сущности свой DataMapper, если можно обойтись и, грубо говоря, одним
Потому что так удобнее. Неудобно когда несколько классов склеены в один.
>>781016
Композер может реализовать автозагрузку если ты следуешь PSR-4, в моем уроке по неймспейсам это было. Также он позволяет подключать сторонние библиотеки.
>>780855
Потому что "чистым фронтендщиком" обычно называют себя те кто с горем пополам научился писать простейшие конструкции на jquery
>>780833
Экранирование должно делаться при выводе, а не в модели.
>>780824
Не придирайся к знанию английского. У нас не филологический тред тут все же. Анон я думаю сам это понимает и в свободное время подучивает язык, читает hacker news и reddit, смотрит аниме с английскими субтитрами.
>>780823
Цвета подбираются путем проб и ошибок. У Лебедева на сайте студии есть раздел "процесс" где видно какие варианты перепробовали, прежде чем найти финальный.
>>780813
Я наверно слепой, с ходу не очевидно, градиент все же довольно нерезкий. Ну и экран у меня не из лучших.
>>780627
> А редирект на htmlspecialchars($url) не сработает разве?
index.php?a=1&b=2
index.php?a=1& amp ; b = 2
Ну-ка, сравни-ка как распарсит php первый и вторй УРЛ (можешь проверить функцией http://php.net/manual/ru/function.parse-str.php )
> Так ничего ж не происходит. Если юзер в url шнягу пишет
Дело не в юзере. Есть правило сборки query string из частей и я не вижу причин по которым стоит отказываться от экранирования тут. Проще всегда делать праивльно чем гадать вызовет это ошибку или нет.
Урок https://github.com/codedokode/pasta/blob/master/network/urls.md
> Все еще надо создавать отлельный класс ради 2х строчек?
Если это отдельная задача то почему бы и нет. Ну если совсем не хочется то можно сделать просто 2 функции, но мне кажется отдельный класс все же удобнее.
И там не 2 строчки. Я вижу как минимум:
- установка/генерация токена
- проверка токена
> а прописана она в абстрактном ERController'е
Я не смотрел код но подозреваю что наследование тут применять не стоило бы.
В пхп область видимости переменных ограничивается только в функции. Тут функций нет значит все переменные глобальные. Причина в чем-то другом, стоит например натыкать var_dump и посмотреть значения переменных, и какие условия выполняются/не выполняются.
Далее, тут скорее всего есть уязвимость. Заголовки письма собираются из пользовательских необработанных данных:
$subjectMessage = $values['name'] . " writes about: " . $values['subject'];
Вполне возможно что, вставив например перевод строки, пользователь сможет вставить дополнительный заголовок в исходник письма. Стоит как-то ограничить допустимые значения в этих полях. Может конечно это уже исправили, раньше такая уязвимость была.
Регулярки кривые так как без флага u, не поддерживают нелатинские символы.
После успешной отправки письма надо делать редирект иначе обновление страницы пошлет еще письма, почитай урок про работу с формами.
В шаблоне стоит использовать версию иф с двоеточием и вынести его в отдельный файл.
>>780546
В пхп нет такого атрибута. Ты ошибся тредом.
>>780540
Норма, не нужен
>>780326
Тебе нужна библиотека-http клиент например guzzle. Не забудь проверять все ошибки.
>>780214
>> Также, тут можно было обойтись функцией max.
> Не понял зачем и как
Для краткости и наглядности. Так:
номер = максимаьное из(переданный номер, 1)
>>779694
Хорошей скорее всего нету. По идее это отдельные темы:
- статьи про настройку апача (в идеале хорошо бы прочесть оф документацию на англ.)
- уроки по пользованию линуксом и баш, система прав, структура файловой системы
Тренироваться можно на дебиане без графического интерфейса, установленном в виртуалбокс. Хватит 400-500 Мб памяти и 2 Гб на диске. Инструкция https://gist.github.com/codedokode/420c8c12a1edae25f0ec
В пхп область видимости переменных ограничивается только в функции. Тут функций нет значит все переменные глобальные. Причина в чем-то другом, стоит например натыкать var_dump и посмотреть значения переменных, и какие условия выполняются/не выполняются.
Далее, тут скорее всего есть уязвимость. Заголовки письма собираются из пользовательских необработанных данных:
$subjectMessage = $values['name'] . " writes about: " . $values['subject'];
Вполне возможно что, вставив например перевод строки, пользователь сможет вставить дополнительный заголовок в исходник письма. Стоит как-то ограничить допустимые значения в этих полях. Может конечно это уже исправили, раньше такая уязвимость была.
Регулярки кривые так как без флага u, не поддерживают нелатинские символы.
После успешной отправки письма надо делать редирект иначе обновление страницы пошлет еще письма, почитай урок про работу с формами.
В шаблоне стоит использовать версию иф с двоеточием и вынести его в отдельный файл.
>>780546
В пхп нет такого атрибута. Ты ошибся тредом.
>>780540
Норма, не нужен
>>780326
Тебе нужна библиотека-http клиент например guzzle. Не забудь проверять все ошибки.
>>780214
>> Также, тут можно было обойтись функцией max.
> Не понял зачем и как
Для краткости и наглядности. Так:
номер = максимаьное из(переданный номер, 1)
>>779694
Хорошей скорее всего нету. По идее это отдельные темы:
- статьи про настройку апача (в идеале хорошо бы прочесть оф документацию на англ.)
- уроки по пользованию линуксом и баш, система прав, структура файловой системы
Тренироваться можно на дебиане без графического интерфейса, установленном в виртуалбокс. Хватит 400-500 Мб памяти и 2 Гб на диске. Инструкция https://gist.github.com/codedokode/420c8c12a1edae25f0ec
Это было актуально на нищехостингах где нельзя поменять корень сайта и для тех, кто не осиливает вынесение кода за пределы веб-папки. Это ведь нелогично. Подумай сам- в веб-папку мы кладем то, что раздает людям сервер. Мы хотим раздавать исходники нашего проекта? Нет. Тогда зачем класть их в публичную папку?
Это же касается папок типа .git - их не должно быть в публичном доступе (кстати гугление легко находит сайты которые не соблюдают это правило - и мы можем выкачать их исходники через гит).
>>779338
Гугл может поменять порядок тегов
>>779330
Это плохая, неинтересная, неблагодарная и плохо оплачиваемая работа. держитесь от сеошников подальше.
>И я тебе сразу советую перестать называть клиентов "дебилами".
Дико извиняюсь, писала крайне бухая и злая свинособака.
>У тебя в классе собраны функции. Это слишком много для одного класса.
>Для того, чтобы делать регистрацию, нам достаточно иметь один объект, им можно зарегистрировать сколько угодно пользователей. Нет никакого смысла делать 2 таких объекта. Но в твоем случае если пользователей несколько, у тебя будет несколько моделей User.
Не, ну я не знаю, как это в РНР, но насколько я знаю, в обычных языках ООП подразумевает, что один класс описывает одну сущность (объект), а не одну функцию; и для каждого пользователя таки нужно создавать отдельный объект класса пользователя.
Экранирование - да, лажа, исправлю. Валидацию, имхо, стоит вынести в отдельный класс только если её можно будет использовать и для других классов.
>Но в функции ты почем-то предпочитаешь передавать поля по отдельности.
Имеешь ввиду передавать поля ассоциативным массивом или что?
>Вот у тебя есть задача: закодировать сообщение об ошибке, содержащее имя поля и вид ошибки.
Я думал массивом сделать, но для одного поля может быть несколько ошибок, и строкой
array('nick-smallLength', 'nick-badMask')
ошибку вывести показалось легче, чем
array('nick' = > array('smallLength', 'nick-badMask'))
Так что-ли лучше, или ты другое имел ввиду? Попробую сделать класс.
>Что это за ерунда? Для ответа да/нет есть true/false.
БД может возвращать '#DB-Error', '#DB-Success и '#DB-Empty', но тут да, путаница, разберусь.
>Константы
Ок.
Спасибо.
>gettext нужен только для получения перевода строки. В нем нет нормальной возможности склонять или менять слова.
Там есть функция ngettext http://php.net/manual/en/function.ngettext.php который может склонять слова с помощью переводов.
А потом я посмотрел исходники дополнения i18n к твигу, и оказалось что тег {% plural %} использует как раз эту функцию. Плохо что они этого в документации не написали.
https://github.com/twigphp/Twig-extensions/blob/master/lib/Twig/Extensions/Node/Trans.php#L41
Так вот, может лучше будет взять эту функцию, чем использовать MessageFormatter? У меня с помощью POedit получилось перевести склонения правильно.
>Вряд ли тебе нужно множественное наследование
Расставляю костыли в очень запутанный и плохо написанный проект, хочется обойтись малой кровью.
Вот нашел для себя выход в трейтах, так то я больше не встречал их на практике. Стало интересно насколько они вообще уместны.
Спасибо, анон! Постараюсь не забыть.
Нет, она очень слабая и не позволит например склонять 2 слова в одной фразе. Так же не позволяет использовать другие условия, например, пол.
>>782110
Массив + цикл.
ну и в чем профит по времени выполнения? Кстати, все в unix time, может можно как-то хитро обрезать цифры и манипулировать числами? Я в этом смысле спрашивал.
>>Это было актуально на нищехостингах где нельзя поменять корень сайта и для тех, кто не осиливает вынесение кода за пределы веб-папки. Это ведь нелогично. Подумай сам- в веб-папку мы кладем то, что раздает людям сервер. Мы хотим раздавать исходники нашего проекта? Нет. Тогда зачем класть их в публичную папку?
Это же касается папок типа .git - их не должно быть в публичном доступе (кстати гугление легко находит сайты которые не соблюдают это правило - и мы можем выкачать их исходники через гит).
А не проще вкаорячить в htaccess Deny from All в неугодные диры, вместо того, чтобы разбрасывать их по файловойм системе?
Привет Ананасы. Пишу парсер для автоматизации. Затупняк произошел на этапе авторизации
Вот сайтик
http://www.vezetvsem.ru/listing
Не могу парсер научить авторизоваться. Вроде все верно делаю, а он не принимает пароль.
Сайт пользует сессии и куки, поэтому простые формочки никак не подходят.
Если нужны детали, спрашивай, скажу все что нужно.
Конкретно вопрос, какого лешего он не хочет меня авторизовать, при этом логин/пароль верные.
Если надо, могу и логин пароль на новый созданный акк дать.
>>
<?
function login($url,$login,$pass){
$ch = curl_init();
if(strtolower((substr($url,0,5))=='https')) { // если соединяемся с https
//моя вставка
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
//моя вставка
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
}
curl_setopt($ch, CURLOPT_URL, $url);
// откуда пришли на эту страницу
curl_setopt($ch, CURLOPT_REFERER, $url);
// cURL будет выводить подробные сообщения о всех производимых действиях
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,"username=".$login."&password=".$pass);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36");
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
echo "username=".$login."&password=".$pass;
//сохранять полученные COOKIE в файл
curl_setopt($ch, CURLOPT_COOKIEJAR, $_SERVER['DOCUMENT_ROOT'].'/cookie.txt');
$result=curl_exec($ch);
// Убеждаемся что произошло перенаправление после авторизации
if(strpos($result,"Location: home.php")===false) die('Login incorrect');
curl_close($ch);
return $result;
}
// чтение страницы после авторизации
function Read($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
// откуда пришли на эту страницу
curl_setopt($ch, CURLOPT_REFERER, $url);
//запрещаем делать запрос с помощью POST и соответственно разрешаем с помощью GET
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
//отсылаем серверу COOKIE полученные от него при авторизации
curl_setopt($ch, CURLOPT_COOKIEFILE, $_SERVER['DOCUMENT_ROOT'].'/cookie.txt');
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (Windows; U; Windows NT 5.0; En; rv:1.8.0.2) Gecko/20070306 Firefox/1.0.0.4");
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
$urlAut = "https://auth.vezetvsem.ru/auth/login";
login($urlAut,"XXX","XXX");
$page = Read("http://www.vezetvsem.ru/listing");
echo $page;
?>
Привет Ананасы. Пишу парсер для автоматизации. Затупняк произошел на этапе авторизации
Вот сайтик
http://www.vezetvsem.ru/listing
Не могу парсер научить авторизоваться. Вроде все верно делаю, а он не принимает пароль.
Сайт пользует сессии и куки, поэтому простые формочки никак не подходят.
Если нужны детали, спрашивай, скажу все что нужно.
Конкретно вопрос, какого лешего он не хочет меня авторизовать, при этом логин/пароль верные.
Если надо, могу и логин пароль на новый созданный акк дать.
>>
<?
function login($url,$login,$pass){
$ch = curl_init();
if(strtolower((substr($url,0,5))=='https')) { // если соединяемся с https
//моя вставка
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
//моя вставка
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
}
curl_setopt($ch, CURLOPT_URL, $url);
// откуда пришли на эту страницу
curl_setopt($ch, CURLOPT_REFERER, $url);
// cURL будет выводить подробные сообщения о всех производимых действиях
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,"username=".$login."&password=".$pass);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36");
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
echo "username=".$login."&password=".$pass;
//сохранять полученные COOKIE в файл
curl_setopt($ch, CURLOPT_COOKIEJAR, $_SERVER['DOCUMENT_ROOT'].'/cookie.txt');
$result=curl_exec($ch);
// Убеждаемся что произошло перенаправление после авторизации
if(strpos($result,"Location: home.php")===false) die('Login incorrect');
curl_close($ch);
return $result;
}
// чтение страницы после авторизации
function Read($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
// откуда пришли на эту страницу
curl_setopt($ch, CURLOPT_REFERER, $url);
//запрещаем делать запрос с помощью POST и соответственно разрешаем с помощью GET
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
//отсылаем серверу COOKIE полученные от него при авторизации
curl_setopt($ch, CURLOPT_COOKIEFILE, $_SERVER['DOCUMENT_ROOT'].'/cookie.txt');
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (Windows; U; Windows NT 5.0; En; rv:1.8.0.2) Gecko/20070306 Firefox/1.0.0.4");
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
$urlAut = "https://auth.vezetvsem.ru/auth/login";
login($urlAut,"XXX","XXX");
$page = Read("http://www.vezetvsem.ru/listing");
echo $page;
?>
Привет Ананасы. Пишу парсер для автоматизации. Затупняк произошел на этапе авторизации
Вот сайтик
http://www.vezetvsem.ru/listing
Не могу парсер научить авторизоваться. Вроде все верно делаю, а он не принимает пароль.
Сайт пользует сессии и куки, поэтому простые формочки никак не подходят.
Если нужны детали, спрашивай, скажу все что нужно.
Конкретно вопрос, какого лешего он не хочет меня авторизовать, при этом логин/пароль верные.
Если надо, могу и логин пароль на новый созданный акк дать.
http://pastebin.com/Vcv7TYcG
Научился сокращать ссылки, просто игнорьте верхний
Если написать классы для меня очень просто (как будто обычные функции с передачей аргумента и ретерном), как и написать вьюхи-шаблончики с разбором через циклы входящих переменных и расстановкой их по полочкам, то вот в контроллерах я ничего не понимаю.
Почему контроллеры должны быть объектами? Мне аж плохо от того какой я тупой.
Контроллеры объекты, чтобы их можно было заменять из одной точки. Был у тебя контроллер PageAController, а потом ты решил быстро поменять на другую страницу, в точке входа заменил на PageBController, и если у контроллеров был общий интерфейс, то все по-прежнему работает, а страница уже другая. Это можно использовать в роутере например.
Открой любой фреймворк типа zend, сразу понятно станет, там гора контроллеров для каждого пути в url, и нужный по цепочке вызывается. Можешь свой роутер-диспатчер подобным образом написать. Ну и кроме того, когда много контроллеров, то куда проще в коде ориентироваться, чем когда гора страниц свалена в один контроллер с кучей методов.
https://winscp.net/eng/docs/faq_su
Речь об этой фиче идет.
>In some cases (with Unix/Linux server) you may be able to use sudo command straight after login to change a user, before file transfer session starts.
>The SFTP and SCP protocols allow for this, but the actual method is platform dependent.
Как ее в curl включить?
Сделай 2 страницы с 2мя контроллерами и разным контентом в них, а потом напиши роутер, и сделай, чтобы по вызову /url1 вызывалась первая страница, а по /url2 вторая. Вот решишь ты их поменять местами, чтобы наоборот вызывались, тут к тебе и придет озарение, зачем контроллеры в виде объектов с общим интерфейсом нужны.
Этот тип по моему появился раньше чем сами объекты.
>>782606
Платиновый вопрос: а ты решил кошки-мышки и вектор?
> Почему контроллеры должны быть объектами?
А почему нет? Объект который отвечает за обработку запроса:
$newsController = new NewsController;
$newsController->latestNewsAction();
Или так, в стиле Симфони:
$newsController = new NewsController;
$response = $newsController->latestNewsAction($request);
Или так, в стиле микрофрейморков:
$newsController = new NewsController;
$response = new Response;
$newsController->latestNewsAction($request, $response);
>$newsController = new NewsController;
>$newsController->latestNewsAction();
Так а зачем ему объект то? Что бы просто было к чему обращаться? Я не могу понять как тут объекты отличаются от массивов блин в целом. Что значит состояние и пр?
Для меня создание объекта в коде это лишние телодвижения, и получается, что проще и логичнее было бы использовать абстрактные классы:
NewsController::latestNewsAction();
Что-то я совсем в общем запутался, надо с 0 всё начинать.
Почитай про статические методы https://github.com/codedokode/pasta/blob/master/arch/di.md
В твоем случае например нельзя куда-то передать объект контроллера, если там будет более сложный код. Нельзя менять его настройки, например:
$newsController = new NewsController;
if ($debug) {
$newsController->setDebugMode(true);
}
....
$newsController->latestNewsAction();
>- сделать кеш DNS. Если у нас несколько ссылок с одним и тем же доменом, незачем отправлять несколько запросов. Достаточно отправить только 1 DNS запрос
Как бы операционка это делает сама, дополнительно в коде такого делать не стоит. Разве что в учебных целях...
Как вариант, тебе можно попробовать вообще забить на curl и из пхп-скрипта просто позапускать нужные консольные команды
http://php.net/manual/ru/function.shell-exec.php
>>782863
Не всегда. зависит от версии ОС и конфигурации. И используемого DNS клиента. С чего ты решил что в твоей версии ОС это так? С чего ты решил что твоя библиотека DNS запросов это поддерживает?
Плюс, у нас речь об асинхронном кеше. То есть первый поток отправил запрос, второй и третий ждут ответа на него. Кеш в этот момент еще пуст и никак не поможет.
>Sublime vs PHPStorm
> не стану ли макакой
Я вот не помню названия многих методов и постоянно забываю структуру switch (дело не в ide я копипастю её из доков).
Но не думаю что это делает меня макакой, ведь я знаю что и где использовать, а конкретные названия не обязательно же помнить.
Но я-то не каждый, Ватсон, поймите: человеческий мозг — это пустой чердак, куда можно набить всё, что угодно. Дурак так и делает: тащит туда нужное и ненужное. И наконец наступает момент, когда самую необходимую вещь туда уже не запихнёшь. Или она запрятана так далеко, что её не достанешь. Я делаю по-другому. В моём чердаке только необходимые мне инструменты. Их много, но они в идеальном порядке и всегда под рукой. А лишнего хлама мне не нужно.
В шторме есть много годноты, типа менеджера баз данных, подключения к серверу и синхронизация, гит, крутая навигация.
Накрутить все это на Атом я нормально не смог, не знаю, как с этим у саблайма.
Но для себя пока альтернатив шторму не вижу.
> переименовывание файлов при загрузке с безопасным расширением вроде .txt, так что файл не будет выполняться как php-код. Пожалуй один из самых надежных вариантов.
Как это понимать? В txt переименовывать любые файлы или только php формата? В первом случае у нас будет папка целиком состоящая из txt файлов, для удобства администратора нужно добавлять префикс какого этого формата файл? И каким образом менять формат на ранний из $_FILES["userfile"]["type"]? Притом там четко не написан формат, что-то в духе "text/plain", "png/jpeg", т.е. для класса модели файла нужно еще добавить свойство с точным форматом "png", "mp3" etc?
Алсо еще вопросики.
Как в PHP происходит скачка файлов? По прямому адресу example.com/file.txt?
Нужно ли хранить файлы в бд или только в папке? В последнем случае выходит так, что в бд хранится только информация о файле и комментарии?
Заранее извиняюсь за возможную расплывчатость первого вопроса.
НЕ ОП
>переименовывание файлов при загрузке с безопасным расширением вроде .txt
Думаю, ты можешь просто дописывать к названиям любых файлов ".txt", а при возврате файла удалять. Должно работать.
>Как в PHP происходит скачка файлов? По прямому адресу example.com/file.txt?
Можно так, но есть и другие способы.
https://habrahabr.ru/post/151795/
>Нужно ли хранить файлы в бд или только в папке?
Думаю задача ОПа не подразумевает хранение файла в базе, просто файлы в папке.
Но ты можешь прикрутить и такой функционал.
>В последнем случае выходит так, что в бд хранится только информация о файле и комментарии?
Да
так что, вариантов нет?
Не могу проверить, тк договор не заключил и смски слать не могу.
Вот API
http://www.devinotele.com/resheniya/dokumentaciya-po-api/https_rest_without_sessionid/Otpravka_SMS-soobshcheny1/
вот код
https://ideone.com/Y1uObt
Никуда не ставь, делай цикл через while($deposit!=0) и в теле добавь проверку того, что остаток на счете больше следующего платежа.
Но насколько реально зарабатывать на PHP? Или огромная конкуренция не даст шанса новичкам? Что выгоднее, фриланс или офис? Как вообще у вас с заработками?
>вкатиться в программирование
>зарабатывать
===
>научиться читать на английском
>зарабатывать переводами
>Вместо include __DIR__ . '/../../templates/registration.phtml'; лучше было бы сделать метод $this->render('templates/registration.phtml')
А будет лучше если метод рендера вынести в класс Viewer? По-моему, лучше иметь его в части представления чем в контроллере.
>>780899
>Анон который https://github.com/someApprentice/Students
>
>Напоминаю: для тебя тут отдельный пост написан >>779261
Да, простите что сразу не отписался. У меня просто не возникло вопросов по этому посту.
http://ideone.com/0hmsEY // Кошки-мышки
class MyStructure {
public $age;
public $canName;
public $readableName;
}
Могу ли я сортировать массив объектов по значению свойств? Например по $MyStructure->age или по другому свойству?
сам спросил. сам ответил = usort + callback
у меня плохо с пространственными абстракциями, но раком-боком додумал.
Это 75 а нужно 77.
Критическое мышление. Ок?
Еще вопрос от меня же >>783027. В файлообменнике надо бороться с CSRF уязвимостью, если нету регистрации?
В форме загрузки файла не нужно, но если захочешь сделать к примеру удаление файла, то в таком случае нужно будет защитить форму удаления.
Применим ли этот шаблон к оценочной функции для классов Кошка/Мышка/Собака в задаче Кошки-Мышки? Или целесообразнее создать один общий метод в суперклассе Животное, а затем в дочерних классах Кошка/Мышка/Собака расширить этот метод, добавив специфический алгоритм для каждого класса?
нет
Борисова ищи на nmn-club (курсы специалиста). Основы разжевываются хорошо, лично я к третьему курсу бросил и сел за студентов.
Что, простите? Какие две функции, о чём вы несёте?
Подобные обьекты называются DTO - data transfer object. И да - их часто используют, просто как удобный "контейнер" для переноса данных внутри приложения.
Но, например, если ты хочешь офоримть юзера как DTO - то это плохая идея. Обьекты, которые отражают вещи из реального мира должны иметь поведение.
Как DTO обычно оформляют всякую фигню, типа обьектов, содержащих внутри чистую инфориацию, без поведения. Например строки из таблички статистики, или рассчитываемую каким нибудь классом-калькулятором статистику
Конкуренция только среди новичков и есть. Если у тебя нормальные скиллы, ее не ощущается почти, везде берут, всем нужен. Но ты попробуй эти скиллы набери, почти все время на это уходит, универ проще закончить, чем хорошим программистом стать.
Да, это называется Value Objects. Они не должны быть изменяемыми, иначе у тебя будут проблемы:
http://www.c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
А в каких сферах нужны прокаченные скиллы для php, ведь 80% вакансий это клонниннг веб магазинов средней руки?
В таких фреймворках как Slim, например.
В документации написано
Слим получает HTTP запрос, выполняет коллбек функцию и возвращает HTTP ответ.
В чем удобство этого? Какие то конкретные плюсы?
Почему нужно делать $request->getQueryParams()['name'] вместо $_GET['name'] ?
И в чем удобство каждый раз очевидно изменять ( $response->getBody->write() )
и возвращать Response в конце?
И в чем вообще смысл Slim фреймворка тогда? Не только же чтобы роут и контейнер типа в комплекте получить (Tам Pimple container и nikis/fast-route) ?
Нужно установить XDebug, но на оф сайте бинарки для win для PHP 5.4 и выше. А в денвере PHP 5.3. Поэтому нужно либо обновить PHP в денвере, либо попробовать установить Vagrant+PuPHPet от сюда https://habrahabr.ru/post/212009/.
Что будет проще?
Настроить среду своими руками не предлагать, мне кажется это слишком долго, шансы на успех сомнительны, а выгода не очевидна.
>Настроить среду своими руками не предлагать, мне кажется это слишком долго, шансы на успех сомнительны, а выгода не очевидна.
Что там сомнительного? Ты же не собираешься это в интернет выводить, для локальной сети все будет работать уже из коробки даже на линуксе (если брать апач + php5).
Сперва настроить апач
потом mysql
потом php
а потом обнаружить ошибку, заниматься с ней страстным сексом сутки напролет, так и не поняв, какие из пол сотни установленных программ конфликтуют.
>Настроить среду своими руками не предлагать, мне кажется это слишком долго, шансы на успех сомнительны, а выгода не очевидна.
Чё-т в голосяку с тебя.
Сам таким был, пока не установил за 15 минут Apache, PHP7.1.0, MySQL и PHPStorm.
А ведь вплоть до ООП по учебнику ОПа всё делал исключительно на Ideone...
Сборки не нужны абсолютно.
Но это ты сам должен дойти, я тебя не переубежу.
Надо уметь определять источник проблемы. Для начала например просто проверить что все установленные программы работают и запущены.
Вот например где-то выше был анон, у которого не работал как нужно Апач, но в лог ошибок он ни разу не заглянул.
Иногда гугление помогает, но иногда выдает много лишнего.
Потому надо знать как проверить что программа установлена и работает. Как посмотреть текущие настройки пхп, путь к нему и тд.
>>784985
Лучше снести денвер и поставить все руками. В Оп посте есть не очень информационные, но вдохновляющие и ободряющие пасты по теме.
>>784985
Вагрант много лишнего же тянет вроде руби. Не лучше найти/сделать образ для виртуалбокса?
>>784973
Ну давай погуглим вместе. Вот что я нашел по словам PSR-7:
- https://5minphp.ru/episode2/
А теперь касательно вопроса.
> а зачем нужны эти PSR 7 классы ServerRequestInterface и ServerResponse?
Открываем PSR-7:
> RequestInterface provides the general representation of an HTTP request message. However, server-side requests need additional treatment, due to the nature of the server-side environment.
> ServerRequestInterface extends RequestInterface to provide an abstraction around these various superglobals.
RequestInterface это HTTP-запрос.
ServerRequestInterface это HTTP-запрос, который содержит дополнительную информацию, которую добавляет например PHP или Апач когда разбирает пришедший запрос. Какую? Давай глянем в код:
> https://github.com/php-fig/http-message/blob/master/src/ServerRequestInterface.php
> public function getServerParams();
> public function getCookieParams();
> public function getQueryParams();
> public function getAttribute($name, $default = null);
Как видишь тут всякие параметры которые соответствуют переменные $_GET, $_SERVER и тд.
> В чем удобство этого? Какие то конкретные плюсы?
у нас есть объект представляющий запрос. В отличие от $_GET/POST:
- мы контролируем где он будет доступен а где нет
- мы можем создать объект и заполнить его произвольными данными
- мы можем создать несколько объектов и передавать их в разные функции
- он не изменяется сам по себе и фиксирует состояние переменных в момент создания
Это упрощает тестирование, разделение кода на части, может где-то повышает удобство использования. Если у тебя есть функция, которая что-то делает с запросом, ты можешь написать
function doSpmething(Request $request)
А с глобальными переменными это неудобно - не будешь же ты передавать 5 переменных по отдельности.
Ну и это упрощает написание того же middleware в Слиме. Оно может что-то сделать с запросом и с ответом на него.
> $request->getQueryParams()['name'] вместо $_GET['name'] ?
как-то некрасиво выглядит.
> И в чем удобство каждый раз очевидно изменять ( $response->getBody->write() )
> и возвращать Response в конце?
В том что потом с респонсом можно что-то сделать. Например проверить соответствие ожиданию или как-то преобразовать.
Ну например у тебя есть функция которая авторизует пользователя (выставляя куки). Как ее тестировать автоматизированно если она делает setcookie? да никак. Потому что ты не можешь получить куки которые она выставила и проверить их (без хаков с перехватом вызова setcookie).
А вот с Response ты можешь взять и посмотреть что она там поставила.
> И в чем вообще смысл Slim фреймворка тогда? Не только же чтобы роут и контейнер типа в комплекте получить (Tам Pimple container и nikis/fast-route) ?
Что ты получаешь, описано в документации. Роутер, контейнер, реквест, респонс, обработчик ошибок, может еще что-то, все отлаженное и протестированное.
Надо уметь определять источник проблемы. Для начала например просто проверить что все установленные программы работают и запущены.
Вот например где-то выше был анон, у которого не работал как нужно Апач, но в лог ошибок он ни разу не заглянул.
Иногда гугление помогает, но иногда выдает много лишнего.
Потому надо знать как проверить что программа установлена и работает. Как посмотреть текущие настройки пхп, путь к нему и тд.
>>784985
Лучше снести денвер и поставить все руками. В Оп посте есть не очень информационные, но вдохновляющие и ободряющие пасты по теме.
>>784985
Вагрант много лишнего же тянет вроде руби. Не лучше найти/сделать образ для виртуалбокса?
>>784973
Ну давай погуглим вместе. Вот что я нашел по словам PSR-7:
- https://5minphp.ru/episode2/
А теперь касательно вопроса.
> а зачем нужны эти PSR 7 классы ServerRequestInterface и ServerResponse?
Открываем PSR-7:
> RequestInterface provides the general representation of an HTTP request message. However, server-side requests need additional treatment, due to the nature of the server-side environment.
> ServerRequestInterface extends RequestInterface to provide an abstraction around these various superglobals.
RequestInterface это HTTP-запрос.
ServerRequestInterface это HTTP-запрос, который содержит дополнительную информацию, которую добавляет например PHP или Апач когда разбирает пришедший запрос. Какую? Давай глянем в код:
> https://github.com/php-fig/http-message/blob/master/src/ServerRequestInterface.php
> public function getServerParams();
> public function getCookieParams();
> public function getQueryParams();
> public function getAttribute($name, $default = null);
Как видишь тут всякие параметры которые соответствуют переменные $_GET, $_SERVER и тд.
> В чем удобство этого? Какие то конкретные плюсы?
у нас есть объект представляющий запрос. В отличие от $_GET/POST:
- мы контролируем где он будет доступен а где нет
- мы можем создать объект и заполнить его произвольными данными
- мы можем создать несколько объектов и передавать их в разные функции
- он не изменяется сам по себе и фиксирует состояние переменных в момент создания
Это упрощает тестирование, разделение кода на части, может где-то повышает удобство использования. Если у тебя есть функция, которая что-то делает с запросом, ты можешь написать
function doSpmething(Request $request)
А с глобальными переменными это неудобно - не будешь же ты передавать 5 переменных по отдельности.
Ну и это упрощает написание того же middleware в Слиме. Оно может что-то сделать с запросом и с ответом на него.
> $request->getQueryParams()['name'] вместо $_GET['name'] ?
как-то некрасиво выглядит.
> И в чем удобство каждый раз очевидно изменять ( $response->getBody->write() )
> и возвращать Response в конце?
В том что потом с респонсом можно что-то сделать. Например проверить соответствие ожиданию или как-то преобразовать.
Ну например у тебя есть функция которая авторизует пользователя (выставляя куки). Как ее тестировать автоматизированно если она делает setcookie? да никак. Потому что ты не можешь получить куки которые она выставила и проверить их (без хаков с перехватом вызова setcookie).
А вот с Response ты можешь взять и посмотреть что она там поставила.
> И в чем вообще смысл Slim фреймворка тогда? Не только же чтобы роут и контейнер типа в комплекте получить (Tам Pimple container и nikis/fast-route) ?
Что ты получаешь, описано в документации. Роутер, контейнер, реквест, респонс, обработчик ошибок, может еще что-то, все отлаженное и протестированное.
Ну и как ты без этих объектов опишешь функцию-контроллер? С ними все логично: контроллер получает на вход request и возвращает response. Ну или получает на вход request и response и пишет в response данные.
>>784839
Модели это не value objects. Они могут меняться, для этого и сделаны.
>>784477
"впаять" вроде ничего и не требовалось.
> PHP Notice: Undefined variable: uppertext in /home/C4Oe7Z/prog.php on line 18
А вот эту ошибочку надо бы исправить. Обращаешься к еще не существующей переменной.
> mb_substr($value, -mb_strlen($value) + 1);
надо писать mb_substr($value, 1);
> foreach ($sentence as $value){
foreach ($sentences as $sentence)
> ([.,:;!?])([а-яёa-z])
Работает только с маленькими буквами, а если там большая?
Тут появляется лишняя точка: http://ideone.com/1W1G35
Ну и как ты без этих объектов опишешь функцию-контроллер? С ними все логично: контроллер получает на вход request и возвращает response. Ну или получает на вход request и response и пишет в response данные.
>>784839
Модели это не value objects. Они могут меняться, для этого и сделаны.
>>784477
"впаять" вроде ничего и не требовалось.
> PHP Notice: Undefined variable: uppertext in /home/C4Oe7Z/prog.php on line 18
А вот эту ошибочку надо бы исправить. Обращаешься к еще не существующей переменной.
> mb_substr($value, -mb_strlen($value) + 1);
надо писать mb_substr($value, 1);
> foreach ($sentence as $value){
foreach ($sentences as $sentence)
> ([.,:;!?])([а-яёa-z])
Работает только с маленькими буквами, а если там большая?
Тут появляется лишняя точка: http://ideone.com/1W1G35
Стратегия обычно используется когда у нас есть выбор нескольких способов поведения для объекта. И мы выносим эти поведения в отдельные заменяемые объекты. Она применима если:
- у кошки есть несколько Поведений, выбор которых делается например при создании
- если животные представлены одним классом, в который загружаются разные Стратегии Поведения
Если у тебя разные классы то наверно паттерн не очень подходит.
>>784410
Совершенно верно.
>>784330
Он старый и плохо спроектированный. Лучше Слим и файлообменник, но нет информации на русском.
>>784258
Нормально.
>>784251
Верно
Есть. Со сбитой версткой правда.
http://rgho.st/87YwtSqKB
http://www.mediafire.com/download/oz0ywl4jv6urji3/pr-thread-77.zip
> А будет лучше если метод рендера вынести в класс Viewer? По-моему, лучше иметь его в части представления чем в контроллере.
Можно, так наверно даже правильнее, но там по сути render это функция из 5 строк в простейшем случае (распаковать переменные + приинклудить файл) так что стоит ли ради нее отдельный класс городить? А так, можно.
>>783469
Надежнее while ($deposit > 0)
>>783443
Поставь echo и выводи как меняются переменные на каждом шаге чтобы найти почему он не доходит до нуля, а проскакивает.
>>783307
Обычно там есть тестовый режим в АПИ или что-то такое. В крайнем случае можно вместо отправки запроса просто например выодить его параметры в консоль.
>>783140
Тут не нужны паттерны. Просто надо подавать на вход функции ее предудущий результат.
Также, тебе возможно было бы интересно изучить генераторы - это такие функции которые могут возвращать значения много раз и сохраняют свое состояние.
>>782110
Попробуй отсортировать диапазоны и искать методом деления пополам. Хотя если у тебя их немного то проще обычным циклом.
> А будет лучше если метод рендера вынести в класс Viewer? По-моему, лучше иметь его в части представления чем в контроллере.
Можно, так наверно даже правильнее, но там по сути render это функция из 5 строк в простейшем случае (распаковать переменные + приинклудить файл) так что стоит ли ради нее отдельный класс городить? А так, можно.
>>783469
Надежнее while ($deposit > 0)
>>783443
Поставь echo и выводи как меняются переменные на каждом шаге чтобы найти почему он не доходит до нуля, а проскакивает.
>>783307
Обычно там есть тестовый режим в АПИ или что-то такое. В крайнем случае можно вместо отправки запроса просто например выодить его параметры в консоль.
>>783140
Тут не нужны паттерны. Просто надо подавать на вход функции ее предудущий результат.
Также, тебе возможно было бы интересно изучить генераторы - это такие функции которые могут возвращать значения много раз и сохраняют свое состояние.
>>782110
Попробуй отсортировать диапазоны и искать методом деления пополам. Хотя если у тебя их немного то проще обычным циклом.
>>Но, например, если ты хочешь офоримть юзера как DTO - то это плохая идея. Обьекты, которые отражают вещи из реального мира должны иметь поведение.
Хоть ты тресни, не пойму, какой у юзера можеь быть поведение. Ну логин, ну пароль, ну "роль" (админ\не админ).
МОжешь привести простой пример?
>>Ну логин, ну пароль, ну "роль" (админ\не админ).
Ну то есть вот это перечилсенное - это совйства, но не поведение.
О, тесты, это интересно.
Давай начнем с вопроса, зачем мы пишем тесты? Не потому что ОП так сказал. Есть разные причины:
- ты написал функцию но не уверен правильно ли она работает. Хочется проверить. Действительно ли функция авторизации авторизует пользователя?
- ты написал код но боишься что ты или кто-то еще в будщем его случайно сломают. Хочется защитить его тестами чтобы можно было спокойно делать сложные рефакторинги не бояться что не заметишь ошибку.
- некоторые используют тесты как документацию с примерами использования функций. В этом случае тесты надо писать максимально наглядно
Вообще, когда у тебя код сильно покрыт тестами, появляется некоторое (приятное) чувство уверенности. Ты понимаешь, что если ошибешься, то увидишь проблему на этапе запуска тестов.
Или когда ты присоединяешься к новому проекту, прогон тестов помогает понять, все ли ты верно у себя настроил.
Исходя из этого, как мы хотим писать тесты? Мы хотим тестировать код как его пользователь. "Пользователь" функции или класса - это код, который ее вызывает или использует. Мы должны тестировать публичный интерфейс и не опираться на знание о внутреннем устройстве и принципе работы функции.
Если этот принцип не соблюдать, то получится что мы тестируем не саму функцию ("авторизовать пользователя"), а ее конкретную реализацию ("выставить куку с названием X содежащую N символов"). Видишь разницу между первым и вторым? Второй тест получается более хрупким и с большей вероятностью сломается при изменениях в коде, когда мы меняем что-то во внутреннем устройстве функции. Это значит, надо будет переписывать тест, а это лишние затраты.
Это же относится к функциональным тестам (эмуляции поведения человека). Мы не хотим писать тест вида "после ввода логина и пароля выставляется кука с именем X". мы хотим писать тест "после ввода логина и пароля пользователь видит личный кабинет и свое имя в углу".
Вообще, тестирование, особенно пока ты начинающий, это отдельная задача, требующая творческого подхода. Не раз ты будешь задавать себе вопрос "а как это вообще можно протестировать?". Ты должен учитывать такие вещи:
- тесты должны быть 100% повторяемымыми. Избегай использования генератора случайных чисел или приводи его в заранее известное состояние
- тесты не должны быть хрупкими, то есть не должны давать случайных ошибок. Например тест испльзующий сеть, может давать ложные срабатывания из-за сетевых неполадок, тест использующий БД может падать если в ней нет нужных данных, или наоборот есть лишние. Потому для тестов надо делать максимально контролируемое окружение
- тест не должен завязыватсья на внутреннюю структуру кода. Например ты должен избегать обращений к приватным или защищенным полям, ты должен тестировать лишь конкретную функцию, так как при рефактоинге тест придется переделывать.
- отдельная проблема - привязка к строкам. Сегодня ты проверяешь наличие кнопки "зарегистрироваться", завтра ее переделывают на "присоединиться" и тест падает. Избегай привязки к строкам и сообщениям.
Также, читай статьи на хабре в блоге яндекса про тестирование - там много интересного.
Сообщение успешно отправлено
Теперь посмотрим на твои тесты.
> https://github.com/foobar1643/filehosting/blob/master/tests/ConfigTest.php#L17
> testGetValue()
Тест полагается на знание значения по умолчанию установленного для поля db.host. Получается ты тестируешь требование "конфиг должен содержать по умолчанию значение X для поля Y", а не функцию получения знаечния. Как бы это сделать лучше? Я вижу такие варианты:
- задать значение поля и проверить что оно читается
- прочитать специально подготовленный конфиг-файл и проверить что значения из него читаются
Я бы выбрал второе. Оно близко к реальному сценарию использования класса Config. Правда это будет тест не только функции get но и чтения файла, ну да ладно. Файл можно либо положить в отдельную папку (напр. test/assets) либо создавать во временной папке на время теста. Либо попробовать использовать какую-нибудь фичу пхп вроде php://memory ( http://php.net/manual/ru/wrappers.php.php ) если она конечно заработает (а нет, там надо передавать файловый дескриптор).
> public function testFailureGetValue()
Этот сценарий написан хорошо, только я бы сделал имя не example, а более говорящее nonExistingKey.
> https://github.com/foobar1643/filehosting/blob/master/app/Translator.php
> public function translatePlural($text, $number)
Эта функция мне не нравится. Это какая-то урезанная версия $messageFormatter->format принимающая только один аргумент. Не очень понимаю, зачем она тут.
https://github.com/foobar1643/filehosting/blob/master/tests/Entity/CommentEntityTest.php#L14
Тут как-то непонятно:
> $children = self::$rootComment->getChildren();
> self::$deepComment = $children[6]->getChildren()[7]
Что-то странно, мы в rootComment вроде всего 3 комментария добавили, откуда взялась цифра 6?
Кстати для функций работы с деревом можно было побольше тестов сделать. Как тебе например такое:
- протестировать addChildNode() для коммента, который уже является чьим-то ребенком
> public function getDepth()
У таких функций всегда должен стоять комментарий описывающий чему равна глубина корневого комментария.
https://github.com/foobar1643/filehosting/blob/master/app/Entity/File.php#L29
> $this->file = $uploaded->file;
> $this->error = $uploaded->getError();
В классе нет поля error и file. Да и по моему логичнее просто запретить создавать File из битых файлов. Насчет type - его лучше не брать от клиента а определять из getId3.
> public function getFormattedSize()
Вообще конечно это надо было в хелпер статическим методом выносить. Может ведь и не для файла пригодиться. Алсо килобайт это 1024 байта.
> public function getDiskName()
Мне кажется функционал замены имени файла удобнее было бы вынести в клас отвечающий за загрузку файлов. А не складывать все в модель. ну например это лучше тем, что если мы поменяем алгоритм переименования, старые файлы продолжат работать (а с твоим подходом они получат новые имена).
https://github.com/foobar1643/filehosting/blob/master/tests/Entity/FileEntityTest.php#L21
> public function testGetExtension()
Тут стоило бы тестировать экзотиечские случае - имя файла, начинающееся с точки, файл без расширения, файл с несколькими расширениями, файл с расширением не из букв.
> public function testGetFolder()
Вот тут по моему мы опять начинаем тестировать внутреннюю реализацию. Я бы просто проверял что эта функция возвращает что-то похожее на имя папки.
> testGetDiskName()
> public function testGetDownloadLink()
Тут тоже идет тестирование реализации. Стоит поменять формат ссылок и все ломается. Я бы сделал так:
- проверял что возвращается что-то отдаленно напоминающее ссылку
- что для разных файлов она разная
- может, проверял бы что файл со специсимволами корректно работает. Но что-то пока не очень представляю какими именно.
Валидность ссылки можно проверить наверно только в функиональном тесте (загрузка файла через браузер и проверка возможности скачать его обратно). Так как в анализе УРЛ участвует роутер, контроллер и много другого кода.
Конечно если у тебя ТЗ вида "ссылка должна иметь вид XXX" то такой тест ему соответствует. Но мне больше нравится тест вида "можно закачать файл и скачать его по ссылке".
> class FileEntityTest extends TestCase
> protected static $file;
Почему static? Один обший файл на любое число тестовых объектов? Тут же нет причин ставить static.
О, тесты, это интересно.
Давай начнем с вопроса, зачем мы пишем тесты? Не потому что ОП так сказал. Есть разные причины:
- ты написал функцию но не уверен правильно ли она работает. Хочется проверить. Действительно ли функция авторизации авторизует пользователя?
- ты написал код но боишься что ты или кто-то еще в будщем его случайно сломают. Хочется защитить его тестами чтобы можно было спокойно делать сложные рефакторинги не бояться что не заметишь ошибку.
- некоторые используют тесты как документацию с примерами использования функций. В этом случае тесты надо писать максимально наглядно
Вообще, когда у тебя код сильно покрыт тестами, появляется некоторое (приятное) чувство уверенности. Ты понимаешь, что если ошибешься, то увидишь проблему на этапе запуска тестов.
Или когда ты присоединяешься к новому проекту, прогон тестов помогает понять, все ли ты верно у себя настроил.
Исходя из этого, как мы хотим писать тесты? Мы хотим тестировать код как его пользователь. "Пользователь" функции или класса - это код, который ее вызывает или использует. Мы должны тестировать публичный интерфейс и не опираться на знание о внутреннем устройстве и принципе работы функции.
Если этот принцип не соблюдать, то получится что мы тестируем не саму функцию ("авторизовать пользователя"), а ее конкретную реализацию ("выставить куку с названием X содежащую N символов"). Видишь разницу между первым и вторым? Второй тест получается более хрупким и с большей вероятностью сломается при изменениях в коде, когда мы меняем что-то во внутреннем устройстве функции. Это значит, надо будет переписывать тест, а это лишние затраты.
Это же относится к функциональным тестам (эмуляции поведения человека). Мы не хотим писать тест вида "после ввода логина и пароля выставляется кука с именем X". мы хотим писать тест "после ввода логина и пароля пользователь видит личный кабинет и свое имя в углу".
Вообще, тестирование, особенно пока ты начинающий, это отдельная задача, требующая творческого подхода. Не раз ты будешь задавать себе вопрос "а как это вообще можно протестировать?". Ты должен учитывать такие вещи:
- тесты должны быть 100% повторяемымыми. Избегай использования генератора случайных чисел или приводи его в заранее известное состояние
- тесты не должны быть хрупкими, то есть не должны давать случайных ошибок. Например тест испльзующий сеть, может давать ложные срабатывания из-за сетевых неполадок, тест использующий БД может падать если в ней нет нужных данных, или наоборот есть лишние. Потому для тестов надо делать максимально контролируемое окружение
- тест не должен завязыватсья на внутреннюю структуру кода. Например ты должен избегать обращений к приватным или защищенным полям, ты должен тестировать лишь конкретную функцию, так как при рефактоинге тест придется переделывать.
- отдельная проблема - привязка к строкам. Сегодня ты проверяешь наличие кнопки "зарегистрироваться", завтра ее переделывают на "присоединиться" и тест падает. Избегай привязки к строкам и сообщениям.
Также, читай статьи на хабре в блоге яндекса про тестирование - там много интересного.
Сообщение успешно отправлено
Теперь посмотрим на твои тесты.
> https://github.com/foobar1643/filehosting/blob/master/tests/ConfigTest.php#L17
> testGetValue()
Тест полагается на знание значения по умолчанию установленного для поля db.host. Получается ты тестируешь требование "конфиг должен содержать по умолчанию значение X для поля Y", а не функцию получения знаечния. Как бы это сделать лучше? Я вижу такие варианты:
- задать значение поля и проверить что оно читается
- прочитать специально подготовленный конфиг-файл и проверить что значения из него читаются
Я бы выбрал второе. Оно близко к реальному сценарию использования класса Config. Правда это будет тест не только функции get но и чтения файла, ну да ладно. Файл можно либо положить в отдельную папку (напр. test/assets) либо создавать во временной папке на время теста. Либо попробовать использовать какую-нибудь фичу пхп вроде php://memory ( http://php.net/manual/ru/wrappers.php.php ) если она конечно заработает (а нет, там надо передавать файловый дескриптор).
> public function testFailureGetValue()
Этот сценарий написан хорошо, только я бы сделал имя не example, а более говорящее nonExistingKey.
> https://github.com/foobar1643/filehosting/blob/master/app/Translator.php
> public function translatePlural($text, $number)
Эта функция мне не нравится. Это какая-то урезанная версия $messageFormatter->format принимающая только один аргумент. Не очень понимаю, зачем она тут.
https://github.com/foobar1643/filehosting/blob/master/tests/Entity/CommentEntityTest.php#L14
Тут как-то непонятно:
> $children = self::$rootComment->getChildren();
> self::$deepComment = $children[6]->getChildren()[7]
Что-то странно, мы в rootComment вроде всего 3 комментария добавили, откуда взялась цифра 6?
Кстати для функций работы с деревом можно было побольше тестов сделать. Как тебе например такое:
- протестировать addChildNode() для коммента, который уже является чьим-то ребенком
> public function getDepth()
У таких функций всегда должен стоять комментарий описывающий чему равна глубина корневого комментария.
https://github.com/foobar1643/filehosting/blob/master/app/Entity/File.php#L29
> $this->file = $uploaded->file;
> $this->error = $uploaded->getError();
В классе нет поля error и file. Да и по моему логичнее просто запретить создавать File из битых файлов. Насчет type - его лучше не брать от клиента а определять из getId3.
> public function getFormattedSize()
Вообще конечно это надо было в хелпер статическим методом выносить. Может ведь и не для файла пригодиться. Алсо килобайт это 1024 байта.
> public function getDiskName()
Мне кажется функционал замены имени файла удобнее было бы вынести в клас отвечающий за загрузку файлов. А не складывать все в модель. ну например это лучше тем, что если мы поменяем алгоритм переименования, старые файлы продолжат работать (а с твоим подходом они получат новые имена).
https://github.com/foobar1643/filehosting/blob/master/tests/Entity/FileEntityTest.php#L21
> public function testGetExtension()
Тут стоило бы тестировать экзотиечские случае - имя файла, начинающееся с точки, файл без расширения, файл с несколькими расширениями, файл с расширением не из букв.
> public function testGetFolder()
Вот тут по моему мы опять начинаем тестировать внутреннюю реализацию. Я бы просто проверял что эта функция возвращает что-то похожее на имя папки.
> testGetDiskName()
> public function testGetDownloadLink()
Тут тоже идет тестирование реализации. Стоит поменять формат ссылок и все ломается. Я бы сделал так:
- проверял что возвращается что-то отдаленно напоминающее ссылку
- что для разных файлов она разная
- может, проверял бы что файл со специсимволами корректно работает. Но что-то пока не очень представляю какими именно.
Валидность ссылки можно проверить наверно только в функиональном тесте (загрузка файла через браузер и проверка возможности скачать его обратно). Так как в анализе УРЛ участвует роутер, контроллер и много другого кода.
Конечно если у тебя ТЗ вида "ссылка должна иметь вид XXX" то такой тест ему соответствует. Но мне больше нравится тест вида "можно закачать файл и скачать его по ссылке".
> class FileEntityTest extends TestCase
> protected static $file;
Почему static? Один обший файл на любое число тестовых объектов? Тут же нет причин ставить static.
О, вот тут как никогда много тестирования внутренней реализации. Чего стоит вот это место:
> $this->assertRegExp('/^[\d\w]{45}$/', CookieUtils::getResponse($response, 'auth')->getValue());
Это не тест авторизации. Это тест того что хелпер ставит куку длиной 45 символов из определенного набора.
Как сделать тест тут? Давай начнем с требований к классу. Что мы хотим? Чтобы он залогинивал пользователей, разлогинивал и чтобы мог проверять залогитненность. Исходя из этого и пишем сценарий.
Я бы предложил такой тест:
- авторизуемся, запомнинаем токен (возвращаенный функцией) и созданные ей куки.
- можно проверить что они не пусты (защита от совсем глупых ошибок), можно даже проверить что токен имеет не меньше N символов (то есть что токен надежен). Можно проверить что для разных пользователей токены получаются разные.
- создаем другой хелпер
- проверяем что изначально он показывает отсутствие авторизации
- проверяем что при подаче ему сохраненных кук он признает авторизацию и токен совпадает с запомненным
Далее еще можно потестировать функцию разлогинивания - например проверкой что после нее с куками не залогиниться или что после этого хелпер отказывается возвращать токен. Правда у тебя ее почему-то нет.
> public function testCanManageFile()
> {
> $file = $this->createMock(File::class);
> $file->method('getAuthToken')->willReturn('1234567890');
Вот здесь конечно тоже многовато знания внутренних принципов работы. А что если авторизатору еще и id понадобится например?
https://github.com/foobar1643/filehosting/blob/master/tests/Helper/CommentAdditionTest.php
Вот тут по сути идет тестирование реализации. Ну например вот этот вот код
> $mapperMock->method('getComment')->willReturn($commentMock);
даже аргументы не проверяет. Тест как итог выглядит странно:
> $expected->setId(1)->setParentId(1);
Понятно что это легко сломать если добавить проверку в Comment что parentId <> id.
То, что связано с базой данных, проще тестировать в интеграционном тесте с этой самой базой. То есть создаем пустую базу, вызываем addComment, потом загружаем его и проверяем что это тот же комментарий и что у него есть нужные поля.
Есть наверно и альтернативы: написать мок для маппера, который будет вместо базы складывать и искать комментарии в массиве. Я думаю, даже есть какие-то библиотеки для реализации таких вещей, но это потенциально очень сложная вещь, так легко дойти до эмуляции SQL запросов.
https://github.com/foobar1643/filehosting/blob/master/app/Helper/CommentHelper.php#L16
> if($comment->getParentId() != NULL) {
> $parentComment = $this->commentMapper->getComment($comment->getParentId());
Ты используешь id в пути. Какая у тебя длина элемента пути? 3 символа? Это значит нельзя создать более 1000 комментариев на всем сайте. Надо использовать не id, а порядковый номер комментария среди братьев.
И кстати это позволит делать вставку одним инсертом.
Составные операции надо делать транзакцией.
В реализации комментария есть один сомнительный момент.У тебя там есть getChild() но всегда ли комментарии организованы в дерево? Что если мы выбираем один комментарий из базы? Что если мы хотим загрузить только часть дерева? В более сложном приложении стоило бы вынести древовидную структуру наружу из класса Comment либо использовать ленивую загрузку которая есть в доктрине.
> public function makeTrees($comments)
Эту функцию кстати можно тестировать.
> public function appendToPath($old, $new)
Вот должно ли это быть публичным? Неьзя ли сделать путь деталью внутренней реализации и не выдавать наружу функции работы с ним? Вообще, почему у тебя там все методы публичные?
> public function getMargin($path)
Это не часть модели а часть вью.
https://github.com/foobar1643/filehosting/blob/master/tests/Helper/PaginationHelperTest.php#L30
Тут я бы не тестировал вид ссылки, а тестировал что она похожа на ссылку и разная для разных страниц
https://github.com/foobar1643/filehosting/blob/master/tests/Helper/TokenGeneratorTest.php
Вот по этому поводу я выше писал другому анону: http://pastebin.ru/t5Z34Uyu
> Factory::requestFactory()
Я бы назвал createRequest().
https://github.com/foobar1643/filehosting/blob/master/tests/Middleware/CsrfMiddlewareTest.php
Я бы тут тоже поменьше опирался на реализацию и тестировал бы только публичный интерфейс класса. То есть получил бы токен и попробовал бы проверить запрос с ним.
https://github.com/foobar1643/filehosting/blob/master/tests/Middleware/LocaleMiddlewareTest.php
Здесь чтобы что-то сказать надо разбираться в коде класса.
https://github.com/foobar1643/filehosting/blob/master/tests/Validation/ValidationTest.php#L37
> $this->validator = new Validation($container);
Ой, что это? serviceLocator вместо dependency injection. Заметь что здесь твой тест опирается на предположение что валидатору нужны ровно 3 зависимости.
Ну и я думаю, было бы неплохо еще сделать интеграционные (с базой) и функциональные (браузерные) тесты. Если ты не используешь яваскрипт, то можно использовать например эмулятор HTML браузера http://symfony.com/doc/current/book/testing.html#functional-tests , если нужен яваскрипт то придется использовать протокол Селениума, а в качестве эмулятора браузера подойдет phantomjs (придется повозиться с настройкой и работать будет конечно медленнее).
Браузерные тесты это отдельная сверхзадача, например как искать элементы? По классу? По id? По тексту? По имени поля формы? Какой из способов наиболее устойчив к изменениям верстки?
По локализации.
Я уже писал, что встроенная в Твиг локализация мне не нравится. Ну, твиг расширяемый, ты можешь при большом желании даже теги свои добавлять если не боишься. Мне например не нравится длинный синтаксис ({% trans %}) и отсутствие поддержки подстановок разных параметров как в formatMessage.
Кстати в локализации есть немало подвохов. Например, в некоторых языках используется написание справа налево и надо добавлять соответствующие css стили. хуже, бывает что часть слов пишется справа налево, а иностранные слова - слева направо.
https://github.com/foobar1643/filehosting/blob/master/templates/comments.twig#L4
> <p class="pull-right"><small>{{ comment.getDatePosted }}</small></p>
В разных странах разные форматы записи дат. Твоя архитектура это не учитывает. Обычно используют объект-форматировщик дат вроде того что есть в Intl.
> <span class="comment-text">{{ comment.getCommentText }}</span>
Не сохраняются переводы строк
> <form method="post" id="fallback-reply-form" action="/{{ lang }}/file/{{ comment.fileId }}/">
Возможно лучше было бы иметь класс отвечающий за генерацию УРЛ а не раскидывать их по всему коду. Он бы мог отвечать и за подстановку языка.
> <h4>{% trans %}Search results for {% endtrans %} <i>«{{ query }}»</i></h4>
Вот еще одно сомнительное место. Ты предполагаешь что запрос будет идти в конце предложения, но в азиатских языках порядок слов другой и запрос может идти в начале или середине: "NNN запрос отправленный на результаты": https://translate.google.com/#en/ja/search results for query NNN (бинг выдал более точный на мой взгляд перевод где запрос идет в начале, но в нем ссылку нельзя скопировать).
Тут же ты можешь и заметить еще проблему подстановки HTML кода в перевод. Кто-то оставляет HTML код, кто-то пишет свои языки разметки или использует что-нибудь вроде markdown.
Еще один подвох - перевод текста в JS скриптах. Для них приходится либо выносить переменные с текстом в шаблон либо писать свою систему переводов, скрипты сбора текстов, генерации файлов переводов, функции форматирования дат и тд. Кстати в JS вроде что-то было добавлено для локализации не так давно.
О, вот тут как никогда много тестирования внутренней реализации. Чего стоит вот это место:
> $this->assertRegExp('/^[\d\w]{45}$/', CookieUtils::getResponse($response, 'auth')->getValue());
Это не тест авторизации. Это тест того что хелпер ставит куку длиной 45 символов из определенного набора.
Как сделать тест тут? Давай начнем с требований к классу. Что мы хотим? Чтобы он залогинивал пользователей, разлогинивал и чтобы мог проверять залогитненность. Исходя из этого и пишем сценарий.
Я бы предложил такой тест:
- авторизуемся, запомнинаем токен (возвращаенный функцией) и созданные ей куки.
- можно проверить что они не пусты (защита от совсем глупых ошибок), можно даже проверить что токен имеет не меньше N символов (то есть что токен надежен). Можно проверить что для разных пользователей токены получаются разные.
- создаем другой хелпер
- проверяем что изначально он показывает отсутствие авторизации
- проверяем что при подаче ему сохраненных кук он признает авторизацию и токен совпадает с запомненным
Далее еще можно потестировать функцию разлогинивания - например проверкой что после нее с куками не залогиниться или что после этого хелпер отказывается возвращать токен. Правда у тебя ее почему-то нет.
> public function testCanManageFile()
> {
> $file = $this->createMock(File::class);
> $file->method('getAuthToken')->willReturn('1234567890');
Вот здесь конечно тоже многовато знания внутренних принципов работы. А что если авторизатору еще и id понадобится например?
https://github.com/foobar1643/filehosting/blob/master/tests/Helper/CommentAdditionTest.php
Вот тут по сути идет тестирование реализации. Ну например вот этот вот код
> $mapperMock->method('getComment')->willReturn($commentMock);
даже аргументы не проверяет. Тест как итог выглядит странно:
> $expected->setId(1)->setParentId(1);
Понятно что это легко сломать если добавить проверку в Comment что parentId <> id.
То, что связано с базой данных, проще тестировать в интеграционном тесте с этой самой базой. То есть создаем пустую базу, вызываем addComment, потом загружаем его и проверяем что это тот же комментарий и что у него есть нужные поля.
Есть наверно и альтернативы: написать мок для маппера, который будет вместо базы складывать и искать комментарии в массиве. Я думаю, даже есть какие-то библиотеки для реализации таких вещей, но это потенциально очень сложная вещь, так легко дойти до эмуляции SQL запросов.
https://github.com/foobar1643/filehosting/blob/master/app/Helper/CommentHelper.php#L16
> if($comment->getParentId() != NULL) {
> $parentComment = $this->commentMapper->getComment($comment->getParentId());
Ты используешь id в пути. Какая у тебя длина элемента пути? 3 символа? Это значит нельзя создать более 1000 комментариев на всем сайте. Надо использовать не id, а порядковый номер комментария среди братьев.
И кстати это позволит делать вставку одним инсертом.
Составные операции надо делать транзакцией.
В реализации комментария есть один сомнительный момент.У тебя там есть getChild() но всегда ли комментарии организованы в дерево? Что если мы выбираем один комментарий из базы? Что если мы хотим загрузить только часть дерева? В более сложном приложении стоило бы вынести древовидную структуру наружу из класса Comment либо использовать ленивую загрузку которая есть в доктрине.
> public function makeTrees($comments)
Эту функцию кстати можно тестировать.
> public function appendToPath($old, $new)
Вот должно ли это быть публичным? Неьзя ли сделать путь деталью внутренней реализации и не выдавать наружу функции работы с ним? Вообще, почему у тебя там все методы публичные?
> public function getMargin($path)
Это не часть модели а часть вью.
https://github.com/foobar1643/filehosting/blob/master/tests/Helper/PaginationHelperTest.php#L30
Тут я бы не тестировал вид ссылки, а тестировал что она похожа на ссылку и разная для разных страниц
https://github.com/foobar1643/filehosting/blob/master/tests/Helper/TokenGeneratorTest.php
Вот по этому поводу я выше писал другому анону: http://pastebin.ru/t5Z34Uyu
> Factory::requestFactory()
Я бы назвал createRequest().
https://github.com/foobar1643/filehosting/blob/master/tests/Middleware/CsrfMiddlewareTest.php
Я бы тут тоже поменьше опирался на реализацию и тестировал бы только публичный интерфейс класса. То есть получил бы токен и попробовал бы проверить запрос с ним.
https://github.com/foobar1643/filehosting/blob/master/tests/Middleware/LocaleMiddlewareTest.php
Здесь чтобы что-то сказать надо разбираться в коде класса.
https://github.com/foobar1643/filehosting/blob/master/tests/Validation/ValidationTest.php#L37
> $this->validator = new Validation($container);
Ой, что это? serviceLocator вместо dependency injection. Заметь что здесь твой тест опирается на предположение что валидатору нужны ровно 3 зависимости.
Ну и я думаю, было бы неплохо еще сделать интеграционные (с базой) и функциональные (браузерные) тесты. Если ты не используешь яваскрипт, то можно использовать например эмулятор HTML браузера http://symfony.com/doc/current/book/testing.html#functional-tests , если нужен яваскрипт то придется использовать протокол Селениума, а в качестве эмулятора браузера подойдет phantomjs (придется повозиться с настройкой и работать будет конечно медленнее).
Браузерные тесты это отдельная сверхзадача, например как искать элементы? По классу? По id? По тексту? По имени поля формы? Какой из способов наиболее устойчив к изменениям верстки?
По локализации.
Я уже писал, что встроенная в Твиг локализация мне не нравится. Ну, твиг расширяемый, ты можешь при большом желании даже теги свои добавлять если не боишься. Мне например не нравится длинный синтаксис ({% trans %}) и отсутствие поддержки подстановок разных параметров как в formatMessage.
Кстати в локализации есть немало подвохов. Например, в некоторых языках используется написание справа налево и надо добавлять соответствующие css стили. хуже, бывает что часть слов пишется справа налево, а иностранные слова - слева направо.
https://github.com/foobar1643/filehosting/blob/master/templates/comments.twig#L4
> <p class="pull-right"><small>{{ comment.getDatePosted }}</small></p>
В разных странах разные форматы записи дат. Твоя архитектура это не учитывает. Обычно используют объект-форматировщик дат вроде того что есть в Intl.
> <span class="comment-text">{{ comment.getCommentText }}</span>
Не сохраняются переводы строк
> <form method="post" id="fallback-reply-form" action="/{{ lang }}/file/{{ comment.fileId }}/">
Возможно лучше было бы иметь класс отвечающий за генерацию УРЛ а не раскидывать их по всему коду. Он бы мог отвечать и за подстановку языка.
> <h4>{% trans %}Search results for {% endtrans %} <i>«{{ query }}»</i></h4>
Вот еще одно сомнительное место. Ты предполагаешь что запрос будет идти в конце предложения, но в азиатских языках порядок слов другой и запрос может идти в начале или середине: "NNN запрос отправленный на результаты": https://translate.google.com/#en/ja/search results for query NNN (бинг выдал более точный на мой взгляд перевод где запрос идет в начале, но в нем ссылку нельзя скопировать).
Тут же ты можешь и заметить еще проблему подстановки HTML кода в перевод. Кто-то оставляет HTML код, кто-то пишет свои языки разметки или использует что-нибудь вроде markdown.
Еще один подвох - перевод текста в JS скриптах. Для них приходится либо выносить переменные с текстом в шаблон либо писать свою систему переводов, скрипты сбора текстов, генерации файлов переводов, функции форматирования дат и тд. Кстати в JS вроде что-то было добавлено для локализации не так давно.
$user->logout()
Я перепутал, у меня стоит РНР7.0.7 сейчас. Всё смешалось в доме Облонских и моей голове.
>>785092
На Win8 ставил. Тут выше в треде есть мои боли при установке на Debian 8 Apache, MySQL и PHP7 по отдельности, но я просто пробовал на виртуалке запустить это всё, я не линуксоид.
PHP5 без проблем установился и на Дебиан, а вот с 7-ым были проблемы.
Остальное всё вообще двумя строками устанавливается.
Как, впрочем, и в cmd.exe.
>>785184
Спасибо, ОП. Есть несколько вопросов.
>Что-то странно, мы в rootComment вроде всего 3 комментария добавили, откуда взялась цифра 6?
Там я циклом добавляю к нему больше элементов чтобы протестировать счет потомков. Наверное это глупое переусложнение и хватило бы трех комментариев.
>В классе нет поля error и file. Да и по моему логичнее просто запретить создавать File из битых файлов
Они наследуются из Slim\Http\UploadedFile. https://github.com/slimphp/Slim/blob/3.x/Slim/Http/UploadedFile.php
>Да и по моему логичнее просто запретить создавать File из битых файлов
Это про $this->error или про общие конструкции типа создания файла с несуществующим именем? Если про $this->error, то это поле наследуется из Slim\Http\UploadedFile и туда сохраняется константа вида UPLOAD_ERR_xxx из формы загрузки. Я потом в валидаторе использую это поле чтобы проверить, все ли успешно загрузилось. Если про создание файла с несуществующим именем - могу сделать, но мне показалось это переусложнением (все равно при попытке вызвать метод moveTo() к такому файлу выбросится исключение).
>Мне кажется функционал замены имени файла удобнее было бы вынести в клас отвечающий за загрузку файлов. А не складывать все в модель. ну например это лучше тем, что если мы поменяем алгоритм переименования, старые файлы продолжат работать (а с твоим подходом они получат новые имена).
Тут тоже не понял каким образом они продолжат работать если имя файла на диске и в БД разное. И getDiskName вызывается только когда нужно получить путь к файлу на диске (для отдачи его пользователю или для анализа getId3).
>Вот тут по моему мы опять начинаем тестировать внутреннюю реализацию. Я бы просто проверял что эта функция возвращает что-то похожее на имя папки.
Регулярка вида ^\d+$ подойдет? Но это ведь тоже вроде как знание внутренней структуры, ведь я знаю что функция должна вернуть имя в виде числа. И я только сейчас заметил что имя функции тут странное, если бы я не знал внутреннюю структуру проекта я бы мог подумать что getFileFolder() может возвращать что угодно.
>- проверял что возвращается что-то отдаленно напоминающее ссылку
>- что для разных файлов она разная
Тут опять же не очень понимаю как сделать. Если для разных файлов можно попробовать применить assertNotEquals($file1->getDownloadLink(), $file2->getDownloadLink()), то с проверкой ссылки возникают трудности. Ссылка ведь может быть формата https://filehosting.ru/ а может и /file/get/1/. Единственная идея которая возникает - проверять регуляркой, как с именем папки, но там ситуация полегче.
> >class FileEntityTest extends TestCase
> >protected static $file;
>Почему static? Один обший файл на любое число тестовых объектов? Тут же нет причин ставить static.
Идея в том чтобы создать его один раз и потом использовать во всех тестах. Смысл создавать файл с одними и теми же данными заново перед каждым тестом, если я в нем ничего не меняю во время теста?
>Далее еще можно потестировать функцию разлогинивания - например проверкой что после нее с куками не залогиниться или что после этого хелпер отказывается возвращать токен. Правда у тебя ее почему-то нет.
Я подумал что это не очень нужно, так как авторизация там используется только для того чтобы показать кнопку удаления файла.
>https://github.com/foobar1643/filehosting/blob/master/tests/Helper/CommentAdditionTest.php
>Вот тут по сути идет тестирование реализации
Мне не понравилось юнит тестирование вообще всего что как-то использует базу данных. Для тестирования добавления\удаления комментариев и файлов я хочу сделать отдельные тесты которые использую базу даных. Интеграционные тесты тоже стоит делать используя PHPUnit? У них есть раздел в документации https://phpunit.de/manual/current/en/database.html
>Ты используешь id в пути. Какая у тебя длина элемента пути? 3 символа? Это значит нельзя создать более 1000 комментариев на всем сайте.
Нули я туда добавляю чтобы правильно работала сортировка при выборке. У меня была проблема когда при выборке комментариев ломалась сортировка и они отображались в неправильном порядке. Сейчас, если комментариев будет больше 1000, все работает, я проверял. Способ порядкового номера среди братьев мне нравится, это в теории убирает id комментария из его matpath, но тут у меня возникают две проблемы:
- Как это повлияет на выборку комментариев, по какой колонке в этом случае сортировать? Не понимаю.
- Как сделать такую вставку одним INSERT я тоже не понимаю, ведь в этом случае мне нужно знать не только matpath родителя, но еще и количество его детей.
Я тут нагородил вот такую конструкцию
>INSERT INTO comments (file_id, parent_id, author, comment_text, date_posted, parent_path) VALUES (:file_id, :parent_id, :author, :text, :date, CONCAT((SELECT parent_path FROM comments WHERE parent_id = :parent_id), '.', (SELECT COUNT(*) FROM comments WHERE parent_id = :parent_id)));
Тут целых три запроса, и оно работает, но как это потом выбирать я не знаю. Может быть я что-то не так понял.
>В реализации комментария есть один сомнительный момент.У тебя там есть getChild() но всегда ли комментарии организованы в дерево? Что если мы выбираем один комментарий из базы?
Есть getChildNodes, получение всех детей. Если выберем один комментарий - вернет null (детей нет). У меня сначала деревья были отдельной структурой, потом я это переделал, потому что проблем от этого было больше чем пользы.
> > $this->validator = new Validation($container);
>Ой, что это? serviceLocator вместо dependency injection. Заметь что здесь твой тест опирается на предположение что валидатору нужны ровно 3 зависимости.
А как по другому протестировать валидацию? У меня там вызываются мапперы чтобы проверить, существует ли такой файл при добавлении комментария, и существует ли родительский комментарий. Не тестировать же это с базой данных? Если подумать, то валидатор к ней вообще отношения не имеет.
>Я уже писал, что встроенная в Твиг локализация мне не нравится. Ну, твиг расширяемый, ты можешь при большом желании даже теги свои добавлять если не боишься. Мне например не нравится длинный синтаксис ({% trans %}) и отсутствие поддержки подстановок разных параметров как в formatMessage.
Я не очень хочу делать свой объект для перевода, потому что тогда получить строки из файлов шаблонов будет проблематично. Плюс мне не нравится то, что нужно будет объект передавать в каждый вью, там существует проблема когда некоторые вызовы вью (например вот тут https://github.com/foobar1643/filehosting/blob/master/app/Controller/FileController.php#L51 ) выглядят большими. И даже если сам шаблон нигде не будет использовать объект перевода, его все равно нужно будет передавать для перевода текста из шапки, например. Плюс этот объект можно забыть передать, тогда будет ошибка.
>>785184
Спасибо, ОП. Есть несколько вопросов.
>Что-то странно, мы в rootComment вроде всего 3 комментария добавили, откуда взялась цифра 6?
Там я циклом добавляю к нему больше элементов чтобы протестировать счет потомков. Наверное это глупое переусложнение и хватило бы трех комментариев.
>В классе нет поля error и file. Да и по моему логичнее просто запретить создавать File из битых файлов
Они наследуются из Slim\Http\UploadedFile. https://github.com/slimphp/Slim/blob/3.x/Slim/Http/UploadedFile.php
>Да и по моему логичнее просто запретить создавать File из битых файлов
Это про $this->error или про общие конструкции типа создания файла с несуществующим именем? Если про $this->error, то это поле наследуется из Slim\Http\UploadedFile и туда сохраняется константа вида UPLOAD_ERR_xxx из формы загрузки. Я потом в валидаторе использую это поле чтобы проверить, все ли успешно загрузилось. Если про создание файла с несуществующим именем - могу сделать, но мне показалось это переусложнением (все равно при попытке вызвать метод moveTo() к такому файлу выбросится исключение).
>Мне кажется функционал замены имени файла удобнее было бы вынести в клас отвечающий за загрузку файлов. А не складывать все в модель. ну например это лучше тем, что если мы поменяем алгоритм переименования, старые файлы продолжат работать (а с твоим подходом они получат новые имена).
Тут тоже не понял каким образом они продолжат работать если имя файла на диске и в БД разное. И getDiskName вызывается только когда нужно получить путь к файлу на диске (для отдачи его пользователю или для анализа getId3).
>Вот тут по моему мы опять начинаем тестировать внутреннюю реализацию. Я бы просто проверял что эта функция возвращает что-то похожее на имя папки.
Регулярка вида ^\d+$ подойдет? Но это ведь тоже вроде как знание внутренней структуры, ведь я знаю что функция должна вернуть имя в виде числа. И я только сейчас заметил что имя функции тут странное, если бы я не знал внутреннюю структуру проекта я бы мог подумать что getFileFolder() может возвращать что угодно.
>- проверял что возвращается что-то отдаленно напоминающее ссылку
>- что для разных файлов она разная
Тут опять же не очень понимаю как сделать. Если для разных файлов можно попробовать применить assertNotEquals($file1->getDownloadLink(), $file2->getDownloadLink()), то с проверкой ссылки возникают трудности. Ссылка ведь может быть формата https://filehosting.ru/ а может и /file/get/1/. Единственная идея которая возникает - проверять регуляркой, как с именем папки, но там ситуация полегче.
> >class FileEntityTest extends TestCase
> >protected static $file;
>Почему static? Один обший файл на любое число тестовых объектов? Тут же нет причин ставить static.
Идея в том чтобы создать его один раз и потом использовать во всех тестах. Смысл создавать файл с одними и теми же данными заново перед каждым тестом, если я в нем ничего не меняю во время теста?
>Далее еще можно потестировать функцию разлогинивания - например проверкой что после нее с куками не залогиниться или что после этого хелпер отказывается возвращать токен. Правда у тебя ее почему-то нет.
Я подумал что это не очень нужно, так как авторизация там используется только для того чтобы показать кнопку удаления файла.
>https://github.com/foobar1643/filehosting/blob/master/tests/Helper/CommentAdditionTest.php
>Вот тут по сути идет тестирование реализации
Мне не понравилось юнит тестирование вообще всего что как-то использует базу данных. Для тестирования добавления\удаления комментариев и файлов я хочу сделать отдельные тесты которые использую базу даных. Интеграционные тесты тоже стоит делать используя PHPUnit? У них есть раздел в документации https://phpunit.de/manual/current/en/database.html
>Ты используешь id в пути. Какая у тебя длина элемента пути? 3 символа? Это значит нельзя создать более 1000 комментариев на всем сайте.
Нули я туда добавляю чтобы правильно работала сортировка при выборке. У меня была проблема когда при выборке комментариев ломалась сортировка и они отображались в неправильном порядке. Сейчас, если комментариев будет больше 1000, все работает, я проверял. Способ порядкового номера среди братьев мне нравится, это в теории убирает id комментария из его matpath, но тут у меня возникают две проблемы:
- Как это повлияет на выборку комментариев, по какой колонке в этом случае сортировать? Не понимаю.
- Как сделать такую вставку одним INSERT я тоже не понимаю, ведь в этом случае мне нужно знать не только matpath родителя, но еще и количество его детей.
Я тут нагородил вот такую конструкцию
>INSERT INTO comments (file_id, parent_id, author, comment_text, date_posted, parent_path) VALUES (:file_id, :parent_id, :author, :text, :date, CONCAT((SELECT parent_path FROM comments WHERE parent_id = :parent_id), '.', (SELECT COUNT(*) FROM comments WHERE parent_id = :parent_id)));
Тут целых три запроса, и оно работает, но как это потом выбирать я не знаю. Может быть я что-то не так понял.
>В реализации комментария есть один сомнительный момент.У тебя там есть getChild() но всегда ли комментарии организованы в дерево? Что если мы выбираем один комментарий из базы?
Есть getChildNodes, получение всех детей. Если выберем один комментарий - вернет null (детей нет). У меня сначала деревья были отдельной структурой, потом я это переделал, потому что проблем от этого было больше чем пользы.
> > $this->validator = new Validation($container);
>Ой, что это? serviceLocator вместо dependency injection. Заметь что здесь твой тест опирается на предположение что валидатору нужны ровно 3 зависимости.
А как по другому протестировать валидацию? У меня там вызываются мапперы чтобы проверить, существует ли такой файл при добавлении комментария, и существует ли родительский комментарий. Не тестировать же это с базой данных? Если подумать, то валидатор к ней вообще отношения не имеет.
>Я уже писал, что встроенная в Твиг локализация мне не нравится. Ну, твиг расширяемый, ты можешь при большом желании даже теги свои добавлять если не боишься. Мне например не нравится длинный синтаксис ({% trans %}) и отсутствие поддержки подстановок разных параметров как в formatMessage.
Я не очень хочу делать свой объект для перевода, потому что тогда получить строки из файлов шаблонов будет проблематично. Плюс мне не нравится то, что нужно будет объект передавать в каждый вью, там существует проблема когда некоторые вызовы вью (например вот тут https://github.com/foobar1643/filehosting/blob/master/app/Controller/FileController.php#L51 ) выглядят большими. И даже если сам шаблон нигде не будет использовать объект перевода, его все равно нужно будет передавать для перевода текста из шапки, например. Плюс этот объект можно забыть передать, тогда будет ошибка.
Аноны выше написали правильно
$user->changetPassword($newPass) //сменить пароль
$user->block() //заблокировать
$user->makePremium() //сделать премиум-пользователем
Спросишь, почему это не сделать обычными полями (типа $user->isPremium=true) - отвечу. ПОтому что очень редко достаточно поменять одно поле в табличке юзера. Обычно при этом надо ещё сделать мнодество всякой фигни. Типа, послать письмо юзеру, сделать запись в лог, удвоить какие нибудь дневные лимиты постинга, и прочее. Если ты начнешь всю эту логику размазывать по множеству разных мест, вместо того, чтобы собирать плотно в кучку в методе соответствующего класса - в большом проекте ты очень скоро сам перестанешь понимать, как и что у тебя вообще работает.
вот я например щас пишу систему электронного документоооборота на PHP. Логика прохождения заявок\согласований документов - пиздец какая сложная. Без продвинутого ООП это просто нереально напиисать
Алсо это слим.
Теперь такая, непонятная для меня, проблема. Что ему еще может не нравиться?
хоспаде, как же хочется программировать! Три дня не кодил с этой переустановкой
Каким образом ты их подключаешь? В твоем случае нужно использовать абсолютные пути от корня сервера.
Извиняюсь, не заметил самый нижний скриншот. Твой способ не будет работать, потому что в случае с точкой он ищет файлы в текущей директории, и как ты можешь видеть, в директории /file/ таких файлов нет. А когда ты переходишь по ссылке /public/file - то все еще находишься в папке public, поэтому в этом случае браузер загружает файлы нормально. Если же указать ссылку вида /public/file/ то все сломается. Решение - использовать абсолютный путь от корня /public/bootstrap/bootstrap.css.
Еще почитай урок ОПа про структуру URL https://github.com/codedokode/pasta/blob/master/network/urls.md
Теперь вот так. Путь правильный, но почему-то новая ошибка.
Магическая константа __DIR__ возвращает абсолютный путь к директории файла на сервере. И ты путь к файлу на сервере отдаешь пользователю, т.е. ты говоришь браузеру пользователя загрузить файл по следующему пути - C:\Apache24\ и т.д. Так как по умолчанию браузеру запрещено загружать что-то из ФС пользователя, возникает ошибка. Использовать __DIR__ в шаблонах это неправильно, корень веб-сервера со стороны браузера будет символ - /. Так же и тебе нужно указать абсолютный путь к css файлу от этого корня, в твоем случае это /file-sharing/public/bootstrap/bootstrap.css.
У ОПа в уроке наглядно показано отличие между относительными и абсолютными ссылками, так же там есть небольшие задания для закрепления, зря ты его пропускаешь.
Ясно, теперь работает.. Спасибо! Обязательно прочитаю.
Это преувеличение, конечно. Знаю только что хром выдаст ошибку при попытке загрузить локальный файл. В других браузерах с таким не сталкивался ни разу.
Лог mysql'а: который мне ни о чём не говорит
2016-07-01 20:08:03 6060 [Warning] You need to use --log-bin to make --binlog-format work.
2016-07-01 20:08:03 6060 [Note] Plugin 'FEDERATED' is disabled.
2016-07-01 20:08:03 6060 [Note] InnoDB: Using atomics to ref count buffer pool pages
2016-07-01 20:08:03 6060 [Note] InnoDB: The InnoDB memory heap is disabled
2016-07-01 20:08:03 6060 [Note] InnoDB: Mutexes and rw_locks use Windows interlocked functions
2016-07-01 20:08:03 6060 [Note] InnoDB: Memory barrier is not used
2016-07-01 20:08:03 6060 [Note] InnoDB: Compressed tables use zlib 1.2.3
2016-07-01 20:08:03 6060 [Note] InnoDB: Not using CPU crc32 instructions
2016-07-01 20:08:03 6060 [Note] InnoDB: Initializing buffer pool, size = 128.0M
2016-07-01 20:08:03 6060 [Note] InnoDB: Completed initialization of buffer pool
2016-07-01 20:08:03 6060 [Note] InnoDB: Highest supported file format is Barracuda.
2016-07-01 20:08:03 6060 [Note] InnoDB: 128 rollback segment(s) are active.
2016-07-01 20:08:03 6060 [Note] InnoDB: Waiting for purge to start
2016-07-01 20:08:03 6060 [Note] InnoDB: 5.6.30 started; log sequence number 1641273
2016-07-01 20:08:03 6060 [Note] Server hostname (bind-address): '*'; port: 3306
2016-07-01 20:08:03 6060 [Note] IPv6 is available.
2016-07-01 20:08:03 6060 [Note] - '::' resolves to '::';
2016-07-01 20:08:03 6060 [Note] Server socket created on IP: '::'.
2016-07-01 20:08:03 6060 [Warning] InnoDB: Cannot open table mysql/slave_master_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2016-07-01 20:08:03 6060 [Warning] Info table is not ready to be used. Table 'mysql.slave_master_info' cannot be opened.
2016-07-01 20:08:03 6060 [Warning] InnoDB: Cannot open table mysql/slave_worker_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2016-07-01 20:08:03 6060 [Warning] InnoDB: Cannot open table mysql/slave_relay_log_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2016-07-01 20:08:03 6060 [Warning] Info table is not ready to be used. Table 'mysql.slave_relay_log_info' cannot be opened.
2016-07-01 20:08:03 6060 [Note] Event Scheduler: Loaded 0 events
2016-07-01 20:08:03 6060 [Note] mysql\bin\mysqld.exe: ready for connections.
Version: '5.6.30' socket: '' port: 3306 MySQL Community Server (GPL)
2016-07-01 20:11:24 164c InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2016-07-01 20:11:24 164c InnoDB: Error: Fetch of persistent statistics requested for table "students"."students" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
Лог mysql'а: который мне ни о чём не говорит
2016-07-01 20:08:03 6060 [Warning] You need to use --log-bin to make --binlog-format work.
2016-07-01 20:08:03 6060 [Note] Plugin 'FEDERATED' is disabled.
2016-07-01 20:08:03 6060 [Note] InnoDB: Using atomics to ref count buffer pool pages
2016-07-01 20:08:03 6060 [Note] InnoDB: The InnoDB memory heap is disabled
2016-07-01 20:08:03 6060 [Note] InnoDB: Mutexes and rw_locks use Windows interlocked functions
2016-07-01 20:08:03 6060 [Note] InnoDB: Memory barrier is not used
2016-07-01 20:08:03 6060 [Note] InnoDB: Compressed tables use zlib 1.2.3
2016-07-01 20:08:03 6060 [Note] InnoDB: Not using CPU crc32 instructions
2016-07-01 20:08:03 6060 [Note] InnoDB: Initializing buffer pool, size = 128.0M
2016-07-01 20:08:03 6060 [Note] InnoDB: Completed initialization of buffer pool
2016-07-01 20:08:03 6060 [Note] InnoDB: Highest supported file format is Barracuda.
2016-07-01 20:08:03 6060 [Note] InnoDB: 128 rollback segment(s) are active.
2016-07-01 20:08:03 6060 [Note] InnoDB: Waiting for purge to start
2016-07-01 20:08:03 6060 [Note] InnoDB: 5.6.30 started; log sequence number 1641273
2016-07-01 20:08:03 6060 [Note] Server hostname (bind-address): '*'; port: 3306
2016-07-01 20:08:03 6060 [Note] IPv6 is available.
2016-07-01 20:08:03 6060 [Note] - '::' resolves to '::';
2016-07-01 20:08:03 6060 [Note] Server socket created on IP: '::'.
2016-07-01 20:08:03 6060 [Warning] InnoDB: Cannot open table mysql/slave_master_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2016-07-01 20:08:03 6060 [Warning] Info table is not ready to be used. Table 'mysql.slave_master_info' cannot be opened.
2016-07-01 20:08:03 6060 [Warning] InnoDB: Cannot open table mysql/slave_worker_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2016-07-01 20:08:03 6060 [Warning] InnoDB: Cannot open table mysql/slave_relay_log_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2016-07-01 20:08:03 6060 [Warning] Info table is not ready to be used. Table 'mysql.slave_relay_log_info' cannot be opened.
2016-07-01 20:08:03 6060 [Note] Event Scheduler: Loaded 0 events
2016-07-01 20:08:03 6060 [Note] mysql\bin\mysqld.exe: ready for connections.
Version: '5.6.30' socket: '' port: 3306 MySQL Community Server (GPL)
2016-07-01 20:11:24 164c InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2016-07-01 20:11:24 164c InnoDB: Error: Fetch of persistent statistics requested for table "students"."students" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
>>785442
У тебя пароль не выставлен. Снеси это глючное говно phpmyadmin и скачай нормальный клиент баз данных HeidiSQL - http://www.heidisql.com/
В нем и заходи, проблем не будет, и все быстрее станет.
Давай начнем с анализа ситуации. Пхп пишет:
Access denied
Это значит:
- соединиться с базой данных удалось (иначе было бы что-то вроде connection failed)
- однако при отправке логина и пароля (точнее только логина, без пароля) база данных отказала в доступе. Очевидно в ней запрещен доступ пользователю root@localhost без пароля (в БД можно настраивать доступ не только по имени но еще и по IP-адресу откуда приходит соединение).
Для проверки что мы правы, попробуй соединиться с базой из консоли используя те же реквизиты что и php:
mysql -uroot -hlocalhost students
- если будет та же ошибка - доступ действительно запрещен
- если не будет - значит ты в пхп неправильно указал имя пользователя, адрес хоста, пароль или что-то еще
- также тебе стоит прочитать гайд по командной строке из ОП поста
Если доступ запрещен, надо либо его дать либо указать в пхп правильный пароль для рута.
Как дать доступ, погугли: https://www.google.ru/search?q=mysql+управление+пользователями&newwindow=1&gbv=1&sei=pvF2V8vENaHi6ASdxpfADw
Пароль рута для mysql по умолчанию либо пустой либо задается при установке. Если ты его совсем забыл, можно его как-то сбросить, погугли.
Из лога кстати видно что:
- используется стандартный порт 3306
- порт слушается на всех сетевых интерфейсах, то есть к нему можно подключиться снаружи. Наверно ты бы хотел слушать только на 127.0.0.1 чтобы подключаться можно было только с твоего компьютера.
Давай начнем с анализа ситуации. Пхп пишет:
Access denied
Это значит:
- соединиться с базой данных удалось (иначе было бы что-то вроде connection failed)
- однако при отправке логина и пароля (точнее только логина, без пароля) база данных отказала в доступе. Очевидно в ней запрещен доступ пользователю root@localhost без пароля (в БД можно настраивать доступ не только по имени но еще и по IP-адресу откуда приходит соединение).
Для проверки что мы правы, попробуй соединиться с базой из консоли используя те же реквизиты что и php:
mysql -uroot -hlocalhost students
- если будет та же ошибка - доступ действительно запрещен
- если не будет - значит ты в пхп неправильно указал имя пользователя, адрес хоста, пароль или что-то еще
- также тебе стоит прочитать гайд по командной строке из ОП поста
Если доступ запрещен, надо либо его дать либо указать в пхп правильный пароль для рута.
Как дать доступ, погугли: https://www.google.ru/search?q=mysql+управление+пользователями&newwindow=1&gbv=1&sei=pvF2V8vENaHi6ASdxpfADw
Пароль рута для mysql по умолчанию либо пустой либо задается при установке. Если ты его совсем забыл, можно его как-то сбросить, погугли.
Из лога кстати видно что:
- используется стандартный порт 3306
- порт слушается на всех сетевых интерфейсах, то есть к нему можно подключиться снаружи. Наверно ты бы хотел слушать только на 127.0.0.1 чтобы подключаться можно было только с твоего компьютера.
Сейчас вроде запрещают, так как это может вести к уязвимостям (например злоумышленник может попытаться читать всякие системные файлы или /proc таким образом). УРЛ должен иметь вид вроде file://c:/file.png иначе не будет работать. file:// значит что браузер ищет ресурс локально на диске, а не запрашивает с сервера по протоколу HTTP.
И разумеется такая ссылка будет работать только на том же компьютере так как браузер запрашивает файл напрямую с диска а не через сервер. Если ты выгрузишь такую страницу в интернет? то картинка будет видна только у тебя. Так как у других пользователей ее скорее всего нет по такому пути.
Потому УРЛ должен иметь вид /some/image.png.
>>785465
Если у него public - это корень сервера то путь отсчитывается от него и будет /bootstrap/bootstrap.css
>>785452
Пишет что запрещено загружать файл напрямую с диска. Скорее всего это потому, что страницам полученным с сервера запрещается обращаться к диску пользователя напрямую из соображений безопасности. Это могут делать только страницы которые сами загружены с диска.
>>785435
А ты посмотри внимательно какие пути написаны в консоли. Там лишнее слово file получилось. Надо либо писать путь от корня /lalala/lalala либо добавлять нужное число точек ../../lalala (сложно).
Одним файлом и со всеми примерами выражений для проверки: https://ideone.com/a4aeZ4
Советую сразу скроллить вниз, классы собраны в один файл скриптом, поэтому в их последовательности нет никакой логики. Добавил на ideone, чтобы проще было тестировать код на проблемные места.
Решил исходить из того, что и int и float можно представить в виде простой дроби, поэтому у меня все числа являются частными случаями SimpleFraction. У меня вообще туго с математикой, во время решения задачи я гуглил как дроби перемножать.
Обработчик ошибок добавил свой, чтобы надпись "Ошибка: (%s/0) делить на ноль нельзя" выводилась аккуратно.
1) Каким требованиям должно удовлетворять валидное RPN-выражение? Достаточно ли просто проверить, что чисел должно быть >= 2 и количество операндов на 1 меньше чем чисел?
2) Ту часть, что на пике, я так и не смог облечь в код по-человечески, вышло огромное плохо читаемое условие: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/ShuntingYard.php#L26
Как можно улучшить?
На всякий случай напомню, что студентов исправил.
> Обычно при этом надо ещё сделать мнодество всякой фигни. Типа, послать письмо юзеру, сделать запись в лог, удвоить какие нибудь дневные лимиты постинга, и прочее
Только вот такие сложные вещи лучше выносить в сервис так как модель юзера обычно не имеет доступа к логам, базам и тд.
>>785399
>>Что-то странно, мы в rootComment вроде всего 3 комментария добавили, откуда взялась цифра 6?
> Там я циклом добавляю к нему больше элементов чтобы протестировать счет потомков. Наверное это глупое переусложнение и хватило бы трех комментариев.
А, видимо я перепутал непосредственных детей и потомков любой глубины. Детей там вроде 3, но у них видимо еще свои дети есть.
>>В классе нет поля error и file. Да и по моему логичнее просто запретить создавать File из битых файлов
> Они наследуются из Slim\Http\UploadedFile
Тогда на мой взгляд это не совсем удачная идея наследовать. Наследование это отношение вида "А является расширенной версией Б".
Но UploadedFile представляет собой файл полученный из массива $FILES, а File - это запись в базе данных. У них разные наборы полей, например в БД мы не храним абсолютный путь к файлу или статус ошибки.
Ну например после сохранения в БД и восстановления - у тебя получается идентичный объект исходному? У него все те же поля прописаны? Все методы вернут тот же результат?
Я не уверен что тут можно использовать наследование. Мне кажется тут может быть разве что отношение вида "А содержит в себе Б", то есть композиция.
Что-то мне кажется что наследование тут несет больше сложностей чем выгоды. Лучше наверно сделать в отдельном классе методы для конвертирования одного во второй.
> Тут тоже не понял каким образом они продолжат работать если имя файла на диске и в БД разное.
У меня идея в том что мы отдельно храним в БД исходное имя файла, а отдельно - под каким именем сохранен файл. Твой подход не позволяет поменять алгоритм преобразования имен, не сломав ранее загруженные файлы.
> Регулярка вида ^\d+$ подойдет? Но это ведь тоже вроде как знание внутренней структуры, ведь я знаю что функция должна вернуть имя в виде числа.
Ну можно заложить в тест требование "папка должна состоять из цифр", можно не закладывать и просто проверять что это не пустая строка. Тут выбор между более тщательно тестировать и сделать менее хрупкий тест.
>>- проверял что возвращается что-то отдаленно напоминающее ссылку
>>- что для разных файлов она разная
> Тут опять же не очень понимаю как сделать. Если для разных файлов можно попробовать применить assertNotEquals($file1->getDownloadLink(), $file2->getDownloadLink()), то с проверкой ссылки возникают трудности.
Проверить ссылку в юнит-тесты в принципе нельзя, если не задавать жестко ее формат (например если он описан в техническом задании к проекту). Иначе проверить ссылку можно только попытавшись открыть ее и скачать по ней файл.
Потому мы можем проверять следующее:
- что ссылка не является пустой строкой
- еще можно проверить что ссылка не содержит запрещенных символов (пробелов). При большом желании можно даже откопать какую-нибудь библиотеку проверяющую ссылку на соответствие стандартам, но это наверно излишне. Можно сделать упрощенную проверку, что ссылка начинается с http://, https:// или / (отсекаем относительные ссылки).
- еще можно проверять что ссылка указывает на правильный домен, но это опять же потребует усложнений, например закладывать список доменов в тесты
Я бы сделал упрощенную функцию проверки ссылок, которая просто проверяет с чего она начинается. Это на мой взгляд нормальный компромисс. И дополнительно проверять что для разных файлов ссылки разные.
> Идея в том чтобы создать его один раз и потом использовать во всех тестах. Смысл создавать файл с одними и теми же данными заново перед каждым тестом, если я в нем ничего не меняю во время теста?
Экономия тут копеечная получается. Создание объекта занимает так мало времени что выгоднее создавать перед каждым тестом заново чем рисковать нарушением изоляции тестов. Смысл - изоляция.
И о таких вещах надо как минимум комментарий писать, а то непонятно зачем это делается.
>>Далее еще можно потестировать функцию разлогинивания - например проверкой что после нее с куками не залогиниться или что после этого хелпер отказывается возвращать токен. Правда у тебя ее почему-то нет.
> Я подумал что это не очень нужно, так как авторизация там используется только для того чтобы показать кнопку удаления файла.
Но с другой стороны это фича которую легко сломать и не заметить.
> Для тестирования добавления\удаления комментариев и файлов я хочу сделать отдельные тесты которые использую базу даных. Интеграционные тесты тоже стоит делать используя PHPUnit?
Можно, но тебе надо решить проблему изоляции. Как гарантировать что тест А, меняя базу, не помешает тесту Б? Тут есть разные варианты, писать тесты которые гарантированно не ломают другие тесты, очищать базу перед каждым тестом, делать тест внутри транзакции которая откатывается в конце. Выбор тут будет между временем выполнения и степенью изоляции.
Я также советую избегать тестов вида "вызвал функцию, проверил базу" в пользу "вызвал одну функцию, вызвал другую функцию проверил результат", так как они более устойчивы и не привязаны к знанию о структуре БД. Хотя с другой стороны иногда удобнее именно вбить данные в базу и на ней вызывать каике-то функции.
Вот такие тесты, которые вызывают функцию и проверяют содержимое базы - они хороши когда есть требования к структуре этой базы. Например когда с ней работает еще кто-то другой и получается что мы знаем как она должна выглядеть и это проверяем. Но в твоем случае предпочительнее тесты, не знающие структуру базы а использующие только публичные методы получения информации.
Потому можно попроьовать сделать такой вариант:
- приводим базу в начальное состояние (например загружаем дамп и загружаем какие-то начальные данные)
- проводим тест
- переходим к п.1
Начальные данные - это например какие-то справочники (например список стран) которые есть в базе изначально. А например список пользователей лучше сделать пустым и вставлять их в ходе теста.
Также, тут есть выбор, использовать одно и то же соединение с БД или переподсоединяться перед каждым тестом (в твоем случае это подразумевает еще и пересоздание контейнера). Опять же выбор меду производительностью и степенью изоляции.
> Обычно при этом надо ещё сделать мнодество всякой фигни. Типа, послать письмо юзеру, сделать запись в лог, удвоить какие нибудь дневные лимиты постинга, и прочее
Только вот такие сложные вещи лучше выносить в сервис так как модель юзера обычно не имеет доступа к логам, базам и тд.
>>785399
>>Что-то странно, мы в rootComment вроде всего 3 комментария добавили, откуда взялась цифра 6?
> Там я циклом добавляю к нему больше элементов чтобы протестировать счет потомков. Наверное это глупое переусложнение и хватило бы трех комментариев.
А, видимо я перепутал непосредственных детей и потомков любой глубины. Детей там вроде 3, но у них видимо еще свои дети есть.
>>В классе нет поля error и file. Да и по моему логичнее просто запретить создавать File из битых файлов
> Они наследуются из Slim\Http\UploadedFile
Тогда на мой взгляд это не совсем удачная идея наследовать. Наследование это отношение вида "А является расширенной версией Б".
Но UploadedFile представляет собой файл полученный из массива $FILES, а File - это запись в базе данных. У них разные наборы полей, например в БД мы не храним абсолютный путь к файлу или статус ошибки.
Ну например после сохранения в БД и восстановления - у тебя получается идентичный объект исходному? У него все те же поля прописаны? Все методы вернут тот же результат?
Я не уверен что тут можно использовать наследование. Мне кажется тут может быть разве что отношение вида "А содержит в себе Б", то есть композиция.
Что-то мне кажется что наследование тут несет больше сложностей чем выгоды. Лучше наверно сделать в отдельном классе методы для конвертирования одного во второй.
> Тут тоже не понял каким образом они продолжат работать если имя файла на диске и в БД разное.
У меня идея в том что мы отдельно храним в БД исходное имя файла, а отдельно - под каким именем сохранен файл. Твой подход не позволяет поменять алгоритм преобразования имен, не сломав ранее загруженные файлы.
> Регулярка вида ^\d+$ подойдет? Но это ведь тоже вроде как знание внутренней структуры, ведь я знаю что функция должна вернуть имя в виде числа.
Ну можно заложить в тест требование "папка должна состоять из цифр", можно не закладывать и просто проверять что это не пустая строка. Тут выбор между более тщательно тестировать и сделать менее хрупкий тест.
>>- проверял что возвращается что-то отдаленно напоминающее ссылку
>>- что для разных файлов она разная
> Тут опять же не очень понимаю как сделать. Если для разных файлов можно попробовать применить assertNotEquals($file1->getDownloadLink(), $file2->getDownloadLink()), то с проверкой ссылки возникают трудности.
Проверить ссылку в юнит-тесты в принципе нельзя, если не задавать жестко ее формат (например если он описан в техническом задании к проекту). Иначе проверить ссылку можно только попытавшись открыть ее и скачать по ней файл.
Потому мы можем проверять следующее:
- что ссылка не является пустой строкой
- еще можно проверить что ссылка не содержит запрещенных символов (пробелов). При большом желании можно даже откопать какую-нибудь библиотеку проверяющую ссылку на соответствие стандартам, но это наверно излишне. Можно сделать упрощенную проверку, что ссылка начинается с http://, https:// или / (отсекаем относительные ссылки).
- еще можно проверять что ссылка указывает на правильный домен, но это опять же потребует усложнений, например закладывать список доменов в тесты
Я бы сделал упрощенную функцию проверки ссылок, которая просто проверяет с чего она начинается. Это на мой взгляд нормальный компромисс. И дополнительно проверять что для разных файлов ссылки разные.
> Идея в том чтобы создать его один раз и потом использовать во всех тестах. Смысл создавать файл с одними и теми же данными заново перед каждым тестом, если я в нем ничего не меняю во время теста?
Экономия тут копеечная получается. Создание объекта занимает так мало времени что выгоднее создавать перед каждым тестом заново чем рисковать нарушением изоляции тестов. Смысл - изоляция.
И о таких вещах надо как минимум комментарий писать, а то непонятно зачем это делается.
>>Далее еще можно потестировать функцию разлогинивания - например проверкой что после нее с куками не залогиниться или что после этого хелпер отказывается возвращать токен. Правда у тебя ее почему-то нет.
> Я подумал что это не очень нужно, так как авторизация там используется только для того чтобы показать кнопку удаления файла.
Но с другой стороны это фича которую легко сломать и не заметить.
> Для тестирования добавления\удаления комментариев и файлов я хочу сделать отдельные тесты которые использую базу даных. Интеграционные тесты тоже стоит делать используя PHPUnit?
Можно, но тебе надо решить проблему изоляции. Как гарантировать что тест А, меняя базу, не помешает тесту Б? Тут есть разные варианты, писать тесты которые гарантированно не ломают другие тесты, очищать базу перед каждым тестом, делать тест внутри транзакции которая откатывается в конце. Выбор тут будет между временем выполнения и степенью изоляции.
Я также советую избегать тестов вида "вызвал функцию, проверил базу" в пользу "вызвал одну функцию, вызвал другую функцию проверил результат", так как они более устойчивы и не привязаны к знанию о структуре БД. Хотя с другой стороны иногда удобнее именно вбить данные в базу и на ней вызывать каике-то функции.
Вот такие тесты, которые вызывают функцию и проверяют содержимое базы - они хороши когда есть требования к структуре этой базы. Например когда с ней работает еще кто-то другой и получается что мы знаем как она должна выглядеть и это проверяем. Но в твоем случае предпочительнее тесты, не знающие структуру базы а использующие только публичные методы получения информации.
Потому можно попроьовать сделать такой вариант:
- приводим базу в начальное состояние (например загружаем дамп и загружаем какие-то начальные данные)
- проводим тест
- переходим к п.1
Начальные данные - это например какие-то справочники (например список стран) которые есть в базе изначально. А например список пользователей лучше сделать пустым и вставлять их в ходе теста.
Также, тут есть выбор, использовать одно и то же соединение с БД или переподсоединяться перед каждым тестом (в твоем случае это подразумевает еще и пересоздание контейнера). Опять же выбор меду производительностью и степенью изоляции.
> Нули я туда добавляю чтобы правильно работала сортировка при выборке. У меня была проблема когда при выборке комментариев ломалась сортировка и они отображались в неправильном порядке. Сейчас, если комментариев будет больше 1000, все работает, я проверял.
Плохо проверял. Допустим есть комментарий с id = 999 и с id = 1002. Они получат такие пути:
001.999
001.002
Сортировка оказвеатся нарушена. А если мы попытаемся вставить комментарий с id = 2002 то нарушится уникальность путей.
Нужно использовать порядковый номер комментария в ветке. То есть
001.001
001.002
....
001.999
Добавить условие уникальности (файл, путь).
Как получить номер перед вставкой? Есть 2 варианта:
- сделать SELECT COUNT() WHERE parent_id = ? либо WHERE file_id = ? AND path LIKE '001.%'
- сделать SELECT MAX(path) WHERE parent_id = ? либо через file_id и path
Второй посложнее но он может работать быстрее так как при удачном стечении обстоятельств он берет 1 запись из индекса, а вот первый вариант вынужден пересчитать все N комментариев в ветке.
Для оптимизации поиска с parent_id конечно же нужен дополнительный индекс по (parent_id, path). При поиске черз file_id и path используется существующий уникальный индекс.
Есть ли тут подвох? Ну конечно, есть. Что если 2 потока параллельно пытаются вставить комментарий, получают один и тот же номер и пытаются сделать вставку? Решение известно - блокировки, они бывают 2 видов ( https://ru.wikipedia.org/wiki/Блокировка_(СУБД) ):
- пессимистичная - на время транзакции эксклюзивно блокируем последний комментарий в ветке через SELECT FOR UPDATE
- оптимичтиная - не блокируем, пробуем вставить, а если получим ошибку уникальности ключа (то есть второй поток успел занять новый идентификатор пути), делаем небольшую паузу и повторяем попытку заново (вычисляя новый путь)
Эта важная тема, надо бы чтобы ты в ней разобрался. Вот старая паста: http://pastebin.ru/JKLyrQYw
То есть ты должен понимать:
- какие проблемы возникают когда мы делаем несколько запросов подряд на изменение данных или получение + измненеие данных. Что меняется если у нас много процессов которые работают с базой данных параллельно
- какие из проблем решают транзакции, а какие блокировки
- какие бывают виды блокировок
- как их реализовать
- что из написанного выше применимо к нашей задаче вставки комментариев
Проанализируй свой текущий код и попробуй определить какие в нем есть проблемы.
Кстати ты знаешь, как протестировать что проблем с параллельной вставкой комментариев нет?
> Способ порядкового номера среди братьев мне нравится, это в теории убирает id комментария из его matpath, но тут у меня возникают две проблемы:
> по какой колонке в этом случае сортировать?
По path
> Как сделать такую вставку одним INSERT
предварительный select + за ним insert
> Тут целых три запроса, и оно работает, но как это потом выбирать я не знаю. Может быть я что-то не так понял.
Лучше делать отдельными запросами
> У меня сначала деревья были отдельной структурой, потом я это переделал, потому что проблем от этого было больше чем пользы.
Ну смотри, вот завтра ты захочешь сделать функцию выборки одного комментария по id. Что у него будет в getChild() ? Привязывая дерево к модели коммента, ты не даешь возможности выбирать комменатрии без учета древовидности.
>>Ой, что это? serviceLocator вместо dependency injection. Заметь что здесь твой тест опирается на предположение что валидатору нужны ровно 3 зависимости.
> А как по другому протестировать валидацию?
Нет, проблема в том что там не соблюдается принцип DI. Надо передавать в конструктор зависимости, а не сам контейнер. Перечитай пасту по DI.
> Я не очень хочу делать свой объект для перевода, потому что тогда получить строки из файлов шаблонов будет проблематично.
Тогда придется укладываться в ограничения твига.
> Плюс мне не нравится то, что нужно будет объект передавать в каждый вью,
Можно передать как глобальную переменную в начале. Во втором слиме была возможность сделать $slim->view->set(...) или как-то так.
> Нули я туда добавляю чтобы правильно работала сортировка при выборке. У меня была проблема когда при выборке комментариев ломалась сортировка и они отображались в неправильном порядке. Сейчас, если комментариев будет больше 1000, все работает, я проверял.
Плохо проверял. Допустим есть комментарий с id = 999 и с id = 1002. Они получат такие пути:
001.999
001.002
Сортировка оказвеатся нарушена. А если мы попытаемся вставить комментарий с id = 2002 то нарушится уникальность путей.
Нужно использовать порядковый номер комментария в ветке. То есть
001.001
001.002
....
001.999
Добавить условие уникальности (файл, путь).
Как получить номер перед вставкой? Есть 2 варианта:
- сделать SELECT COUNT() WHERE parent_id = ? либо WHERE file_id = ? AND path LIKE '001.%'
- сделать SELECT MAX(path) WHERE parent_id = ? либо через file_id и path
Второй посложнее но он может работать быстрее так как при удачном стечении обстоятельств он берет 1 запись из индекса, а вот первый вариант вынужден пересчитать все N комментариев в ветке.
Для оптимизации поиска с parent_id конечно же нужен дополнительный индекс по (parent_id, path). При поиске черз file_id и path используется существующий уникальный индекс.
Есть ли тут подвох? Ну конечно, есть. Что если 2 потока параллельно пытаются вставить комментарий, получают один и тот же номер и пытаются сделать вставку? Решение известно - блокировки, они бывают 2 видов ( https://ru.wikipedia.org/wiki/Блокировка_(СУБД) ):
- пессимистичная - на время транзакции эксклюзивно блокируем последний комментарий в ветке через SELECT FOR UPDATE
- оптимичтиная - не блокируем, пробуем вставить, а если получим ошибку уникальности ключа (то есть второй поток успел занять новый идентификатор пути), делаем небольшую паузу и повторяем попытку заново (вычисляя новый путь)
Эта важная тема, надо бы чтобы ты в ней разобрался. Вот старая паста: http://pastebin.ru/JKLyrQYw
То есть ты должен понимать:
- какие проблемы возникают когда мы делаем несколько запросов подряд на изменение данных или получение + измненеие данных. Что меняется если у нас много процессов которые работают с базой данных параллельно
- какие из проблем решают транзакции, а какие блокировки
- какие бывают виды блокировок
- как их реализовать
- что из написанного выше применимо к нашей задаче вставки комментариев
Проанализируй свой текущий код и попробуй определить какие в нем есть проблемы.
Кстати ты знаешь, как протестировать что проблем с параллельной вставкой комментариев нет?
> Способ порядкового номера среди братьев мне нравится, это в теории убирает id комментария из его matpath, но тут у меня возникают две проблемы:
> по какой колонке в этом случае сортировать?
По path
> Как сделать такую вставку одним INSERT
предварительный select + за ним insert
> Тут целых три запроса, и оно работает, но как это потом выбирать я не знаю. Может быть я что-то не так понял.
Лучше делать отдельными запросами
> У меня сначала деревья были отдельной структурой, потом я это переделал, потому что проблем от этого было больше чем пользы.
Ну смотри, вот завтра ты захочешь сделать функцию выборки одного комментария по id. Что у него будет в getChild() ? Привязывая дерево к модели коммента, ты не даешь возможности выбирать комменатрии без учета древовидности.
>>Ой, что это? serviceLocator вместо dependency injection. Заметь что здесь твой тест опирается на предположение что валидатору нужны ровно 3 зависимости.
> А как по другому протестировать валидацию?
Нет, проблема в том что там не соблюдается принцип DI. Надо передавать в конструктор зависимости, а не сам контейнер. Перечитай пасту по DI.
> Я не очень хочу делать свой объект для перевода, потому что тогда получить строки из файлов шаблонов будет проблематично.
Тогда придется укладываться в ограничения твига.
> Плюс мне не нравится то, что нужно будет объект передавать в каждый вью,
Можно передать как глобальную переменную в начале. Во втором слиме была возможность сделать $slim->view->set(...) или как-то так.
>Только вот такие сложные вещи лучше выносить в сервис так как модель юзера обычно не имеет доступа к логам, базам и тд.
В этом месте я бы поспорил...
Вот смотри. К примеру у нас проект гигантского размера, над которым работало 40 рыл кодеров на протяжении пары лет. В таком проекте обычно тысячи классов, типа что-то-там-Service, которые делают... да всё короче делают.
Вот я очередной бедняга на этом проекте. Мне нужно сделать обычного юзера - премиальным.
Где я буду искать метод, среди тысяч классов, который мне это сделает? Ответ очевиден, вначале я посмотрю на класс юзера. И если вдруг там не найду - то мне придется рыскать по другим тысячам классов. Хорошо если сервис, отвечающий за это назван нормально? А если нет??...
Короче. Доменная логика должна быть сосредоточена в модели, к которой она относится. Если логика сложная, то она должна быть инкапсулирована в команду. Но в модели всё равно должен быть метод, который эту команду принимает и вызывает.
Иначе шансы, что среди тысяч классов я не смогу найти нужный, и напишу свой аналогичный (делающий юзера премиумным) - процентов 50%. А к чему ведёт дублирование кода - ты знаешь.
Выглядеть это должно примерно так:
Class User {
public function makePremium(MakeUserPremiumCommand $command)
{
return $command->execute($this);
}
}
Ну а внутри команды - там код, где и манипуляция с юзером, рассылка писем, логами, внешними АПИ и бог знает что ещё.
А раз ты парсингом увлекся, не хочешь написать парсер и свой движок регулярных выражений? Это минимум месяца два голову ломать можно. Или например сделать интерпретатор подмножества яваскрипта (то есть только части синтаксиса). Или интерпретатор лиспа (ну, это конечно самая простая из трех задач будет, это на пару недель всего).
https://github.com/applejacky/arithmetic_expression_calculator/tree/master/Classes
Многовато классов, надо разбивать на папки и неймспесы. Например все токены поместить в отдельный неймспейс.
В лексере проблема - это интерпретация знаков "минус". -1 - это "минус один" или операция "отрицание" примененная к числу один?
Также твой лексер не ловит ошибочные символы. Достаточно дописать
|.
В конец регулярки и он начнет их ловить.
Твой лексер не поточный. Тут это не принципиально, но поточные лексеры, которые двигаются по одной лексеме за раз, потребляют меньше памяти и их сложнее писать (тут можно было бы задействовать генераторы).
Лексер и токенайзер - по моему одно и то же. Наверно можно было обойтись одним классом.
Ты парсишь выражение в RPN но не удобнее ли сразу строить дерево AST ? Вот тут например есть даже примеры с кодом: https://moodle.vsu.ru/pluginfile.php?file=/80770/mod_resource/content/1/Основы синтаксического разбора.pdf
Но там используется рекурсивный спуск, то есть приоритеты операций зафиксированы в коде и много однотипного кода. Если бы твой алгоритм как-то с тем совместить, чтобы сравнивались приоритеты, но строилось бы не RPN а AST. Разве невозможно?
Вот тут какие-то алгоритмы есть: http://algolist.manual.ru/syntax/parsear.php - не подходят?
А, хотя ладно, AST при желании можно построить из RPN но это скорее будет лишний шаг.
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/ShuntingYard.php#L8
Тут мне кажется стеки незачем передавать как зависимости. У тебя нет необходимости их подменять на что-то, это просто коллекции с данными.
> set_exception_handler(function (Exception $e) {
>$e->getMessage();
>$e->getCode();
Зачем это? Это ведь игнорирует любые исключения. Это неправильно. Чтобы ловить исключения, оберни вычисление в try/catch и укажи там свой класс исключений.
Соответственно в тесте лучше писать так:
'1/0' => 'DivideByZeroException',
Вот я попробовал вычислить выражения:
')))' : https://ideone.com/283Htn
'- (- 1)' : https://ideone.com/gkdxNi
'1 2 3': https://ideone.com/Yedp3k - должна быть ошибка
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/ShuntingYard.php#L14
Тут трудно понять логику, нужны комментарии. Нету последнего else { ... }
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/SimpleFraction.php#L17
Вот тут есть подвох. Флоаты в пхп приближенные и хранятся с ограниченной точностью. int ограничен рамками от -2 млрд до +2 млрд на 32-битных системах. Попробуй дробь вроде 0.1111111111111111111111111 - там скорее всего не получится нужное число знаков и потеряется точность (то есть при компиляции программы эта дробь сконвертируется в что-то вроде 0.11111112). Для борьбы с этим есть библиотеки bcmath и GMP.
> list($integerPart, $fractionalPart) = explode('.', (string) $result);
> $valueAsString = sprintf('%s.%s', $integerPart, $fractionalPart);
sprintf("%f", $result). Либо (string)$result. зачем лишние преобразования? И кстати ты учел что результат может получиться в виде 1.2e-20?
В общем то, что касается преобразований строка-число у тебя выглядит очень сомнительно.
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/Substraction.php#L8
Эта функция не очень аккуратно написана. Она меняет знак одного из переданных операндов что неожиданно. Надо создавать новый операнд.
Также, мне кажется что операции вроде вычитания/умножения выгоднее поместить в класс SimpleFraction. Тогда ее можно использовать для вычисления выражений.
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/Power.php#L8
Тут по моему ошибка. Что будет если возвести (9/1) в (1/2) ? Возведение в 1/2 это квадратный корень то есть получается ответ 3.Возведение в нулевую степень должно давать единицу. В единичную степень - возвращает то же число.
Вот первый попавшийся урок: http://www.algebraclass.ru/otricatelnaya-stepen/
А раз ты парсингом увлекся, не хочешь написать парсер и свой движок регулярных выражений? Это минимум месяца два голову ломать можно. Или например сделать интерпретатор подмножества яваскрипта (то есть только части синтаксиса). Или интерпретатор лиспа (ну, это конечно самая простая из трех задач будет, это на пару недель всего).
https://github.com/applejacky/arithmetic_expression_calculator/tree/master/Classes
Многовато классов, надо разбивать на папки и неймспесы. Например все токены поместить в отдельный неймспейс.
В лексере проблема - это интерпретация знаков "минус". -1 - это "минус один" или операция "отрицание" примененная к числу один?
Также твой лексер не ловит ошибочные символы. Достаточно дописать
|.
В конец регулярки и он начнет их ловить.
Твой лексер не поточный. Тут это не принципиально, но поточные лексеры, которые двигаются по одной лексеме за раз, потребляют меньше памяти и их сложнее писать (тут можно было бы задействовать генераторы).
Лексер и токенайзер - по моему одно и то же. Наверно можно было обойтись одним классом.
Ты парсишь выражение в RPN но не удобнее ли сразу строить дерево AST ? Вот тут например есть даже примеры с кодом: https://moodle.vsu.ru/pluginfile.php?file=/80770/mod_resource/content/1/Основы синтаксического разбора.pdf
Но там используется рекурсивный спуск, то есть приоритеты операций зафиксированы в коде и много однотипного кода. Если бы твой алгоритм как-то с тем совместить, чтобы сравнивались приоритеты, но строилось бы не RPN а AST. Разве невозможно?
Вот тут какие-то алгоритмы есть: http://algolist.manual.ru/syntax/parsear.php - не подходят?
А, хотя ладно, AST при желании можно построить из RPN но это скорее будет лишний шаг.
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/ShuntingYard.php#L8
Тут мне кажется стеки незачем передавать как зависимости. У тебя нет необходимости их подменять на что-то, это просто коллекции с данными.
> set_exception_handler(function (Exception $e) {
>$e->getMessage();
>$e->getCode();
Зачем это? Это ведь игнорирует любые исключения. Это неправильно. Чтобы ловить исключения, оберни вычисление в try/catch и укажи там свой класс исключений.
Соответственно в тесте лучше писать так:
'1/0' => 'DivideByZeroException',
Вот я попробовал вычислить выражения:
')))' : https://ideone.com/283Htn
'- (- 1)' : https://ideone.com/gkdxNi
'1 2 3': https://ideone.com/Yedp3k - должна быть ошибка
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/ShuntingYard.php#L14
Тут трудно понять логику, нужны комментарии. Нету последнего else { ... }
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/SimpleFraction.php#L17
Вот тут есть подвох. Флоаты в пхп приближенные и хранятся с ограниченной точностью. int ограничен рамками от -2 млрд до +2 млрд на 32-битных системах. Попробуй дробь вроде 0.1111111111111111111111111 - там скорее всего не получится нужное число знаков и потеряется точность (то есть при компиляции программы эта дробь сконвертируется в что-то вроде 0.11111112). Для борьбы с этим есть библиотеки bcmath и GMP.
> list($integerPart, $fractionalPart) = explode('.', (string) $result);
> $valueAsString = sprintf('%s.%s', $integerPart, $fractionalPart);
sprintf("%f", $result). Либо (string)$result. зачем лишние преобразования? И кстати ты учел что результат может получиться в виде 1.2e-20?
В общем то, что касается преобразований строка-число у тебя выглядит очень сомнительно.
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/Substraction.php#L8
Эта функция не очень аккуратно написана. Она меняет знак одного из переданных операндов что неожиданно. Надо создавать новый операнд.
Также, мне кажется что операции вроде вычитания/умножения выгоднее поместить в класс SimpleFraction. Тогда ее можно использовать для вычисления выражений.
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/Classes/Power.php#L8
Тут по моему ошибка. Что будет если возвести (9/1) в (1/2) ? Возведение в 1/2 это квадратный корень то есть получается ответ 3.Возведение в нулевую степень должно давать единицу. В единичную степень - возвращает то же число.
Вот первый попавшийся урок: http://www.algebraclass.ru/otricatelnaya-stepen/
Если у тебя проект больших размеров и если ты все будешь писать все прямо в User то он тоже станет больших размеров. Нужно поддерживать архитектуру и старший разработчик должен решать эту проблему, спроектировав и описав архитектуру.
Ты пишешь "добавлю в User" но в нормальном проекте с DI в юзере нет объекта для работы с базой данных и выполнять из него запросы ты не можешь.
То что у тебя написано это оправдания плохой культуре разработки.
> Выглядеть это должно примерно так:
> Class User {
> public function makePremium(MakeUserPremiumCommand $command)
Непонятно зачем тогда вообще эта функция. Если у тебя есть Command то проще сделать
$command->execute($user);
Тоесть я смогу например:
Отправить GET методом, например, ?game=start
В коллбэк функции проверить наличие QueryParameters, сохранить их в переменную
И дальше убрать ?game=start из URL (что-нибудь с Request объектом сделать типа header(location:www.game.com/game);
Но в респонс передать эту переменную с QueryParams (или ещё куда)
Эмулияция POST метода получается, только мы не в Request body параметры передаем а в Request header (т.к GET).
Все верно?
Не могу в AMPPS найти командную строку. Вообще, сложный он какой-то, настроек столько.
Ошибка заключалась в том, что там пароль по-умолчанию был. А теперь вообще mysql не запускается.
Поставил Bitnami, он хоть из коробки работает. За разбор спасибо, а то в таких ситуациях чувствуешь себя беспомощной тётей Зиной
Я уверен что можно записать короче, но я не могу понять как, если бы не было пробелов, скобок и -, я бы написал [\d]{10} но это не прокатит. может я что то не знаю или не понял, подскажите. Спасибо.
>корове не рисуются звездочки
Никто не будет здесь ничего угадывать и проставлять за тебя звёздочки, тебя могут просто проигнорить.
Не поленись и залей код на ideone или на regex101 со своей регуляркой, если хочешь, чтобы тебе проще было помочь.
>я хз поч.
Михуй, потому что ты - ньюфаг. Глянь сюда: http://noobtype.ru/wiki/Wakaba_mark
Зачем неймфажишь?
Есть. Для этого тебе нужно будет запустить отдельный демон php-fpm на порту, который отличается от уже запущенного. Потом при создании конфига для vhost ты указываешь тот порт на котором у тебя запущен демон с отдельной версией. Имей ввиду что тебе нужно будет иметь две версии php, которые установлены в разные каталоги и никак между собой не конфликтуют, иначе могут быть проблемы.
Как я понимаю, в apache стоит какое-то кеширование, только как его отключить не знаю
Вообще, это сложный способ. Я бы на твоем месте попробовал сначала Docker или Vagrant.
Сейчас смутно представляю себе что это, времени изучать особо нет. Задача состоит в том чтобы работающий сервер с кучей древних, но используемых по сей день скриптов оставить в нетронутом работоспособном состоянии и параллельно с ними запустить новый приличный проект. Единственная проблема - старье работает на 5.3 и чуть его тронуть, все повалится. Вот и нужно как-то совместно с тем вхостом запустить новый на ~7 версии.
Чуть по другому скажу. Есть метод validate (Foo $foo) и методы checkBla(), checkBlaBla(), в них передавать из основного метода свойства $foo или сам объект $foo?
echo "bla bla $foo bla bla";
или
echo "bla bla {$foo} bla bla";
А то я начал уроки по ссылке из шапки читать, там и так и так делается.
http://ideone.com/rUhZYS
Ну у меня на линуксе был выхлоп в виде кракозябр. Подсказка из мануала:
>Note: str_split() will split into bytes, rather than characters when dealing with a multi-byte encoded string.
+ У ОПа в учебнике есть упоминание о том, как правильно разбивать строку.
Алсо, зачем там array_map, чем foreach не устроил?
Смею только предполагать, но возможно дело в том, что встроенные функции написаны на си и потому работают полюбому быстрее любых ухищрений с форич? Ну а то что ты с колясочными линуксами не справляешься, то эт ты прост неосилятор, азаза.
Алсо, оно же тебе говорит прямым текстом практически, что ты используешь не то, что нужно для кириллицы. Урок ОПа почитай, да.
Например, вот у нас Yii2 (это не суть важно):
$customer = Customer::findOne(123);
$order = new Order();
$order->subtotal = 100;
- и так далее.
Вот как мне в findOne($id) передать из стороннего скрипта переменную?
Прописываю пространства имён, файл связываю - не видит.
Только если определяю в самом контроллере эту $id.
>Если (у пользователя нет куки с токеном) {
> $token = генерируем случайный код;
> сохраняем код в куки пользователю;
А в нашем случае не будет лучше сгенеривировать токент только один раз при залогинивании, и здесь вместо этого вбрасывать исключение?
Под сперму обычно советуют Star UML, но его сейчас воровать нужно. Бери Dia, он бесплатный.
А вообще есть ещё вот такая штука: http://yuml.me/diagram/scruffy/class/samples
Как по мне, то так удобнее и быстрее, чем мышкой.
>>786415
>оно же тебе говорит прямым текстом практически, что ты используешь не то, что нужно для кириллицы.
Да гляди, так тебе интерпретатор об этом и скажет. В следующий раз будь внимателен, ты всё напутал. В моём предыдущем посте написано, что это подсказка, отрывок из мануала, который поможет >>786239-анону решить его проблему.
>>786409
Там проблема с тем, что Юникод для хранения символов использует переменное количество байт, а Windows-1251 - кодировка 8-битная. Функция str_split бъет побайтово. У анона, видимо, винда, поэтому и проблем с работой скрипта нет.
Объясни, какое отношение к этому имеет колясочность дистрибутива линукса?
Что такое сперма?
>>обычно советуют Star UML, но его сейчас воровать нужно
Первый все еще бесплатный http://staruml.sourceforge.net/v1/
Пожалуй с него и начну. Спасибо
>Смею только предполагать, но возможно дело в том, что встроенные функции написаны на си
А foreach на чём? Нужно не гадать, проверять: https://ideone.com/od1muV
>>786326
>>786398
>>786649
>>786691
http://ideone.com/wI8aSz
Есть такой вариант, но до меня, как то не доходит, как его исправить
Почитал про работу транзакций и блокировки, но видимо я чего-то не понимаю. Вот тестировал и попробовал воссоздать в командной строке ситуацию, когда два пользователя одновременно пытаются добавить комментарий.
В двух клиентах psql я начинаю две транзакции, и в одном из них выбираю из таблицы comments строку, которая имеет самый большой matpath в ветке, и блокирую эту строку через SELECT FOR UPDATE. Потом, во втором клиенте делаю то же самое, но так как строка уже заблокирована первой транзакцией, результата я не получаю, все вроде бы работает как должно (пик 1).
Затем, в клиенте который знает максимальный matpath, я добавляю новый комментарий в ветку, соответственно увеличивая максимальный matpath ветки на 1. После добавления комментария, я завершаю транзакцию, и во втором окне, я вижу что запрос который все это время был заблокирован, выбрал комментарий с старым matpath (пик 2).
Почему так происходит? Ведь я закомиттил транзакцию, значит данные должны быть доступны всем. Если после коммита первой транзакции сделать точно такую же выборку еще раз (во второй транзакции) она вернет правильный результат.
В пасте написано
>Пользователь внутри транзакции видит только закоммиченные чужие изменения, а также все свои.
Но почему-то тут SELECT все равно возвращает старые данные. Я предполагаю что это из-за подзапроса, который выбирает максимальный matpath из таблицы
>SELECT MAX(matpath) FROM comments WHERE NOT (parent_id IS NOT NULL) AND file_id = 3)
Так как этот подзапрос ничем не блокируется, то он в самом начале выбирает matpath максимальный на тот момент (004), и после того как основной запрос разблокирован, происходит выборка записи с старым matpath. Так как в запросах типа SELECT FOR UPDATE в постгресе нельзя использовать агрегатные функции, это наталкивает меня на мысль что тут лучше использовать оптимистичные блокировки. Или я что-то не так делаю?
> Почему так происходит? Ведь я закомиттил транзакцию, значит данные должны быть доступны всем. Если после коммита первой транзакции сделать точно такую же выборку еще раз (во второй транзакции) она вернет правильный результат.
Интересный вопрос. Видимо дело в том что выполнение запроса начинается до коммита и после разблокировки продолжается на существовавшем на тот момент "снимке" базы данных. То есть запрос был начат до коммита транзакции и потому он не видит более новые изменения.
Вместо подзапроса лучше наверно писать ORDER BY mpath DESC LIMIT 1
> Так как этот подзапрос ничем не блокируется, то он в самом начале выбирает matpath максимальный на тот момент (004), и после того как основной запрос разблокирован, происходит выборка записи с старым matpath.
Не знаю точно но мне кажется запрос с подзапросом по идее должен выполняться как одно целое. А не так что подзапрос видит базу в другом состоянии.
Вообще SELECT FROM UPDATE рассчитан на случаи когда ты выбираешь запись, что-то с ней делаешь и сохраняешь изменения.
Может блокировать по-другому? Берем блокировку на родительский (или последний, или все в ветке) комментарий, затем отдельным запросом спокойно считаем max path, вставляем комментарий и коммитимся.
Тут правда проблема - что блокировать, если ни одного комментария еще нет? Файл?
Насчет производительности - какой вид блокировок быстрее - я не знаю, надо делать тест на параллельную вставку в N потоков и сравнивать.
Что насчет тестирования? У тебя есть идея как проверить что все нужные блокировки реализованы корректно?
>>781215
>>776762
> W5.1(Циклы и айфон в кредит)
> Исправлено: http://ideone.com/De0c4w
> $paymentTotal += min($creditBalance, $monthlyPayment);
> $creditBalance -= $monthlyPayment;
> $creditBalance = max($creditBalance, 0);
Тут можно было просто сделать
плата = мин(баланс, месячная плата);
....
Ты по моему как-то перестарался, так как при вычитании уходишь в минус. Ну ладно, думаю, идею ты понял, так что давай считать эту задачу полностью решенной.
> W5.2(Циклы и айфон в кредит)
> Исправлено: http://ideone.com/wmLILK
Все верно
> Регулярные выражения (номера телефонов)
> Исправлено: http://ideone.com/JCXwN9
Ок, все верно
> Регулярные выражения (имейлы)
> Исправлено: https://ideone.com/Plrxg7
Ок, хорошо
> Регулярные выражения (правописание)
> Исправлено: https://ideone.com/ZgaGL7
Ок, хотя я бы в правиле про а/но просто поставил бы \b. но перечислить знаки препинания тоже в общем можно.
> Регулярные выражения
> Исправлено: https://ideone.com/FypBqZ
> "rulePattern"=>"/\bзделал\b/ui",
> "rulePattern"=>"/\bзделаю\b/ui",
> "rulePattern"=>"/\bзделан\b/ui",
Это можно объединить вместе, плюс не поддерживаются слова "зделает", "зделанный". Лучше убрать \b справа.
>>781215
>>776762
> W5.1(Циклы и айфон в кредит)
> Исправлено: http://ideone.com/De0c4w
> $paymentTotal += min($creditBalance, $monthlyPayment);
> $creditBalance -= $monthlyPayment;
> $creditBalance = max($creditBalance, 0);
Тут можно было просто сделать
плата = мин(баланс, месячная плата);
....
Ты по моему как-то перестарался, так как при вычитании уходишь в минус. Ну ладно, думаю, идею ты понял, так что давай считать эту задачу полностью решенной.
> W5.2(Циклы и айфон в кредит)
> Исправлено: http://ideone.com/wmLILK
Все верно
> Регулярные выражения (номера телефонов)
> Исправлено: http://ideone.com/JCXwN9
Ок, все верно
> Регулярные выражения (имейлы)
> Исправлено: https://ideone.com/Plrxg7
Ок, хорошо
> Регулярные выражения (правописание)
> Исправлено: https://ideone.com/ZgaGL7
Ок, хотя я бы в правиле про а/но просто поставил бы \b. но перечислить знаки препинания тоже в общем можно.
> Регулярные выражения
> Исправлено: https://ideone.com/FypBqZ
> "rulePattern"=>"/\bзделал\b/ui",
> "rulePattern"=>"/\bзделаю\b/ui",
> "rulePattern"=>"/\bзделан\b/ui",
Это можно объединить вместе, плюс не поддерживаются слова "зделает", "зделанный". Лучше убрать \b справа.
>Может блокировать по-другому? Берем блокировку на родительский (или последний, или все в ветке) комментарий, затем отдельным запросом спокойно считаем max path, вставляем комментарий и коммитимся.
Так работает, только получается 3 запроса на одну вставку комментария. Не слишком ли это много?
>Тут правда проблема - что блокировать, если ни одного комментария еще нет? Файл?
А в таком случае запросов будет уже 4.
>Что насчет тестирования? У тебя есть идея как проверить что все нужные блокировки реализованы корректно?
У меня есть два варианта, и для обоих нужна поддержка многопоточности.
1. Запустить два потока для добавления комментария, получить результат, сравнить что matpath одного и второго комментария не равны друг другу.
2. Запустить два потока для добавления, сделать так чтобы каждый из них задержал выполнение скрипта на n секунд. Таким образом, если блокировки работают правильно, один поток должен иметь время выполнения в два раза больше чем n. Насчет этого способа я не уверен, но можно попробовать применить функцию sleep() http://php.net/manual/en/function.sleep.php
Это просто предположения, я раньше ничего многопоточного на PHP не делал, но реализации нескольких потоков можно взять вот это https://github.com/krakjoe/pthreads например.
А еще мне кажется что я придумал какие-то велосипеды и там есть способ попроще.
Открыол документацию симфони, ларавель, йии - там блять всё по-разному совершенно и нахуй не нужны ваши эти велосипеды самописы.
Какой профит возится с самописным говном, когда везде всё другое и ради чего? Чтобы иметь свой кривопис на гитхабе?
Родина дала им фреймворки. Бери, делай что угодно.
Не хочу, хочу жрать говно.
уже написал когда заметил, что предлагается юзать фреймворки, ну да похуй, пусть будет
Делай TestHub на Symfony.
>> if ($registerStudentForm->getPassword() != "") {
>> $registerStudentForm->setStudentPassword();
>Вообще, это можно было бы делать в классе формы в методе fillDataFromArray
Эта проверка делается для того чтобы понять обновлять кукисы или нет. Можно ли обновлять их в любом случае, независимо от того меняем мы пароль или нет?
$boss->addEmployee(Employee::recruit ("Игорь");
Какие подводные камни?
Это вродь какой-то общепринятый паттерн, попробуй в гугле singleton и factory method
Ну погугли "PHP recursive directory path", неужели так сложно?
Вторая ссылка как раз ведёт на мануал.
Итератор этот находил, но чтоб наверняка здесь решил спросить, спасибо.
> Так работает, только получается 3 запроса на одну вставку комментария. Не слишком ли это много?
Либо 3 запроса, либо оптимистичная блокировка.
> и для обоих нужна поддержка многопоточности.
Не нужна. Ты можешь запускать несколько процессов, а не потоков, то есть выполнять команды вроде
exec('php some-script.php 1 &');
Вообще конечно через exec что-то запускать не лучшая идея, так как он плохо логгирует ошибки, но для простого тестового скрипта сгодится (а для нормальных приложений подойдет библиотека вроде Symfony Process).
То есть можно сделать такой bash-скрипт и запускать его:
php script.php 1 &
php script.php 2 &
# ждать завершения фоновых процессов
wait
И получается сценарий тестирования такой:
- запускаем N потоков, непрерывно вставляющих комментарии, например с увеличивающимися числами
- дожидаемся их завершения
- пересчитываем комментарии и проверяем что числа идут в правильной последовательности, без пропусков и повторов
Прогнав скрипт на большом числе комментариев, можно убедиться что многопоточная вставка работает корректно.
>>787499
Как ты в фреймворках будешь разбираться не зная основ? Они не для начинающих.
>>787554
Можно узнавать у формы, введен ли пароль, если да то обновлять куки. И можно оставить как сделано у тебя, обновления пароля вне формы.
>>787802
Чем это лучше конструктора? Это называется статический конструктор, и он используется когда надо сделать еще один конструктор, но с другим набором аргументов.
>>788107
рекурсивный итератор
> Так работает, только получается 3 запроса на одну вставку комментария. Не слишком ли это много?
Либо 3 запроса, либо оптимистичная блокировка.
> и для обоих нужна поддержка многопоточности.
Не нужна. Ты можешь запускать несколько процессов, а не потоков, то есть выполнять команды вроде
exec('php some-script.php 1 &');
Вообще конечно через exec что-то запускать не лучшая идея, так как он плохо логгирует ошибки, но для простого тестового скрипта сгодится (а для нормальных приложений подойдет библиотека вроде Symfony Process).
То есть можно сделать такой bash-скрипт и запускать его:
php script.php 1 &
php script.php 2 &
# ждать завершения фоновых процессов
wait
И получается сценарий тестирования такой:
- запускаем N потоков, непрерывно вставляющих комментарии, например с увеличивающимися числами
- дожидаемся их завершения
- пересчитываем комментарии и проверяем что числа идут в правильной последовательности, без пропусков и повторов
Прогнав скрипт на большом числе комментариев, можно убедиться что многопоточная вставка работает корректно.
>>787499
Как ты в фреймворках будешь разбираться не зная основ? Они не для начинающих.
>>787554
Можно узнавать у формы, введен ли пароль, если да то обновлять куки. И можно оставить как сделано у тебя, обновления пароля вне формы.
>>787802
Чем это лучше конструктора? Это называется статический конструктор, и он используется когда надо сделать еще один конструктор, но с другим набором аргументов.
>>788107
рекурсивный итератор
Сначала выучи РНР, дальше почувствуешь, что нужно.
И дальше будет уже проще намного.
PHP+SQL+HTML+CSS+Javascript - для начала.
Разобрался.
Токены нужны чтобы не было возможности отправлять формы с чужого сайта которые доступны даже для не зарегистрированных пользователей.
Как давно занимаешься изучением погромирования? Как и откуда узнал об этом треде?
Расскажи, не стесняйся, здесь все свои, а я просто собираю статистику.
Традиция всех последних тредов 1000+ постов.
Я не только читал, но и всё абсолютно повторял за Никсоном, даже финальную гадость без шаблона.
Очень качественная книга для новичка.
Там объясняется и демонстрируется куча такого, о чём ОП не особо плавно рассказывает в своём учебнике.
Но рекомендую сначала разобрать учебник ОПа до ООП, а потом ещё раз закрепить Никсоном, как раз подобраться к MySQL.
Правда, я сразу ставил себе РНР7, а не РНР5, как у него, - пришлось додумывать, как некоторые функции по-другому писать (mysqli вместо mysql и ещё немного других).
Ты не ответил на вопрос: откуда узнал о треде, что подвигло заняться программированием?
Зачем? Наоборот, когда в треде 500+ постов, в нём, в общем случае, нет случайно залетных с вопросами как под копирку. Почитай первые 200 постов треда - просто обсуждение ни о чём.
>>787499
Фреймворк - не панацея, он не научит тебя писать хороший код.
В этом треде есть пост: >>775454
Обрати внимание на строки
>достался проект системы электронного документооборота на PHP+Symfony2, но при этом с процедурным кодом внутри (всё свалено в огромные классы с иманами что-то-там-Serivce, где по 20-30 публичных методов, в каждом из которых по 50-400 строк кода. Простыни по 4 экрана в среднем...).
Ещё я помню статью на хабре, туториал по созданию блога на Symfony. Так там автор вместо того, чтобы использовать связь M:M для постов и тегов ( воспользовавшись богатыми возможностями ORM), предпочёл хранить список тегов сплошной строкой в одной колонке! Это ведь даже первой нормальной форме не соответствует, не соблюдается атомарность значений.
Мне велосипедироание студентов очень помогло, я рад, что отложил фреймворки на время, с которыми работал как с чёрной коробкой. Теперь они гораздо понятней. В конце концов, тебя никто ничего не заставляет делать. Тебе дали интересные задачки, нет, не хочу, буду крудить на фреймворках, копируя бездумно код из документации, а потом сосну, когда предложат сделать TestHub.
нужно обойти два массива, один с вариантами хода, другой с глупыми собаками, и исключить из первого соседние с собакой варианты хода.
Сравниваю координаты ходов и собаки, и если модуль разницы обоих координат <= 1 то такие ходы соседние с собакой и их нужно исключить.
Зачем колбек-функции возвращать три аргумента -1 0 1? Просто 0 не достаточно, показать что значения в массивах одинаковы?
Код на пике
ОП, успокой меня. Я сейчас пошёл на hh.ru, на moikrug.ru, я смотрю вакансии и тихо охуеваю. По python, ruby, node.js не так уж мало вакансий и там есть реальные предложения за 200+к в месяц. Для php даже в вакансиях, где перечислены вообще все известные эйчару слова, в основном порог в 150. А выше идет какая-то совсем муть и почти что нет вариантов. Почему так и все ли так плохо? PHP оплачивается настолько хуже, чем другие web-языки? Это ведь еще с учетом того, что когда в вакансии написано RoR, то там и будет, скорее всего, RoR, а когда в вакансии написано PHP, там будет php, symphony, html, css, javascript (amber, backbone, angular), mysql, mongodb, apache hadoop, sas, less, bootstrap, wordpress, bitrix и стометровка за 5 секунд.
Потому что куча спроса.
Спрос делает предложение более вялым.
Не ты, так куча других РНРшников.
Я не ОП, меня такие ваши заявления раздражают только.
Родина дала им знание РНР и всего сопутствующего. Не хочу делать свой проект, хочу работать на дядю и чистить вилкой за кем-нибудь код во всякой мути...
> Это ведь еще с учетом того, что когда в вакансии написано RoR, то там и будет, скорее всего, RoR, а когда в вакансии написано PHP, там будет php, symphony, html, css, javascript (amber, backbone, angular), mysql, mongodb, apache hadoop, sas, less, bootstrap, wordpress, bitrix и стометровка за 5 секунд.
Ты думаешь если ты рубист, то тебя никто фронтэнд делать не заставит? Это от места работы зависит, есть компании которые в требованиях пишут что нужно знать PHP, а на деле ты будешь и сервера настраивать, и интерфейсы рисовать, и бэкэнд делать. На других языках то же самое, такие обнаглевшие шараги везде есть.
Ну едритЪ, как же сделать такое?
Вот у меня есть CRUD на MVC: запускаю test/index, запускается контроллер, который из модели берёт что-то и выводит в этом index.
Как мне дополнительно подставлять ориентиры для этого вывода сторонним скриптом?
Выводится строка по id - как мне менять передаваемую из модели в контроллер $id, чтобы каждый раз выводимая строка была другой (в соответствии с тем, что там сторонний скрипт подставляет)?
Не знаю поможет ли тебе это или нет, но у нас писали так
site/controller/method/arguments
Как бы выглядел при этом урл ирл воображаемой социалочки
social.net/users/show_user/3
- просим у контроллера показать юзера с id3
social.net/users/show_friends
-показать друзей этого юзера например
далее например есть гет запросы, которые контроллер может сам себе отправить
social.net/users/show_friends?sort=name
-с сортировкой по имени
social.net/users/show_friends?sort=id
-с сортировкой по id
и прочее, надеюсь ты понял любым сторонним скриптом можно было так обращаться к контроллеру и спрашивать что хочешь с него.
ПС. я вообще не шарю о чем ты хочешь узнать, я ракал меня джуном в новео не взяли, просто мне обидно что тебе никто не помогает
Ты хочешь плейсхолдеры сделать что ли?
Допустим чтобы example.com/index.php?id=3 выводила пользователя с ID 3?
Это делается через получение GET переменной, в фреймворках эту переменную обычно хранит в себе класс Request, например вот - http://www.yiiframework.com/doc-2.0/yii-web-request.html
Если не используешь фреймворк, GET переменную можно получить из глобального массива $_GET http://php.net/manual/en/reserved.variables.get.php хотя это не совсем ООП подход.
Этот подход может и годится для разработки прототипа, но в общем он плохой:
- УРЛ могут получаться слишком длинные
- одной странице соответствует бесконечное количество УРЛ:
/users/show_user/3
/users/show_user/3/
/users/show_user/3/some/1
/users/show_user/3/some/2
И тд. Это приводит к тому что ссылки на сайте ставят как попало, и поисковики видят кучу дублирующихся страниц.
Лучше исплоьзовать роутинг который позволяет задавать произвольные УРЛ и не позволяет зайти на страницу под другим УРЛ. Например symfony routing
>>788664
> Выводится строка по id - как мне менять передаваемую из модели в контроллер $id, чтобы каждый раз выводимая строка была другой (в соответствии с тем, что там сторонний скрипт подставляет)?
Ты по моему что-то путаешь? Обычно это контроллер передает в модель id записи которая ему нужна, а не модель в контроллер.
>Родина дала им знание РНР и всего сопутствующего. Не хочу делать свой проект, хочу работать на дядю и чистить вилкой за кем-нибудь код во всякой мути...
Вот просто скажи, что может анон такого сделать, чтобы это кому-то надо было и анону что-то приносило? Серьезно, с монетизацией сейчас все итак хуево, а дальше только хуже будет, эпл вон уже в ОС адблок встроила, браузерные игры вымерли как класс.
>>788656
Вот именно, что на PHP их значительно больше.
>Вот просто скажи, что может анон такого сделать, чтобы это кому-то надо было и анону что-то приносило? Серьезно, с монетизацией сейчас все итак хуево, а дальше только хуже будет, эпл вон уже в ОС адблок встроила, браузерные игры вымерли как класс.
Не слышал про такого Гоблина, который сделал аналог от слова "анал" агар.ио - Чашка Петри?
Парнишка аноним, обитает где-то в нашем разделе.
Отлично сейчас зарабатывает на продаже всяких скинов для этих молекул и на рекламе AdSense.
Браузерка.
какой нахер свой проект? Таких стартаперов в москве как неёбаных тараканов, и все сосут, без исключения.
Думаю норм вышло, я сделал запутанней: https://ideone.com/Wkq2Fo
>правильный Front controller
Я разве его обязательно делать? Да и что там может быть неправильного, в твоём случае это будет индексный файл, который обрабатывает все запросы к сайту. Хорошее объяснение FC есть в (не пугайся) доках Symfony: https://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
>>788716
>>788710
Спасибо за помощь, братья и друзья!
Сейчас буду разбираться.
Я пока путаюсь в понятиях, потому что только недавно начал изучать MVC.
Просто так научился делать вывод из БД всей таблицы с помощью модели, контроллера и вида. А вот как сделать динамику и, допустим, вывод попеременно каких-нибудь строк из той же таблицы - не разобрался.
Просто подставив в контроллер id строки - пожалуйста, а вот сторонним скриптом передать не получалось.
Сейчас вникну в ваши советы, ух, как вникну сейчас!..
> для меня муть – это автозагрузка
Я вот так сделал, и это собственно всё.
<?php
spl_autoload_register(function ($class) {
include_once 'classes/' . $class . '.php';
});
складываешь свой файлик с классом в папку classes что бы путь выглядел по типу classes/Yoba.php
и в коде можешь писать теперь $a = new Yoba;
>Ты по моему что-то путаешь? Обычно это контроллер передает в модель id записи которая ему нужна, а не модель в контроллер
Я могу путать.
Но я имею в виду именно следующее: как в контроллер передавать переменную id, которая является primary_key у таблицы? Это нужно, чтобы вытащить строку по этому первичному ключу.
Читаю про плейсхолдеры тут - http://www.yiiframework.com/doc-2.0/yii-web-request.html - не вполне это то, к сожалению. Или я не понимаю опять.
Вот есть у нас, допустим, тест. Каждое отдельное задание содержит вопрос, варианты ответов к нему, подсказку и количество баллов за правильный ответ, а также сам правильный ответ. Все они содержатся в одной строке таблицы.
И вот мне надо, чтобы в контроллер передавался id этой строки, тогда view будет отображать остальные все моменты: вопрос, варианты ответов, подсказку и т.д.
И мне для этого нужно лишь идентификатор строки передать, дальше всё вылетит в браузер.
>Как бы выглядел при этом урл ирл воображаемой социалочки
>social.net/users/show_user/3
>- просим у контроллера показать юзера с id3
Вот так, наверное, возможно, да. Этот id передавать внутрь контроллера же можно как-то через $_GET? А дальше от тех же вопросов переходить по ссылке (там просто id++ в URL будет, например) и так далее, наверное.
Подумаю, раздумаю, спасибо.
Вот это для начала почитай http://php.net/manual/ru/reserved.variables.get.php
В фреймворках там немного по другому реализовано, для начала тебе хватит и $_GET.
Контроллер как раз этим и занимается, что разбирает запрос от пользователя, а потом уже на этой основе что-то ему отдает.
>Этот id передавать внутрь контроллера же можно как-то через $_GET?
Если ссылка будет вида example.com/index.php?id=3 то в скрипте $_GET['id'] будет равно 3.
>Вот так, наверное, возможно, да. Этот id передавать внутрь контроллера же можно как-то через $_GET?
Ну у тебя как контроллеры написаны??? У тебя есть "умненькие урлы"?
Что бы ты мог обращаться к контроллеру через урл?
Не так что бы у тебя всегда было обращение к site/index.php
к site/controller1, site/controller2 и так далее?
Если там у тебя всё очень плохо то просто через get передавай в контроллер нужные тебе переменные
и в контроллере проверяй пришло ли что в $_GET[];
Просто херачить начал кошек-мышек. буду спамить своими неловкими подвижками и спрашивать всё ли я делаю правильно.
Вот что написал за вечер.
Без комментариев правда, но надеюсь опытные поймут что тут и как.
http://ideone.com/DgArvv
У тебя для одних и тех же мышек могут быть разные иконки? Зачем?
То есть, твой код позволяет сделать так:
$cat = new Cat('К');
$mouse = new Mouse('К');
То есть, иконки могут продублироваться.
Думаю, их можно прописывать по умолчанию в свойстве для каждого класса животного. Ну а вообще, смотреть пока нечего, пиши ещё.
Ну да, ты прав, пока нечего. Ведь все проблемы и затупы у меня в голове. Например держать ли в классе животных координаты или только в мире?
Делаю перерывы на покурить/пожрать (а жру я чаще чем в офисе) или прост дух перевести между задачками, залипая в окошко с чашкой чая. Еще бывает нужно ждать пока с клиентом что-то согласуют или например развернут площадку для работы.
Все это время, в отличии от офиса, внезапно не затрекать. Как-то у меня получается что на 8 затреканных часов выходит 11-13 потеряных по факту - в 9 сажусь и ток к 21 вылезаю. В офисе я в лучшем случае фактически отрабатывал часов 6, а с учетом времени на дорогу и собирашки тратил часов 10-11.
Из плюсов - можно пить пиво под конец рабочего дня и не надо ручкаться с коллегами. Это круто.
По мне так это конечно лучше, чем час на дорогу в одну сторону, но 10 часов это конечно пиздец.
Учись оптимизировать процесс забивая хуй на часок другой в середине рабочего дня пока с другой стороны вся описанная тобой вата и прочее. Можно работать час через час например. Ходя в тренажерку или магазин в процессе рабочего дня. Или как там у вас устроено всё? 5 минут не отвечаешь в скайпик и тебя уже штрафуют? Вангую что если реально 12 часов сидеть дома на удаленке то через месяца 3 люто заебет.
Гугли отношения в SQL. Конкретно тебе нужно многие-ко-многим, много сущностей могут иметь много тегов.
>как там у вас устроено всё?
Примерно раз в 10 минут делается скрин экрана. Ну и активность замеряется. Если за 10 минутный промежуток она у тебя нулевая, то выходит проебался.
>Можно работать час через час например.
У меня подкованный тимлид. Знает сколько времени требуется на задачу и уже расписал мое будущее на месяц вперед. Если трачу на задачу больше времени, чем нужно, то обязательно спросит. А там либо подгонит программиста в помощь, либо сверхурочные согласует, либо поставит вопрос о снижении ставки.
>через месяца 3 люто заебет
Тоже так думаю.
Нет, если каждый день практиковаться, то будет всё лучше получаться. Кругом одни, не гении, поверь. Просто тренькаются постоянно в чем-то и поэтому норм тащат.
>>790144
Ну может у тебя прост пока первый месяц не очень получается. А дальше получше будет. Но всё равно надо как-то оптимизировать. Опять же если за еще 1 месяц ничего не изменится, то можешь прямо сказать тимлиду, что рассчитывал на 8 часов работы, а не на 12.
Я примерно так же на собеседовании реализовал друзей в бд, что каждая пара просто была отдельной записью и всё такое. Суть в том, что с точки зрения нормализации это ведь куча лишней инфы и все такое. Ничего лучше не придумали?
Быть гением = иметь внутренний стержень + задрачивать основную область + иметь знания в других областях + укрепление своих слабых сторон.
А, увидел сейчас.
Вот мой вариант: http://ideone.com/sugCcD
Насколько помню сейчас, затратил на него не один час и даже не два.
Но я-то вполне безнадёжен, даже не интересуюсь, насколько.
Поначалу слоупочить в новых для себя областях это более чем нормально.
Не ной, а решай, пробуй, ошибайся, совершенствуйся. Вот, смотри, человек в famous university >= 4 года отбарабанил, а простую задачку решить не может: https://workplace.stackexchange.com/questions/39004/which-weak-algorithmic-strategies-i-have-that-lead-me-to-failing-coding-this-sim
Вот у него всё плохо.
>Вместо include __DIR__ . '/../../templates/registration.phtml'; лучше было бы сделать метод $this->render('templates/registration.phtml')
Если заключить инклуд в стороннюю функцию то в шаблоне становиться нельзя обращаться к переменным в контроллере (к таким как $token, $registerStudentForm). Можно как-нибудь обойтись без передавания этих параметров на вход функции?
Тоже устраиваюсь на удаленку, но я дизайнер. Обдумывал вот этот момент, и пришел к выводу, что если работодатель будет требовать трекать время, то во-первых, рабочий день будет на пару часов длиннее чем в офисе, за счет перерывов на обед, размяться, покурить. А во-вторых, я буду работать столько, сколька за все свои десять лет стажа не работал, ни в офисе, ни на фрилансе. Я всегда для себя трекаю свое время, это позволяет лучше оценитвать свою работу, и отлично помогает в борьбе против прокрастинации, т.к. я зараннее знаю сколько мне потребуется времени на решение конкретной задачи. Так вот в среднем, я работаю три часа в день. Иногда бывает больше два, три подхода по 2 часа, и в такие ддн я реально заебываюсь под вечер. Голова просто перестает соображать, а руки не слушаются. Но работать по 8 часов, каждый день - ты герой, скажу я тебе!
У меня имеется модель с некоторыми свойствами, одно из которых "размер". Оно измеряется в байтах. Контроллер получил модель из базы данных. Теперь следующее. У меня имеется функция берущая на вход int байты и отдающая строку "столько-то мбайт/кбайт/йоттабайт". В контроллере "информация о файле" я перевожу данные в строку и отдаю переменной в шаблон. Но что делать в контроллере "n-ое число последних файлов"? Пробегать по массиву объектов-файлов и ставить в свойство модели "размер" строку "столько-то того-то" чтобы в дальнейшем в шаблоне вызывать это свойство? Или философия MVC допускает то, что в шаблоне в цикле я смогу вызвать мою функцию конвертер для каждого объекта?
Ладно, раз я пришел за советами спрошу еще. Будут ли модели "Картинка", "Видео", "Аудио" наследники модели "Файл"? Или в этой задаче всего одна модель.
Модель - это почти всегда отдельная таблица. Решай сам дальше.
>>790496
Там хватит просто вложенного цикла: https://ideone.com/EFAli4
Ну вот комменатрии "У меня от этого файла брат умер" это я точно понял что будут отдельной моделью и таблицей. А с картинками, например, не понятно. У них наверное будут отличающиеся от других файлов свойства вроде "ширина/длина", т.е. получается тоже отдельно будут. Ладно, решаем дальше.
>Там хватит просто вложенного цикла: https://ideone.com/EFAli4
Сука пиздец блядь сука блядь нахуй у меня пригорело от тебя, какой же я тупой.
Это уже совсем другое (тут уже браузер просто площадка, ничего от форумных срачей и ролевого элемента всяких БК и даже Дваров не осталось и близко) + причем тут пхп?
>>788640
ОП, ответь плиз.
>Это ведь еще с учетом того, что когда в вакансии написано RoR, то там и будет, скорее всего, RoR, а когда в вакансии написано PHP, там будет php, symphony, html, css, javascript (amber, backbone, angular), mysql, mongodb, apache hadoop, sas, less, bootstrap, wordpress, bitrix и стометровка за 5 секунд.
Прочитай первые ~200 постов этого треда. Вот, блин, такой же вопрос задали: >>775493
Никто тебя уговаривать и держать не будет, на чём хочешь зарабатывать - то и учи.
По mime-type.
Его можно получить этой функцией http://php.net/manual/ru/function.mime-content-type.php
Или использовать библиотеку getId3 http://getid3.sourceforge.net/
>>790728
Или еще вот этим можно http://php.net/manual/ru/function.finfo-file.php
Эта функция поновее будет чем mime_content_type
http://ideone.com/z42H7e
Ну да, у тебя вот эта строчка
$creditBalance = ( $creditBalance * $percent ) + $servicePayment;
перед циклоv сначала высчитывает долг, а потом в конце цикла после платежей она же.
http://ideone.com/LcPT7o
Чет я встал на написании функции движения мышки. Весь написанный до этого код под сомнением, что пиздец. Что бы подвинуть мышку, надо ей передать как аргумент мир. Что бы её передвинуть на нем.
Похоже всё придется переделывать. Да и то, что координаты животинки хранятся и в классе животинки и в классе мир как-то неправильно ведь? Надо что бы либо там либо тут?
Ну так перед циклом это строка нужна, чтобы процент за нулевой месяц прибавить. В цикле же я сначала выплачиваю долг, а потом уже прибавляю месячный процент. Если сделать наоборот, то может выйти так, что до проверки условия выхода из цикла сумма долга была меньше чем сумма, которую платит анон(5к в данном случае), а после прибавления процентов она станет больше и за месяц выплатить до конца не удастся, хотя цикл уже завершился. У меня был вариант внутри самого цикла сделать if с проверкой финальной суммы. Тогда бы выглядело красивее и все влезло в цикл, но мне в таком варианте не понравилось, что этот if будет лишним действием, вызываемым на каждой итеррации цикла, хотя по факту он там не нужен.
Я начал студентов с листочка с карандашом. Нарисовал представления, какие должны быть, сразу модули повторяющиеся увидел, а там пошло-поехало.
Че-то github'у плохо и клиент не открывается. А я как раз все правки закончил(
На сервере пхп 5.6
Нет, он не будет вызываться на каждой итерации, но проверяться будет, да.
Я тебе сообщу, когда появится.
https://ideone.com/1sNagN
https://github.com/applejacky/arithmetic_expression_calculator
>Что будет если возвести (9/1) в (1/2) ? Возведение в 1/2 это квадратный корень то есть получается ответ 3
Я гуглил, но не нашёл функции для нахождения корня n-ной степени. Везде советуют использовать pow(основание_степени, 1/показатель_степени). Проблема в том, что возводить в дробную степень может только функция pow, bcpow и gmp_pow не могут: https://ideone.com/miPWb3
Всякие матановые способы нахождения корня n-ной степени я не осилю. Пример с 9^1/2 теперь работает, но пришлось использовать pow.
Вообще с числами с произвольной точностью появились проблемы, которые просто ставят меня в тупик.
К примеру, я хочу посчитать сумму '0.111111111111111111112' и '0.22222222222222222222'. Сама функция bcadd считает её нормально, но в калькуляторе мне нужно каждое из этих чисел перевести в простые дроби, так как все операции у нас проходят над простыми дробями. Для этого нужно найти НОК. То есть для первой дроби мне нужно умножать 111111111111111111112 на 1000000000000000000000. Даже ideone не выдержал, выплюнув Time limit exceeded (пик 1), при том, что сложные расчёты на нём происходят в несколько десятков раз быстрее, чем на моём ноуте. Нижний Success относится к ситуации, когда я пытался найти НОК для 2 и 100..(много нулей), сама функция нахождения НОК работает правильно: https://ideone.com/TmuS8l
>Ты парсишь выражение в RPN но не удобнее ли сразу строить дерево AST ?
Было проще почитать статью про алгоритм сортировочной станции на вики и облечь псевдокод в код, чем читать талмуд вроде: https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
Теперь я понимаю, что нужно было сразу браться за AST с грамматиками, причины описаны ниже. Однако всё же хотелось бы сделать задачу 2-я способами. Но и браться за один способ, не доделав другой, не хочется.
>И кстати ты учел что результат может получиться в виде 1.2e-20?
Изменил трюки с explode('.', $foo) на трюки с bcdiv и floatval, теперь экспонента появляться не должна: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/SimpleFraction.php#L59
>В общем то, что касается преобразований строка-число у тебя выглядит очень сомнительно.
Попробовал ещё использовать вместо регулярок функцию sscanf здесь: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/SimpleFraction.php#L21
Но эта функция основана на доступных типах данных, поэтому не годится для чисел с произвольным количеством цифр (пик 2).
>В лексере проблема - это интерпретация знаков "минус". -1 - это "минус один" или операция "отрицание" примененная к числу один?
Да, я погуглил насчёт унарных операторов в RPN и понял, что эта нотация не умеет отличать унарный плюс/минус от бинарного: http://wcipeg.com/wiki/Shunting_yard_algorithm#Unary_operators
Там советуют использовать отдельные знаки для унарных + и -, например # и $, для этого нужно модифицировать алгоритм распределяющей шляп сортировочной станции. Так пока что и сделал.
Ещё я вижу очень запутанный способ решения без необходимости вводить новые знаки - на этапе парсинга инфиксного выражения заменять конструкции вида -3 на (0-3), сделав минус/плюс только бинарными. Но что делать с выражением вида -(3+((+2)+2))?
Находим унарный оператор (на основе соседних символов), в данном случае это будет минус, он матчится в $1, находим его операнд, в данном случае это будет выражение (3+((+2)+2)), оно матчится в $2, заменяем всё выражение на (0 $1 $2). И тут, наверное, без рекурсии не обойтись.
Сам операнд унарного оператора нельзя просто заматчить регуляркой, так как неизвестно с какой глубиной скобочек он будет.
В общем, если я и смогу реализовать такой ужасный способ, то понятен он, наверное, будет только мне.
>Твой лексер не поточный.
Не нагуглил, что это. Как он бинарный от унарного минуса отличает, если двигается только по лексеме за раз? Чувствую, что нужно просто полностью ознакомится с содержанием ссылок, которыми ты со мной поделился.
Насчёт генераторов, то для PHP я нашёл только сомнительные проекты с устаревшим кодом лет на 5-10 и без документации.
>Также, мне кажется что операции вроде вычитания/умножения выгоднее поместить в класс SimpleFraction. Тогда ее можно использовать для вычисления выражений.
То есть, чтобы была возможность сделать $fraction1->add($fraction2)?
У меня сейчас и так куча операторов/операций, да и класс SimpleFraction немаленький. Распределяя ответственности, исходил из того, что оператор оперирует операндами, используя операцию.
> Вот я попробовал вычислить выражения:
> ')))' : https://ideone.com/283Htn
> '- (- 1)' : https://ideone.com/gkdxNi
> '1 2 3': https://ideone.com/Yedp3k - должна быть ошибка
Там заглушка с неменяющимся true стояла. На основе выражений выше попробовал сформулировать требования к валидному инфиксному выражению:
- Все скобочки должны быть закрыты: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L29
- Чисел должно быть >= 1: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L44
- Количество бинарных операторов должно быть на один меньше, чем количество чисел: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L54
- унарный оператор должен быть предварён знаком (, или быть в начале строки: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L59
- Должны использоваться только операторы +-*/()#$, числа вида \d+(\.d+)? : https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L13
Ещё я сделал try/catch на уровне вычисления RPN, это позволяет в случае возникновения исключения просто переходить к вычислению следующего инфиксного выражения (чтобы не создавать на каждое выброшенное исключения отдельную ссылку на ideone).
> Тут трудно понять логику, нужны комментарии.
Так и не понял, где там комментарии помогут, код старался сделать максимально похожим на псевдокод здесь: https://en.wikipedia.org/wiki/Shunting-yard_algorithm#The_algorithm_in_detail
За исключением того, что проверки скобочек вынесены в лексер.
Ещё я несколько дней пытался отлепить знак дроби от числителя и знаменателя, чтобы передавать знак дроби через конструктор, а в числителе и знаменателе держать только абсолютные значения. Даже подумал, что операцию смены знака можно лаконично сделать с помощью оператора XOR вот так: public function changeSign() { $this->sign ^= true; }
Не это потребовало огромных правок в методах классов Addition, Power и прочих, так как определять знак результата операции теперь предстояло мне, а не PHP, поэтому я отбросил эту идею.
>Лексер и токенайзер - по моему одно и то же. Наверно можно было обойтись одним классом.
Лексер возвращает массив вида ['2', '+', '3'], токенайзер - [object SimpleFraction, object Addition, object SimpleFraction]. Удобно для тестов, потом солью в один класс Parser.
>не хочешь написать парсер и свой движок регулярных выражений? Это минимум месяца два голову ломать можно
Regex-движок звучит пугающе. Я в любом случае хотел за SICP когда-нибудь сесть, там, вроде бы, как раз интерпретатор Lisp'а по ходу дела пишется. Но максимум, на что я расчитывал - прорешать хотя бы треть задачек оттуда, так как она (опять же, по слухам) перенасыщена задачами. Посмотрю, если SICP зайдёт, то возьмусь за что-нибудь из предложенного тобой.
Времени достаточно, меня ещё 2 года будет универ содержать, выходить на работу нет необходимости.
Пойду изучать AST/Recursive descent и пробовать применять его на калькуляторе.
https://ideone.com/1sNagN
https://github.com/applejacky/arithmetic_expression_calculator
>Что будет если возвести (9/1) в (1/2) ? Возведение в 1/2 это квадратный корень то есть получается ответ 3
Я гуглил, но не нашёл функции для нахождения корня n-ной степени. Везде советуют использовать pow(основание_степени, 1/показатель_степени). Проблема в том, что возводить в дробную степень может только функция pow, bcpow и gmp_pow не могут: https://ideone.com/miPWb3
Всякие матановые способы нахождения корня n-ной степени я не осилю. Пример с 9^1/2 теперь работает, но пришлось использовать pow.
Вообще с числами с произвольной точностью появились проблемы, которые просто ставят меня в тупик.
К примеру, я хочу посчитать сумму '0.111111111111111111112' и '0.22222222222222222222'. Сама функция bcadd считает её нормально, но в калькуляторе мне нужно каждое из этих чисел перевести в простые дроби, так как все операции у нас проходят над простыми дробями. Для этого нужно найти НОК. То есть для первой дроби мне нужно умножать 111111111111111111112 на 1000000000000000000000. Даже ideone не выдержал, выплюнув Time limit exceeded (пик 1), при том, что сложные расчёты на нём происходят в несколько десятков раз быстрее, чем на моём ноуте. Нижний Success относится к ситуации, когда я пытался найти НОК для 2 и 100..(много нулей), сама функция нахождения НОК работает правильно: https://ideone.com/TmuS8l
>Ты парсишь выражение в RPN но не удобнее ли сразу строить дерево AST ?
Было проще почитать статью про алгоритм сортировочной станции на вики и облечь псевдокод в код, чем читать талмуд вроде: https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
Теперь я понимаю, что нужно было сразу браться за AST с грамматиками, причины описаны ниже. Однако всё же хотелось бы сделать задачу 2-я способами. Но и браться за один способ, не доделав другой, не хочется.
>И кстати ты учел что результат может получиться в виде 1.2e-20?
Изменил трюки с explode('.', $foo) на трюки с bcdiv и floatval, теперь экспонента появляться не должна: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/SimpleFraction.php#L59
>В общем то, что касается преобразований строка-число у тебя выглядит очень сомнительно.
Попробовал ещё использовать вместо регулярок функцию sscanf здесь: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/SimpleFraction.php#L21
Но эта функция основана на доступных типах данных, поэтому не годится для чисел с произвольным количеством цифр (пик 2).
>В лексере проблема - это интерпретация знаков "минус". -1 - это "минус один" или операция "отрицание" примененная к числу один?
Да, я погуглил насчёт унарных операторов в RPN и понял, что эта нотация не умеет отличать унарный плюс/минус от бинарного: http://wcipeg.com/wiki/Shunting_yard_algorithm#Unary_operators
Там советуют использовать отдельные знаки для унарных + и -, например # и $, для этого нужно модифицировать алгоритм распределяющей шляп сортировочной станции. Так пока что и сделал.
Ещё я вижу очень запутанный способ решения без необходимости вводить новые знаки - на этапе парсинга инфиксного выражения заменять конструкции вида -3 на (0-3), сделав минус/плюс только бинарными. Но что делать с выражением вида -(3+((+2)+2))?
Находим унарный оператор (на основе соседних символов), в данном случае это будет минус, он матчится в $1, находим его операнд, в данном случае это будет выражение (3+((+2)+2)), оно матчится в $2, заменяем всё выражение на (0 $1 $2). И тут, наверное, без рекурсии не обойтись.
Сам операнд унарного оператора нельзя просто заматчить регуляркой, так как неизвестно с какой глубиной скобочек он будет.
В общем, если я и смогу реализовать такой ужасный способ, то понятен он, наверное, будет только мне.
>Твой лексер не поточный.
Не нагуглил, что это. Как он бинарный от унарного минуса отличает, если двигается только по лексеме за раз? Чувствую, что нужно просто полностью ознакомится с содержанием ссылок, которыми ты со мной поделился.
Насчёт генераторов, то для PHP я нашёл только сомнительные проекты с устаревшим кодом лет на 5-10 и без документации.
>Также, мне кажется что операции вроде вычитания/умножения выгоднее поместить в класс SimpleFraction. Тогда ее можно использовать для вычисления выражений.
То есть, чтобы была возможность сделать $fraction1->add($fraction2)?
У меня сейчас и так куча операторов/операций, да и класс SimpleFraction немаленький. Распределяя ответственности, исходил из того, что оператор оперирует операндами, используя операцию.
> Вот я попробовал вычислить выражения:
> ')))' : https://ideone.com/283Htn
> '- (- 1)' : https://ideone.com/gkdxNi
> '1 2 3': https://ideone.com/Yedp3k - должна быть ошибка
Там заглушка с неменяющимся true стояла. На основе выражений выше попробовал сформулировать требования к валидному инфиксному выражению:
- Все скобочки должны быть закрыты: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L29
- Чисел должно быть >= 1: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L44
- Количество бинарных операторов должно быть на один меньше, чем количество чисел: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L54
- унарный оператор должен быть предварён знаком (, или быть в начале строки: https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L59
- Должны использоваться только операторы +-*/()#$, числа вида \d+(\.d+)? : https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/InfixParsing/Lexer.php#L13
Ещё я сделал try/catch на уровне вычисления RPN, это позволяет в случае возникновения исключения просто переходить к вычислению следующего инфиксного выражения (чтобы не создавать на каждое выброшенное исключения отдельную ссылку на ideone).
> Тут трудно понять логику, нужны комментарии.
Так и не понял, где там комментарии помогут, код старался сделать максимально похожим на псевдокод здесь: https://en.wikipedia.org/wiki/Shunting-yard_algorithm#The_algorithm_in_detail
За исключением того, что проверки скобочек вынесены в лексер.
Ещё я несколько дней пытался отлепить знак дроби от числителя и знаменателя, чтобы передавать знак дроби через конструктор, а в числителе и знаменателе держать только абсолютные значения. Даже подумал, что операцию смены знака можно лаконично сделать с помощью оператора XOR вот так: public function changeSign() { $this->sign ^= true; }
Не это потребовало огромных правок в методах классов Addition, Power и прочих, так как определять знак результата операции теперь предстояло мне, а не PHP, поэтому я отбросил эту идею.
>Лексер и токенайзер - по моему одно и то же. Наверно можно было обойтись одним классом.
Лексер возвращает массив вида ['2', '+', '3'], токенайзер - [object SimpleFraction, object Addition, object SimpleFraction]. Удобно для тестов, потом солью в один класс Parser.
>не хочешь написать парсер и свой движок регулярных выражений? Это минимум месяца два голову ломать можно
Regex-движок звучит пугающе. Я в любом случае хотел за SICP когда-нибудь сесть, там, вроде бы, как раз интерпретатор Lisp'а по ходу дела пишется. Но максимум, на что я расчитывал - прорешать хотя бы треть задачек оттуда, так как она (опять же, по слухам) перенасыщена задачами. Посмотрю, если SICP зайдёт, то возьмусь за что-нибудь из предложенного тобой.
Времени достаточно, меня ещё 2 года будет универ содержать, выходить на работу нет необходимости.
Пойду изучать AST/Recursive descent и пробовать применять его на калькуляторе.
https://ideone.com/R5AoPX // Кошки-мышки
Куки, кеш чистил. Что еще сделать можно не знаю
ОП, я готов: https://github.com/TheSidSpears/Students/
На <br> не обращай внимания - когда дойдет до css, тогда формы буду
делать по уму.
Открываю теперь под проксей, а приложение перекачал.
Не ты один такой, ждем.
http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers
Нашел для себя вот это решение. Анончики, а вы тоже в своих IDE пишите для контейнеров
/ @var YourClassType $mailer */
$mailer = $container['mailer'];
каждый раз? Может есть еще альтернативы кроме банального отключения этой валидации в ide?
Так же разобрался с PSR-4, но чё-то не вижу смысла в таком маленьком проекте его использовать
Только что усложнять лапшой
return new Router(); --> return new Project\Classes\Router();
Я так понимаю, если я через композер подключаю сторонние библиотеки и там встретится Router, то он не будет конфликтовать с моим Router, который объявлен без всяких PSR-4. Мне главное самому внутри проекта не плодить одинаково названных классов
>>790577
Для задач подобного рода, как правило, достаточно отследить зависимость между счётчиками циклов и требуемым выводом. Можно на листочке просто расписывать каждую итерацию в стиле "что нужно" => "что имеем". Конкретно в той задаче на каждой итерации вложенного цикла нужно вывести либо звёздочку, либо пробел, а имеем значения 2-х счётчиков и input, определяющий сколько отрабатывать циклам.
Можешь потренироваться на более простых задачах:
1. На ввод подаётся число, к примеру 4, на вывод - рамка квадрата со стороной 4 символа в псевдографике: http://pastebin.com/raw/aaTEgvgU
2. То же самое, только на ввод подаётся нечётное число, на вывод - треугольник.
После этого задача на вывод креста никаких проблем не вызовет.
Алсо, вспомнил о рубисте с большим опытом коммерческой разработки, который месяца 3 назад создавал в /pr тред, где, как и ОП, помогал новичкам вкатиться и делал код-ревью. Предложил пару интересных задачек, которые мы можем и на PHP без проблем делать. Кому интересно: https://gist.github.com/djinn2chhk/d4889f9fbc0ecf1ec7ba
>>791867
Есть сборник задач по HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
После его прохождения верстать сайты-визитки будет несложно.
>>791808
Лапши не будет, если ты будешь использовать короткое имя и use (и вписывать его не руками, а использовать автоматическую вставку use в твоей IDE). Если у тебя 5 классов то да, наверно можно обойтись без неймспейсов, но в реальном приложении их будут сотни и лучше наверно сразу привыкать к неймспейсам.
> Я так понимаю, если я через композер подключаю сторонние библиотеки и там встретится Router, то он не будет конфликтовать с моим Router, который объявлен без всяких PSR-4.
Да, если библиотека современная и использует неймспейсы, то все ее классы будут засунуты в отдельный неймспейс.
>>791698
Проще перенастроить проверяльщик кода. Я не знаком настолько хорошо с пхпсторм, но уверен что там все настраивается.
Идея с @var мне не нравится так как если ты 4 раза получаешь какой-то сервис то 4 раза должен писать @var. Выгоднее бы на самом контейнере 1 раз пометить что это контейнер и он содердит такие-то сервисы.
Тут (по твоей же ссылке) есть такой совет: http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers/6418373#6418373
Там есть вариант с @property, хотя мне не очень нравится что мы делаем лишний класс ради ИДЕ. Ну пустой класс создать недолго, так что это не проблема. Зато сервис достаточно один раз описать.
>>791581
По дизайну - советую не тырить, а изучить возможности бутстрапа и использовать их. Там довольно аккуратные поля форм, верхнее меню, и еще много чего. Если уж тырить то с того же rghost (только без всяких рекламных кнопок).
>>791536
Роскомнадзор буянит.
>>791867
Есть сборник задач по HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
После его прохождения верстать сайты-визитки будет несложно.
>>791808
Лапши не будет, если ты будешь использовать короткое имя и use (и вписывать его не руками, а использовать автоматическую вставку use в твоей IDE). Если у тебя 5 классов то да, наверно можно обойтись без неймспейсов, но в реальном приложении их будут сотни и лучше наверно сразу привыкать к неймспейсам.
> Я так понимаю, если я через композер подключаю сторонние библиотеки и там встретится Router, то он не будет конфликтовать с моим Router, который объявлен без всяких PSR-4.
Да, если библиотека современная и использует неймспейсы, то все ее классы будут засунуты в отдельный неймспейс.
>>791698
Проще перенастроить проверяльщик кода. Я не знаком настолько хорошо с пхпсторм, но уверен что там все настраивается.
Идея с @var мне не нравится так как если ты 4 раза получаешь какой-то сервис то 4 раза должен писать @var. Выгоднее бы на самом контейнере 1 раз пометить что это контейнер и он содердит такие-то сервисы.
Тут (по твоей же ссылке) есть такой совет: http://stackoverflow.com/questions/6395737/how-do-i-make-my-php-ide-understand-dependency-injection-containers/6418373#6418373
Там есть вариант с @property, хотя мне не очень нравится что мы делаем лишний класс ради ИДЕ. Ну пустой класс создать недолго, так что это не проблема. Зато сервис достаточно один раз описать.
>>791581
По дизайну - советую не тырить, а изучить возможности бутстрапа и использовать их. Там довольно аккуратные поля форм, верхнее меню, и еще много чего. Если уж тырить то с того же rghost (только без всяких рекламных кнопок).
>>791536
Роскомнадзор буянит.
переходить можно в любом случае, не надо меня ждать.
В коде везде, где можно, надо бы расставить тайп-хинты.
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ (увы, возможность вернуть null пока не реализовали, так что ждем)
---------
> // Константы
> const cat = 'Cat';
Имена констант пишутся большими буквами. Более того, в твоем случае они не нужны так как имя класса само по себе константа и можно писать Cat::CLASS (это вернет строку 'Cat').
Также, проверить что объект относится к классу X или его наследнику можно через if ($x instanceof X).
> // Счетчик экземпляров класса
> protected static $counter = 1;
Тут правильнее сделать private чтобы не дать возможность потомкам трогать счетчик.
> // Кол-во пропускаемых ходов
> protected $restingTime = 0;
Ты добавляешь это свойство в базовый класс - а это значит что все животные могут пропускать ходы. Но мне кажется, это умеет делать только кошка и потому это должно быть в классе кошки.
> // Координаты ХY
> protected $xy = array();
А почему массив? Почему не 2 поля, x и y? Так и писать будет короче, и логичне по моему.
> if ($weightA==$weightB) return 0;
PSR требует всегда ставить фигурные скобки и писать в 3 строки, привыкай сразу.
> $bestMoveVariantWeight
> $bestMoveVariants
Можно просто $bestVariants и $bestWeight
> // Находим животных в зоне видимости
> protected function getScope($animals)
> protected function getAnimal($animals, $animalType)
Мне кажется это (поиск) логичнее сделать в классе, отвечающем за карту. Каждый класс должен выполнять свою задачу и тут ты это правило явно нарушаешь.
> protected function getDistance($target)
> {
> $target = $target;
Очень полезная команда.
> protected function getWeightsByDirections
Я не очень понимаю, зачем тут косинус. Разве недостаточно расстояния до цели, выраженного в числе ходов?
> protected function removeMoveByAnimals($animals, $moveVariants)
Лучше в классе Карта сделать метод,проверяющий можно ли сходить на клетку.
> protected function getCorners ()
> // Определяем координаты углов
> $fieldSizeX = fieldSize;
Тут ошибка
> public function toDie()
> $this->hp = 0;
> return true;
Стоит добавить комментарий в каких случаях и что вернет функция, что значит false.
> // Игровой ход
> abstract function move($animals, $moveVariants, $corners);
По моему этот метод должен выглядеть так: move(). Найти других животных или углы можно с помощью Карты. Ты не сделал класс Карта, и потому теперь вынужден информацию о животных передавать с помощью кучи массивов в каждую функцию.
> // Оценка ходов
> abstract protected function setRating($animals, $moveVariants, $corners);
Вот мне кажется что из 2 абстрактных методов - setRating и move - один лишний. Я имею в виду, если все животные пользуются алгоритмом оценки хода, то должно быть достаточно функции выбора всех допустимых ходов + setRaing, верно? Для move тогда можно было бы предоставить реализацию по умолчанию в классе Animal. С другой стороны, если мы не хотим заставлять всех пользоваться алгоритмом оценки, достаточно сделать абстрактной только move.
У тебя очень неуклюже получилась генерация допустимых ходов, где генерируются ходы, потом часть из них (диагональные) убираются. По моему проще сделать фукцнию которая сразу вернет список допустимых ходов.
> // Исключение занятых ходов
> abstract protected function removeOccupiedMove($animals, $moveVariants)
Выгоднее сделать метод, возвращающий все допустимые ходы.
> $this->getWeightsByDirections
Тут не get, а set, get-функции обычно ничего не меняют.
> // Трансформирует 3х мышей в мегамышь неуязвимую для кошек
> private function transformMegaMouse ($animals)
Тут не стоит использовать свойство megaMOuse. Ведь его значение устаревает после каждого перемещения любой мыши и легко может оказаться так, что в нем будет неактуальное значение. Лучше не сохранять статус мегамыши, а каждый раз проверять заново.
Для определения расстояния между животными можно было бы сделать статический метод, например Animal::getDistance($a, $b) или Field::getDistance(). Если мы меряем в ходах и расстояние разное для разных видов животных то $a->getDistainceTo($b);
> / Возможность ходить по горизонт, вертикали, диагонали
> public function getMoveAbility()
А как насчет возможности ходить конем? Ты зря так ограничиваешь себя, лучше просто сделать метод возвращающий допустимые ходы.
> // Если в соседней клетке есть мышь, рейтинг = INF
Это не очень удачная идея так как если рядом несколько мышей то ходы к ним получаются равнозначны в твоем алгоритме, но ведь там могут быть и другие факторы.
В проверке на мегамышь, что происходит если кошка пытается ее съесть, но не может? Кошка встает на ее клетку? Но она не должна это делать.
> $moveVariants = array_map(function ($moveVariant) {
Тут подошел бы простой цикл. Если ты меняешь объект в массиве то тебе не надо создавать новый массив с измененными объектами и записывать его обратно в переменную, так как объекты меняются и в исходном массиве.
В классе Animals нет проверки на генерацию не повторяющихся координат. Название класса плохое.
> // Фабрика ВариантовXода
> static public function createMoveVariants ($animal)
Мне кажется это лучше поместить в Animal. Почему? Потому что в этом случае зависимость будет однонаправленная: классу Animal нужен класс MoveVariant, а MV ничего не знает об A. Как-то более аккуратно получается.
> do {
> $start['y'] = $animalXY['y']-$animalSpeed;
> $animalSpeed--;
Не лучше ли использовать for ($i от 1 до animalSpeed) ?
> // Класс Вектор
> class Vector
Вот это вот самый нелогичный класс тут. Как представить вектор? Классический способ - это 2 числа, x и y. Зачем тут свойство $zero котороу избыточно (без него легко обойтись)?
Логично ждать и конструктор, принимающий 2 координаты. А конструктор, считающий вектор между 2 точками, сделать статическим методом.
> if ((is_int($startXY) && is_int($endXY)) |
> } else if (is_array($startXY) && is_array($endXY)) {
Такие вещи сильно запутывают код. Аргументы должны иметь четко определенный тип, иначе ты вынужден вокруг каждой строчки писать сторожевой иф.
В твоем случае надо сделать несколько статических конструткоров.
> public function getAngle($vector1, $vector2)
Это судя по всему статическая функция, так как она не испоьзует поля текущего объекта.
> class Corner
Название плохое, можно подумать что это объект представляющий один угол.
переходить можно в любом случае, не надо меня ждать.
В коде везде, где можно, надо бы расставить тайп-хинты.
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ (увы, возможность вернуть null пока не реализовали, так что ждем)
---------
> // Константы
> const cat = 'Cat';
Имена констант пишутся большими буквами. Более того, в твоем случае они не нужны так как имя класса само по себе константа и можно писать Cat::CLASS (это вернет строку 'Cat').
Также, проверить что объект относится к классу X или его наследнику можно через if ($x instanceof X).
> // Счетчик экземпляров класса
> protected static $counter = 1;
Тут правильнее сделать private чтобы не дать возможность потомкам трогать счетчик.
> // Кол-во пропускаемых ходов
> protected $restingTime = 0;
Ты добавляешь это свойство в базовый класс - а это значит что все животные могут пропускать ходы. Но мне кажется, это умеет делать только кошка и потому это должно быть в классе кошки.
> // Координаты ХY
> protected $xy = array();
А почему массив? Почему не 2 поля, x и y? Так и писать будет короче, и логичне по моему.
> if ($weightA==$weightB) return 0;
PSR требует всегда ставить фигурные скобки и писать в 3 строки, привыкай сразу.
> $bestMoveVariantWeight
> $bestMoveVariants
Можно просто $bestVariants и $bestWeight
> // Находим животных в зоне видимости
> protected function getScope($animals)
> protected function getAnimal($animals, $animalType)
Мне кажется это (поиск) логичнее сделать в классе, отвечающем за карту. Каждый класс должен выполнять свою задачу и тут ты это правило явно нарушаешь.
> protected function getDistance($target)
> {
> $target = $target;
Очень полезная команда.
> protected function getWeightsByDirections
Я не очень понимаю, зачем тут косинус. Разве недостаточно расстояния до цели, выраженного в числе ходов?
> protected function removeMoveByAnimals($animals, $moveVariants)
Лучше в классе Карта сделать метод,проверяющий можно ли сходить на клетку.
> protected function getCorners ()
> // Определяем координаты углов
> $fieldSizeX = fieldSize;
Тут ошибка
> public function toDie()
> $this->hp = 0;
> return true;
Стоит добавить комментарий в каких случаях и что вернет функция, что значит false.
> // Игровой ход
> abstract function move($animals, $moveVariants, $corners);
По моему этот метод должен выглядеть так: move(). Найти других животных или углы можно с помощью Карты. Ты не сделал класс Карта, и потому теперь вынужден информацию о животных передавать с помощью кучи массивов в каждую функцию.
> // Оценка ходов
> abstract protected function setRating($animals, $moveVariants, $corners);
Вот мне кажется что из 2 абстрактных методов - setRating и move - один лишний. Я имею в виду, если все животные пользуются алгоритмом оценки хода, то должно быть достаточно функции выбора всех допустимых ходов + setRaing, верно? Для move тогда можно было бы предоставить реализацию по умолчанию в классе Animal. С другой стороны, если мы не хотим заставлять всех пользоваться алгоритмом оценки, достаточно сделать абстрактной только move.
У тебя очень неуклюже получилась генерация допустимых ходов, где генерируются ходы, потом часть из них (диагональные) убираются. По моему проще сделать фукцнию которая сразу вернет список допустимых ходов.
> // Исключение занятых ходов
> abstract protected function removeOccupiedMove($animals, $moveVariants)
Выгоднее сделать метод, возвращающий все допустимые ходы.
> $this->getWeightsByDirections
Тут не get, а set, get-функции обычно ничего не меняют.
> // Трансформирует 3х мышей в мегамышь неуязвимую для кошек
> private function transformMegaMouse ($animals)
Тут не стоит использовать свойство megaMOuse. Ведь его значение устаревает после каждого перемещения любой мыши и легко может оказаться так, что в нем будет неактуальное значение. Лучше не сохранять статус мегамыши, а каждый раз проверять заново.
Для определения расстояния между животными можно было бы сделать статический метод, например Animal::getDistance($a, $b) или Field::getDistance(). Если мы меряем в ходах и расстояние разное для разных видов животных то $a->getDistainceTo($b);
> / Возможность ходить по горизонт, вертикали, диагонали
> public function getMoveAbility()
А как насчет возможности ходить конем? Ты зря так ограничиваешь себя, лучше просто сделать метод возвращающий допустимые ходы.
> // Если в соседней клетке есть мышь, рейтинг = INF
Это не очень удачная идея так как если рядом несколько мышей то ходы к ним получаются равнозначны в твоем алгоритме, но ведь там могут быть и другие факторы.
В проверке на мегамышь, что происходит если кошка пытается ее съесть, но не может? Кошка встает на ее клетку? Но она не должна это делать.
> $moveVariants = array_map(function ($moveVariant) {
Тут подошел бы простой цикл. Если ты меняешь объект в массиве то тебе не надо создавать новый массив с измененными объектами и записывать его обратно в переменную, так как объекты меняются и в исходном массиве.
В классе Animals нет проверки на генерацию не повторяющихся координат. Название класса плохое.
> // Фабрика ВариантовXода
> static public function createMoveVariants ($animal)
Мне кажется это лучше поместить в Animal. Почему? Потому что в этом случае зависимость будет однонаправленная: классу Animal нужен класс MoveVariant, а MV ничего не знает об A. Как-то более аккуратно получается.
> do {
> $start['y'] = $animalXY['y']-$animalSpeed;
> $animalSpeed--;
Не лучше ли использовать for ($i от 1 до animalSpeed) ?
> // Класс Вектор
> class Vector
Вот это вот самый нелогичный класс тут. Как представить вектор? Классический способ - это 2 числа, x и y. Зачем тут свойство $zero котороу избыточно (без него легко обойтись)?
Логично ждать и конструктор, принимающий 2 координаты. А конструктор, считающий вектор между 2 точками, сделать статическим методом.
> if ((is_int($startXY) && is_int($endXY)) |
> } else if (is_array($startXY) && is_array($endXY)) {
Такие вещи сильно запутывают код. Аргументы должны иметь четко определенный тип, иначе ты вынужден вокруг каждой строчки писать сторожевой иф.
В твоем случае надо сделать несколько статических конструткоров.
> public function getAngle($vector1, $vector2)
Это судя по всему статическая функция, так как она не испоьзует поля текущего объекта.
> class Corner
Название плохое, можно подумать что это объект представляющий один угол.
> Я гуглил, но не нашёл функции для нахождения корня n-ной степени. Везде советуют использовать pow(основание_степени, 1/показатель_степени).
Когда мы вычитаем, мы можем выйти за границы натуральных чисел, когда делим - за границы целых. Когда мы используем дробную степень (то есть корень), мы можем выйти за диапазон рациональных чисел. Чему равен корень из 2? Это так называемая бесконечная дробь, которую нельзя представить в виде рационального числа.
Получается, надо либо запретить возводить в дробные степени, либо запретить возводить в степени, которые дают иррациональное число (метод Роскомнадзора), либо придумать метод выразить результат приближенно (увы, теряя точность). То есть сделать pow(), и превратить float в SimpleFraction. Либо сделать новый тип чисел (иррациональные) и получать результаты вроде "корень из 2 делить на корень из трех" (пытаясь написать алгоритм их сложения, мы дойдем до поддержки произвольных выражений и напишем полноценную математическую систему).
Я думаю, надо брать либо вариант с запретом, либо с округлением. Неплохо бы помечать полученные в результате округления значения специальной пометкой.
> Для этого нужно найти НОК. То есть для первой дроби мне нужно умножать 111111111111111111112 на 1000000000000000000000. Даже ideone не выдержал, выплюнув Time limit exceeded
У тебя ужасный с точки зрения производительности алгоритм. Сложность древнегреческого алгоритма НОД небольшая так как остаток от деления всегда меньше делителя (подробнее: http://codeforces.com/blog/entry/9426?locale=ru и http://e-maxx.ru/algo/euclid_algorithm - пишут что сложность меньше логарифмеческой. Для твоих чисел это дает около 100 шагов) (кстати вперые узнал о теореме Ламе, век гугли - век учись).
Ну а НОК легко считается через НОД. Реализуй алгоритм Евклида, а то у тебя сделан брутфорс полным перебором всех значений от 1 до N - тут время работы может легко превысить время существования Вселенной. Не забывай что скорость работы компьютера ограничена и начиная с миллионов операций становится заметна глазу.
>>Ты парсишь выражение в RPN но не удобнее ли сразу строить дерево AST ?
> Было проще почитать статью про алгоритм сортировочной станции на вики и облечь псевдокод в код, чем читать талмуд вроде:
Вообще, я подозреваю, что если писать обобщенный алгоритм, то у тебя в итоге получится тот же самый алгоритм железнодорожной станции. Ну то есть реальные парсеры, работающие по грамматике, и парсящие например текст программы, вроде бы содержат те же самые стеки. Так что не беспокойся особо по этому поводу. Если ты не делаешь операции над составными математическими выражениями, тебе AST не так и нужен.
> Изменил трюки с explode('.', $foo) на трюки с bcdiv и floatval,
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/SimpleFraction.php#L52
Вот такой код однозначно не будет работать как задумано. Когда ты видишь floatval, ты должен понимать что это преобразование с потерями (вроде сжатия картинки в jpeg - результат всегда будет хуже оригинала):
> return (string) floatval(bcdiv(...))
floatval делает преобразование в float. float даже в 64-битном пхп сохраняет не более 14 значащих цифр ( http://php.net/manual/ru/language.types.float.php ). float это приближенный, неточный формат с потерями.
Прочитай-ка на досуге: https://habrahabr.ru/post/112953/
В случае bcmath, она уже хранит числа в строках и тебе не нужны эти конвертации в float. Проще всего наверно написать свой алгоритм (или найти) который берет числитель, разбивает на цифры, добивает нулями и ставит в нужном месте запятую. Тесты:
123456789123456789123456789/100 -> 1234567891234567891234567.89
1/1000 -> 0.001
100/1 -> 100
1230/100 -> 12.3
Десятичная дробь это не только когда знаменатель равен 10, но и 1, 100, 1000 и тд. Проверить это можно посимвольным анализом строки с знаменателем, что он состоит из единицы и нулей (регулярка?).
Аналогичные потери из-за конвертации во флоат будут тут: $valueAsString = (string) ($this->numerator * $this->denominator);
> Но эта функция основана на доступных типах данных,
да, она хранит результат как флоат
> Да, я погуглил насчёт унарных операторов в RPN и понял, что эта нотация не умеет отличать унарный плюс/минус от бинарного:
> Там советуют использовать отдельные знаки для унарных + и -,
Я думаю, имеется в виду что знак надо поменять в RPN нотации, но не во входном синтаксисе. В нем унарность знака надо определять из контекста (предыдущего токена). Если число - то бинарный:
1-1
-1
---1
-(1+1)--1
-(-1)
> Ещё я вижу очень запутанный способ решения без необходимости вводить новые знаки - на этапе парсинга инфиксного выражения заменять конструкции вида -3 на (0-3),
Это тупиковый путь так как код бессмысленно усложнется. Надо сделать флаг, хранящий тип предыдущего токена и смотреть по нему.
>>Твой лексер не поточный.
> Не нагуглил, что это.
Поточный лексер может получать данные на вход посимвольно/построчно, а твой требует сразу подать входное выражение целиком. В случае математических выражения не проблема, но при парсинге больших программ часто эффективнее парсить их постепенно, а не сразу - экономия на выделении/освобождении памяти.
> То есть, чтобы была возможность сделать $fraction1->add($fraction2)?
> У меня сейчас и так куча операторов/операций, да и класс SimpleFraction немаленький.
Ну теоретически можно сделать класс с методами Math::add($a, $b), но по моему можно и в сам класс дробей засунуть. Объект это ведь данные + методы для работы с ними. Логично что дробь умеет сама себя складывать.
> Распределяя ответственности, исходил из того, что оператор оперирует операндами, используя операцию.
Здесь есть проблемка. Твои Addition это классы, относящиеся к парсингу выражений ведь. Потому что в математике нет операции "левая скобка". И получается, чтобы посчитать выражение с дробями, нам приходится подключать классы от парсера. Ну и синтаксис громоздкий получается, попробуй сам написать код сложения/умножения нескольких дробей. Ну можно и так оставить, я в общем не против особо.
> Там заглушка с неменяющимся true стояла. На основе выражений выше попробовал сформулировать требования к валидному инфиксному выражению:
У тебя парсинг оказался разделен на 2 части: проверка синтаксиса и сам парсинг. Это требует поддерживать обе части кода в согласованном состоянии, писать непростые правила проверки и гадать, а все ли ты проверил. При парсинге проверка синтаксиса делается парсером/лексером:
- встретился символ не из белого списка - ошибка
- в сортировочной станции неожиданная ситуация (например, 2 знака умножения подряд) - ошибка
- после парсинга остались незакрытые скобки - ошибка
Разделять парсинг и проверку отдельно это плохо работающая идея, которая принесет тебе головную боль.
В твоем случае можно хранить тип предыдущего токена и при парсинге проверять.
> str_pad("Выражение в инфиксной нотации", 61)
Она не умеет считать русские буквы, имей в виду.
> Ещё я несколько дней пытался отлепить знак дроби от числителя и знаменателя, чтобы передавать знак дроби через конструктор, а в числителе и знаменателе держать только абсолютные значения.
Это проще делать наверно в рамках упрощения дроби. Также можно сделать метод getSign(). Не думаю что есть смысл заводить поле так как потом надо будет всюду этот знак домножать и убирать обратно.
> $this->sign ^= true;
^ это не булев, а целочисленный (побитовый) оператор. Он работает с числами а не true/false.
> Regex-движок звучит пугающе. Я в любом случае хотел за SICP когда-нибудь сесть, там, вроде бы, как раз интерпретатор Lisp'а по ходу дела пишется. Но максимум, на что я расчитывал - прорешать хотя бы треть задачек оттуда,
Да, SICP неплохая идея, только учти что это очень теоретическая штука и стоит параллельно что-то практическое делать. Там надо решать задачи на языке Scheme, он простой, можно скачать интерпретатор или тупо писать код на repl.it если лень ставить.
> Regex-движок звучит пугающе.
Да, я тут тоже подумал что сложновато и польза не очень ясна. Наверно не стоит пока тебе это делать. Хотя, ты бы узнал как именно работают движки регулярных выражений. Если интересно, вот очень ценные статьи, правда на англ:
- https://swtch.com/~rsc/regexp/
- https://swtch.com/~rsc/regexp/regexp1.html
- https://swtch.com/~rsc/regexp/regexp2.html
> Я гуглил, но не нашёл функции для нахождения корня n-ной степени. Везде советуют использовать pow(основание_степени, 1/показатель_степени).
Когда мы вычитаем, мы можем выйти за границы натуральных чисел, когда делим - за границы целых. Когда мы используем дробную степень (то есть корень), мы можем выйти за диапазон рациональных чисел. Чему равен корень из 2? Это так называемая бесконечная дробь, которую нельзя представить в виде рационального числа.
Получается, надо либо запретить возводить в дробные степени, либо запретить возводить в степени, которые дают иррациональное число (метод Роскомнадзора), либо придумать метод выразить результат приближенно (увы, теряя точность). То есть сделать pow(), и превратить float в SimpleFraction. Либо сделать новый тип чисел (иррациональные) и получать результаты вроде "корень из 2 делить на корень из трех" (пытаясь написать алгоритм их сложения, мы дойдем до поддержки произвольных выражений и напишем полноценную математическую систему).
Я думаю, надо брать либо вариант с запретом, либо с округлением. Неплохо бы помечать полученные в результате округления значения специальной пометкой.
> Для этого нужно найти НОК. То есть для первой дроби мне нужно умножать 111111111111111111112 на 1000000000000000000000. Даже ideone не выдержал, выплюнув Time limit exceeded
У тебя ужасный с точки зрения производительности алгоритм. Сложность древнегреческого алгоритма НОД небольшая так как остаток от деления всегда меньше делителя (подробнее: http://codeforces.com/blog/entry/9426?locale=ru и http://e-maxx.ru/algo/euclid_algorithm - пишут что сложность меньше логарифмеческой. Для твоих чисел это дает около 100 шагов) (кстати вперые узнал о теореме Ламе, век гугли - век учись).
Ну а НОК легко считается через НОД. Реализуй алгоритм Евклида, а то у тебя сделан брутфорс полным перебором всех значений от 1 до N - тут время работы может легко превысить время существования Вселенной. Не забывай что скорость работы компьютера ограничена и начиная с миллионов операций становится заметна глазу.
>>Ты парсишь выражение в RPN но не удобнее ли сразу строить дерево AST ?
> Было проще почитать статью про алгоритм сортировочной станции на вики и облечь псевдокод в код, чем читать талмуд вроде:
Вообще, я подозреваю, что если писать обобщенный алгоритм, то у тебя в итоге получится тот же самый алгоритм железнодорожной станции. Ну то есть реальные парсеры, работающие по грамматике, и парсящие например текст программы, вроде бы содержат те же самые стеки. Так что не беспокойся особо по этому поводу. Если ты не делаешь операции над составными математическими выражениями, тебе AST не так и нужен.
> Изменил трюки с explode('.', $foo) на трюки с bcdiv и floatval,
https://github.com/applejacky/arithmetic_expression_calculator/blob/master/src/SimpleFraction.php#L52
Вот такой код однозначно не будет работать как задумано. Когда ты видишь floatval, ты должен понимать что это преобразование с потерями (вроде сжатия картинки в jpeg - результат всегда будет хуже оригинала):
> return (string) floatval(bcdiv(...))
floatval делает преобразование в float. float даже в 64-битном пхп сохраняет не более 14 значащих цифр ( http://php.net/manual/ru/language.types.float.php ). float это приближенный, неточный формат с потерями.
Прочитай-ка на досуге: https://habrahabr.ru/post/112953/
В случае bcmath, она уже хранит числа в строках и тебе не нужны эти конвертации в float. Проще всего наверно написать свой алгоритм (или найти) который берет числитель, разбивает на цифры, добивает нулями и ставит в нужном месте запятую. Тесты:
123456789123456789123456789/100 -> 1234567891234567891234567.89
1/1000 -> 0.001
100/1 -> 100
1230/100 -> 12.3
Десятичная дробь это не только когда знаменатель равен 10, но и 1, 100, 1000 и тд. Проверить это можно посимвольным анализом строки с знаменателем, что он состоит из единицы и нулей (регулярка?).
Аналогичные потери из-за конвертации во флоат будут тут: $valueAsString = (string) ($this->numerator * $this->denominator);
> Но эта функция основана на доступных типах данных,
да, она хранит результат как флоат
> Да, я погуглил насчёт унарных операторов в RPN и понял, что эта нотация не умеет отличать унарный плюс/минус от бинарного:
> Там советуют использовать отдельные знаки для унарных + и -,
Я думаю, имеется в виду что знак надо поменять в RPN нотации, но не во входном синтаксисе. В нем унарность знака надо определять из контекста (предыдущего токена). Если число - то бинарный:
1-1
-1
---1
-(1+1)--1
-(-1)
> Ещё я вижу очень запутанный способ решения без необходимости вводить новые знаки - на этапе парсинга инфиксного выражения заменять конструкции вида -3 на (0-3),
Это тупиковый путь так как код бессмысленно усложнется. Надо сделать флаг, хранящий тип предыдущего токена и смотреть по нему.
>>Твой лексер не поточный.
> Не нагуглил, что это.
Поточный лексер может получать данные на вход посимвольно/построчно, а твой требует сразу подать входное выражение целиком. В случае математических выражения не проблема, но при парсинге больших программ часто эффективнее парсить их постепенно, а не сразу - экономия на выделении/освобождении памяти.
> То есть, чтобы была возможность сделать $fraction1->add($fraction2)?
> У меня сейчас и так куча операторов/операций, да и класс SimpleFraction немаленький.
Ну теоретически можно сделать класс с методами Math::add($a, $b), но по моему можно и в сам класс дробей засунуть. Объект это ведь данные + методы для работы с ними. Логично что дробь умеет сама себя складывать.
> Распределяя ответственности, исходил из того, что оператор оперирует операндами, используя операцию.
Здесь есть проблемка. Твои Addition это классы, относящиеся к парсингу выражений ведь. Потому что в математике нет операции "левая скобка". И получается, чтобы посчитать выражение с дробями, нам приходится подключать классы от парсера. Ну и синтаксис громоздкий получается, попробуй сам написать код сложения/умножения нескольких дробей. Ну можно и так оставить, я в общем не против особо.
> Там заглушка с неменяющимся true стояла. На основе выражений выше попробовал сформулировать требования к валидному инфиксному выражению:
У тебя парсинг оказался разделен на 2 части: проверка синтаксиса и сам парсинг. Это требует поддерживать обе части кода в согласованном состоянии, писать непростые правила проверки и гадать, а все ли ты проверил. При парсинге проверка синтаксиса делается парсером/лексером:
- встретился символ не из белого списка - ошибка
- в сортировочной станции неожиданная ситуация (например, 2 знака умножения подряд) - ошибка
- после парсинга остались незакрытые скобки - ошибка
Разделять парсинг и проверку отдельно это плохо работающая идея, которая принесет тебе головную боль.
В твоем случае можно хранить тип предыдущего токена и при парсинге проверять.
> str_pad("Выражение в инфиксной нотации", 61)
Она не умеет считать русские буквы, имей в виду.
> Ещё я несколько дней пытался отлепить знак дроби от числителя и знаменателя, чтобы передавать знак дроби через конструктор, а в числителе и знаменателе держать только абсолютные значения.
Это проще делать наверно в рамках упрощения дроби. Также можно сделать метод getSign(). Не думаю что есть смысл заводить поле так как потом надо будет всюду этот знак домножать и убирать обратно.
> $this->sign ^= true;
^ это не булев, а целочисленный (побитовый) оператор. Он работает с числами а не true/false.
> Regex-движок звучит пугающе. Я в любом случае хотел за SICP когда-нибудь сесть, там, вроде бы, как раз интерпретатор Lisp'а по ходу дела пишется. Но максимум, на что я расчитывал - прорешать хотя бы треть задачек оттуда,
Да, SICP неплохая идея, только учти что это очень теоретическая штука и стоит параллельно что-то практическое делать. Там надо решать задачи на языке Scheme, он простой, можно скачать интерпретатор или тупо писать код на repl.it если лень ставить.
> Regex-движок звучит пугающе.
Да, я тут тоже подумал что сложновато и польза не очень ясна. Наверно не стоит пока тебе это делать. Хотя, ты бы узнал как именно работают движки регулярных выражений. Если интересно, вот очень ценные статьи, правда на англ:
- https://swtch.com/~rsc/regexp/
- https://swtch.com/~rsc/regexp/regexp1.html
- https://swtch.com/~rsc/regexp/regexp2.html
разве что register_shutdown_handler . В php7 несколько фатальных ошибок переделали на исключения.
>>790816
Коммить из командной строки
>>790793
Можно в момент добавления мышки на карту передавать ей ссылку на объект карты и сохранять. Можно даже передавать в конструктор но тогда мышку будет нельзя создать без карты.
> } while ($animal->placed == false);
Тут потенциально бесконечный цикл. Сделай разумное ограничение либо делай рандом только средит свободных клеток.
>>790773
У тебя отдельно код для обычных месяцев и отдельно для последнего, когда платится остаток. Можно сделать общий код для всех случаев, вычисляя плату в текущем месяце с учетом остатка долга.
>>790722
Функцией определения MIME типа, можно из getId3 раз уж ты все равно ее используешь.
>>788640
Я не очень хорошо ориентируюсь в рынке труда. Попробуй погуглить тематические сайты, на тостере часто устраивают флуд по теме, если ты из Украины то dou, тут есть раздел перезвонивших итд. Были какие-то сомнительные исследования на Хабре.
Тут есть много факторов, сколько тех или иных вакансий, сколько у тебя будет конурентов и тд.
Ты как-то смешал все в кучу, я плохо представляю зачем, знающего Симфони, отправлять на поддержку битрикса.
разве что register_shutdown_handler . В php7 несколько фатальных ошибок переделали на исключения.
>>790816
Коммить из командной строки
>>790793
Можно в момент добавления мышки на карту передавать ей ссылку на объект карты и сохранять. Можно даже передавать в конструктор но тогда мышку будет нельзя создать без карты.
> } while ($animal->placed == false);
Тут потенциально бесконечный цикл. Сделай разумное ограничение либо делай рандом только средит свободных клеток.
>>790773
У тебя отдельно код для обычных месяцев и отдельно для последнего, когда платится остаток. Можно сделать общий код для всех случаев, вычисляя плату в текущем месяце с учетом остатка долга.
>>790722
Функцией определения MIME типа, можно из getId3 раз уж ты все равно ее используешь.
>>788640
Я не очень хорошо ориентируюсь в рынке труда. Попробуй погуглить тематические сайты, на тостере часто устраивают флуд по теме, если ты из Украины то dou, тут есть раздел перезвонивших итд. Были какие-то сомнительные исследования на Хабре.
Тут есть много факторов, сколько тех или иных вакансий, сколько у тебя будет конурентов и тд.
Ты как-то смешал все в кучу, я плохо представляю зачем, знающего Симфони, отправлять на поддержку битрикса.
Вообще эта ситуация, когда файл может быть картинкой, видео, итд, называется наследование таблиц (по аналогии с классами). Есть паттерны:
Single Table Inheritance (Наследование с единой таблицей)
Class Table Inheritance (Наследование с таблицами классов)
Concrete Table Inheritance (Наследование с таблицами конечных классов)
( http://design-pattern.ru/ )
Тут я думаю проще всего просто в модели и таблице файла предусмотреть поля для информации о картинке и видео. Поскольку видео бывает разных типов с разыми параметрами, то проще всего хранить эти параметры в базе как JSON массив. В коде конечно работать с массивом неизвестной структуры работать неудобно, потому хорошо бы завернуть это в класс, например, с названием FileInfo, с методами для получения списка свойств, значений свойств, конкретного свойства и тд.
>>790546
Я думаю тут нет особой выгоды городить несколько классов. Получаем усложнение кода, а выгода в чем?
>>790528
> В контроллере "информация о файле" я перевожу данные в строку и отдаю переменной в шаблон. Но что делать в контроллере "n-ое число последних файлов"?
Это замусоривает контроллер. Проще в шаблоне написать
<?= html(ViewHelper::formatFileSize($file->size)) ?>
> я перевожу данные в строку и отдаю переменной в шаблон.
Проще просто передать один объект с файлом
> Или философия MVC допускает то, что в шаблоне в цикле я смогу вызвать мою функцию конвертер для каждого объекта?
Допускает, почему нет. Функции-помощники для представления данных в какой-то форме вполне допустимы.
Вообще эта ситуация, когда файл может быть картинкой, видео, итд, называется наследование таблиц (по аналогии с классами). Есть паттерны:
Single Table Inheritance (Наследование с единой таблицей)
Class Table Inheritance (Наследование с таблицами классов)
Concrete Table Inheritance (Наследование с таблицами конечных классов)
( http://design-pattern.ru/ )
Тут я думаю проще всего просто в модели и таблице файла предусмотреть поля для информации о картинке и видео. Поскольку видео бывает разных типов с разыми параметрами, то проще всего хранить эти параметры в базе как JSON массив. В коде конечно работать с массивом неизвестной структуры работать неудобно, потому хорошо бы завернуть это в класс, например, с названием FileInfo, с методами для получения списка свойств, значений свойств, конкретного свойства и тд.
>>790546
Я думаю тут нет особой выгоды городить несколько классов. Получаем усложнение кода, а выгода в чем?
>>790528
> В контроллере "информация о файле" я перевожу данные в строку и отдаю переменной в шаблон. Но что делать в контроллере "n-ое число последних файлов"?
Это замусоривает контроллер. Проще в шаблоне написать
<?= html(ViewHelper::formatFileSize($file->size)) ?>
> я перевожу данные в строку и отдаю переменной в шаблон.
Проще просто передать один объект с файлом
> Или философия MVC допускает то, что в шаблоне в цикле я смогу вызвать мою функцию конвертер для каждого объекта?
Допускает, почему нет. Функции-помощники для представления данных в какой-то форме вполне допустимы.
>>790379
Это особенность удаленной работы - учитывается только реально потраченное время. Не нравится - иди в офис, хотя там тоже не побездельничаешь. Я, к счастью, не испытываю необходимости работать по 8 часов в день, это неинтересно и от этого устаешь. Но если ты молодой, ты ведь небось за компьютерной игрой можешь 3 дня просидеть без сна, можешь и попрограммировать наверно.
От этого никуда не убежать. Либо ты научишься как-то себя организовывать, режим дня, отдых, чтобы иметь возможность продуктивно и много работать, либо станешь обитателем перезвоним-треда.
Алсо сразу советую работать по обычному офисному графику (типа с 11 до 18). Избегай мыслей вроде "сделаю перерыв, посплю, побездельничаю немного, вечером/в выходные доделаю" - в итоге ты будешь вообще по 12 часов в сутки работать. Старайся искать такую работу, где будет возмодность постоянно изучать что-то новое, а не ковыряться в залежах кода под битрикс. Старайся ничего не делать в выходные и ни под каким предлогом не соглашаться на овертаймы.
>>790355
> Если заключить инклуд в стороннюю функцию то в шаблоне становиться нельзя обращаться к переменным в контроллере (к таким как $token, $registerStudentForm).
Обычно в функцию передается массив переменных, а перед инклудом извлекается с помощью extract:
$this->render('template.phtml', ['a' => 1, 'b' => 2]);
У тебя плохо сделано что переменная $i меняется в нескольких местах и трудно понять как вообще работает внешний цикл for. Лучше заменить его на while, и сделать чтобы $i++ был только в одном месте.
>>790152
Есть версия что надо потратить 10 000 часов чтобы стать профессионалом в чем-то.
>>790158
Есть отношения многие-ко-многим, их (вроде бы) ты и использовал, придумывать велосипеды незачем. Если записей в базе станет много, попросишь инвесторов купить побольше железа.
>>790144
Я просто мимо проходил и хотел сказать что снижение ставки это по сути "ты нам не подходишь, но если ты готов поработать за еду, можешь остаться". Понижение зарплаты это предложение уволиться.
>>790110
гугли нормализацию баз данных, отношения, также глянь наши задачки в ОП посте.
>>789929
держать данные в 2 копиях - всегда плохая идея. Ведь тебе надо постоянно будет поддерживать их согласованность. Должен быть один "источник правды".
>>789926
чтобы например кошек цифрами обозначить
У тебя плохо сделано что переменная $i меняется в нескольких местах и трудно понять как вообще работает внешний цикл for. Лучше заменить его на while, и сделать чтобы $i++ был только в одном месте.
>>790152
Есть версия что надо потратить 10 000 часов чтобы стать профессионалом в чем-то.
>>790158
Есть отношения многие-ко-многим, их (вроде бы) ты и использовал, придумывать велосипеды незачем. Если записей в базе станет много, попросишь инвесторов купить побольше железа.
>>790144
Я просто мимо проходил и хотел сказать что снижение ставки это по сути "ты нам не подходишь, но если ты готов поработать за еду, можешь остаться". Понижение зарплаты это предложение уволиться.
>>790110
гугли нормализацию баз данных, отношения, также глянь наши задачки в ОП посте.
>>789929
держать данные в 2 копиях - всегда плохая идея. Ведь тебе надо постоянно будет поддерживать их согласованность. Должен быть один "источник правды".
>>789926
чтобы например кошек цифрами обозначить
Поле field это неудачная идея. Тебе надо будет отслеживать все перемещения животных и обновлять этот массив, ты замучаешься. Он не нужен если у тебя есть координаты всех животных.
Хранить надо не бесполезную иконку, а просто например список объектов-животных.
>>789465
Это https://symfony.com/doc/current/book/from_flat_php_to_symfony2.html (англ) хорошая статья. Всем изучающим MVC советую глянуть.
>>789451
> $text=preg_split("/".PHP_EOL."/um",$text);
Не стоит так писать так как PHP_EOL это символ(ы) которыми в данной ОС принято переводить строку. Но текст программы пишется в редакторе и где гарантия что у тебя там выбран тот же символ конца строки? Употребимых варианта всего 2:
- винда обозначает перевод строки как \r\n
- линукс/макось как \n
- древняя макось использовала \r но это было очень давно и уже неактуально
Разбивая по \n и делая trim для удаления \r ты получишь код, работающий в любом режиме редактора.
Кстати в echo можно использовать тоже просто \n - оно работает везде, кроме Блокнота.
> for($j=0, $count=count($text);$j<$count;$j++){
> $count=count($text)
Экономия на спичках, на мой взгляд, тем более что тут лучше бы подошел foreach
В остальном, норм.
>>788653
Не у всех есть нужные знания и умения чтобы сделать свой "проект".
>>788773
забыл обновить
>>788854
адблок это тоже ведь возможность заработка если подумать. Браузерные игры могут вымереть, а потребность в играх - нет.
>>788626
Это наверно нужно для оптимизации, она может сортировать массивы перед сравнением.
Поле field это неудачная идея. Тебе надо будет отслеживать все перемещения животных и обновлять этот массив, ты замучаешься. Он не нужен если у тебя есть координаты всех животных.
Хранить надо не бесполезную иконку, а просто например список объектов-животных.
>>789465
Это https://symfony.com/doc/current/book/from_flat_php_to_symfony2.html (англ) хорошая статья. Всем изучающим MVC советую глянуть.
>>789451
> $text=preg_split("/".PHP_EOL."/um",$text);
Не стоит так писать так как PHP_EOL это символ(ы) которыми в данной ОС принято переводить строку. Но текст программы пишется в редакторе и где гарантия что у тебя там выбран тот же символ конца строки? Употребимых варианта всего 2:
- винда обозначает перевод строки как \r\n
- линукс/макось как \n
- древняя макось использовала \r но это было очень давно и уже неактуально
Разбивая по \n и делая trim для удаления \r ты получишь код, работающий в любом режиме редактора.
Кстати в echo можно использовать тоже просто \n - оно работает везде, кроме Блокнота.
> for($j=0, $count=count($text);$j<$count;$j++){
> $count=count($text)
Экономия на спичках, на мой взгляд, тем более что тут лучше бы подошел foreach
В остальном, норм.
>>788653
Не у всех есть нужные знания и умения чтобы сделать свой "проект".
>>788773
забыл обновить
>>788854
адблок это тоже ведь возможность заработка если подумать. Браузерные игры могут вымереть, а потребность в играх - нет.
>>788626
Это наверно нужно для оптимизации, она может сортировать массивы перед сравнением.
Для обычных визиток достаточно HTML + CMS на которую он натягивается (а вот она уже написана на php)
Спасибо.
Оп, вот так подойдет? Длину/ширину в json или отдельным атрибутом?
А вообще мне же наверное придется как-то идентифицировать тип файла и сохранить это в дальнейшем, т.е. наверное http://design-pattern.ru/patterns/single-table-inheritance.html хорошо подойдет.
Ах да, у меня же это свойство уже есть.
Алсо они встречаются дальше в массиве, везде в data.
>бутстрап
Вполне сгодится.
>>788640
>200+
>150+
Так туда после учебников-хуебников не возьмут же, там опыт овердохуя лет и ололо конкуренция. Ибо вакансий таких все же мало. Закрываются очень быстро по мои наблюдениям.
Еще часто пишут на высоких уровнях не опыт в ЯЗЫКНЕЙМ, а опыт в вебе например, т.к. если ты 5лет хуярил на симфони еще с каким нибудь ангуларом, то перекат на техологию у тебя будет быстрый, как у ёжика соника.
ОП тут
>>774246
Второй вариант плохой. Надо делать повторяющиеся через цикл, а не копипастить. Чтобы склеить строку из частей, есть 2 варианта:
- использовать оператор точка (склеивание строки)
- складывать части в массив, который в конце склеить через implode
>>774916
Вообще, токен будет быстрее устаревать. Лучше бы все таки куки.
>>775124
При просмотре страницы анализируется УРЛ, проверяется например по базе данных, и определяется, что надо вывести на этой странице.
>>775327
Не знаю
>>775382
Соединение нужно одно, использовать DI можно и нужно.
> Так как тогда объект БД нужно будет создавать в контроллере и передавать в качестве аргумента в модель, но контроллер ведь для этого не предназначен, тогда создавать объект логичней все же в модели?
Если создавать в модели, это будет не DI.
В маленьком приложении можно создать все нужные объекты в скрипте boostrap. Или сделать простой DI container.
>>775478
Пока нет на это времени.
>>777546
> Надо вызвать из php js-скрипт, лежащий на локалке, передав в него данные для нескольких переменных.
Нужна node.js если я правильно тебя понял.
>>777637
погугли free web hosting например
ОП тут
>>774246
Второй вариант плохой. Надо делать повторяющиеся через цикл, а не копипастить. Чтобы склеить строку из частей, есть 2 варианта:
- использовать оператор точка (склеивание строки)
- складывать части в массив, который в конце склеить через implode
>>774916
Вообще, токен будет быстрее устаревать. Лучше бы все таки куки.
>>775124
При просмотре страницы анализируется УРЛ, проверяется например по базе данных, и определяется, что надо вывести на этой странице.
>>775327
Не знаю
>>775382
Соединение нужно одно, использовать DI можно и нужно.
> Так как тогда объект БД нужно будет создавать в контроллере и передавать в качестве аргумента в модель, но контроллер ведь для этого не предназначен, тогда создавать объект логичней все же в модели?
Если создавать в модели, это будет не DI.
В маленьком приложении можно создать все нужные объекты в скрипте boostrap. Или сделать простой DI container.
>>775478
Пока нет на это времени.
>>777546
> Надо вызвать из php js-скрипт, лежащий на локалке, передав в него данные для нескольких переменных.
Нужна node.js если я правильно тебя понял.
>>777637
погугли free web hosting например
Здесь писать ничего не нужно, здесь будут только ответы на вопросы, которые я ответить не успел.
>>778083
> Возник вопрос: как открыть пустые клетки, как в виндовом Сапере?
При клике в клетку смотреть, если она пустая, то обойти все еще не открытые соседние клетки и открыть их. И так далее. Тут нужна рекурсивная функция.
По коду:
У тебя какой-то странный синтаксис объявления функций:
var x = function () {};
Зачем так писать если можно писать function x() {} ?
Далее, если ты уж делаешь ООП код, то делай его нормально, на прототипах, а не вкладывая одну функцию в другую. У тебя гигантская функция Field с кучей функций и переменных внутри и трудно что-то понять. Если бы ты создавал отдельные методы на прототипе, я думаю, было бы проще. Как минимум у тебя не было бы гигантских функций.
Функции названы неудачно: setHeight ничего не задает и потому должна называтья checkHeight. Более того, я не понимаю, зачем это было выносить в функцию, если эти ифы можно было и так написать внутри Field().
> var getY = function(cell) {
Тоже странная функция. Не проще у cell сделать свойства x/y?
> document.head.innerHTML =
Это в общем плохая идея так как она удаляет то, что было в head до этого. В твоем случае проще вписать стили вручную. Да и вообще, что CSS код делает в JS файле?
> var generateMines = function() {
тут бы не помешала защита от вечного цикла, если мин просят поставить больше чем свободных клеток.
> if (typeof(cells) !== "undefined"
зачем копировать этот код? Зачем тут typeof? Можно просто писать if (a === undefined), или, что еще лучше, использовать оператор in. Кто-то написал в интернете неправильный код, и теперь все его копируют. В твоем случае даже in не нужен, достаточно сравнить что i меньше высоты или ширины.
> var countMines = function(c) {
Эта функция ведь не должна считать мины на центральной клеточке, только на соседних?
> for (var k = 0; k < width; k++) {
> cells[k].setMinesAround(countMines(cells[k]));
Я не думаю, что это надо рассчитывать заранее, это можно делать в момент открытия клетки.
> var click = function(){
> table.addEventListener("click", function(event){
Название функции не соответствует тому, что она делает.
> table.addEventListener("click", function(event){
> for (var i = 0; i < height; i++) {
....
> });
Слишком много кода, надо выносить обработчик в отдельную функцию.
> if (cells[k].getTd() === event.target) {
У ячеек и строк в DOM есть атрибуты rowIndex/colIndex по моему, по ним можно определить координаты ячейки.
> this.openEmptyCells = function(c) {
Надо открывать все 8 соседних ячеек, в том числе по диагонали. Не стоит писать копипасту, стоит сделать цикл.
> function Cell(tdom) {
> var minesAround = 0;
Незачем это хранить, это всегда можно посчитать.
> var isEmpty = false;
Это всегда можно вывести из числа мин рядом.
> td.innerHTML = mine.getView();
Непонятно зачем тут объект mine. зачем вообще нужен класс Mine?
> this.setOpenStyle = function() {
> td.style.background = "white";
Тут лучше добавлять CSS класс. зачем тащить CSS код в яваскрипт?
Я тебе советую, кроме исправления кода, почитать еще мой урок про MVC-версию сапера.
>>778083
> Возник вопрос: как открыть пустые клетки, как в виндовом Сапере?
При клике в клетку смотреть, если она пустая, то обойти все еще не открытые соседние клетки и открыть их. И так далее. Тут нужна рекурсивная функция.
По коду:
У тебя какой-то странный синтаксис объявления функций:
var x = function () {};
Зачем так писать если можно писать function x() {} ?
Далее, если ты уж делаешь ООП код, то делай его нормально, на прототипах, а не вкладывая одну функцию в другую. У тебя гигантская функция Field с кучей функций и переменных внутри и трудно что-то понять. Если бы ты создавал отдельные методы на прототипе, я думаю, было бы проще. Как минимум у тебя не было бы гигантских функций.
Функции названы неудачно: setHeight ничего не задает и потому должна называтья checkHeight. Более того, я не понимаю, зачем это было выносить в функцию, если эти ифы можно было и так написать внутри Field().
> var getY = function(cell) {
Тоже странная функция. Не проще у cell сделать свойства x/y?
> document.head.innerHTML =
Это в общем плохая идея так как она удаляет то, что было в head до этого. В твоем случае проще вписать стили вручную. Да и вообще, что CSS код делает в JS файле?
> var generateMines = function() {
тут бы не помешала защита от вечного цикла, если мин просят поставить больше чем свободных клеток.
> if (typeof(cells) !== "undefined"
зачем копировать этот код? Зачем тут typeof? Можно просто писать if (a === undefined), или, что еще лучше, использовать оператор in. Кто-то написал в интернете неправильный код, и теперь все его копируют. В твоем случае даже in не нужен, достаточно сравнить что i меньше высоты или ширины.
> var countMines = function(c) {
Эта функция ведь не должна считать мины на центральной клеточке, только на соседних?
> for (var k = 0; k < width; k++) {
> cells[k].setMinesAround(countMines(cells[k]));
Я не думаю, что это надо рассчитывать заранее, это можно делать в момент открытия клетки.
> var click = function(){
> table.addEventListener("click", function(event){
Название функции не соответствует тому, что она делает.
> table.addEventListener("click", function(event){
> for (var i = 0; i < height; i++) {
....
> });
Слишком много кода, надо выносить обработчик в отдельную функцию.
> if (cells[k].getTd() === event.target) {
У ячеек и строк в DOM есть атрибуты rowIndex/colIndex по моему, по ним можно определить координаты ячейки.
> this.openEmptyCells = function(c) {
Надо открывать все 8 соседних ячеек, в том числе по диагонали. Не стоит писать копипасту, стоит сделать цикл.
> function Cell(tdom) {
> var minesAround = 0;
Незачем это хранить, это всегда можно посчитать.
> var isEmpty = false;
Это всегда можно вывести из числа мин рядом.
> td.innerHTML = mine.getView();
Непонятно зачем тут объект mine. зачем вообще нужен класс Mine?
> this.setOpenStyle = function() {
> td.style.background = "white";
Тут лучше добавлять CSS класс. зачем тащить CSS код в яваскрипт?
Я тебе советую, кроме исправления кода, почитать еще мой урок про MVC-версию сапера.
Книги для наичнающих есть, их много, но они все довольно плохие и учат быдокодингу. В Оп посте есть 2 хороших книги, но они не для начинающих.
>>778205
> Потому что эти поля (ставку, кофе) нужно переопределять походу выполнения программы, при повышении ставки для аналитика. Можно сделать как ты советовал, сделать переопределяемые поля в классе Employee, по умолчанию брать из класса Profession, а при смене профессии сбрасывать. > Будет норм?
Как сейчас сделано, годится. То есть абстрактные методы в классе Profession.
> Тогда нужно где-то хранить объекты профессии, чтобы потом их передать в качестве аргументов. А про константы не понятно, их нужно будет создавать в начале программы, а где гарантия, что при создании новой профессии программист создаст новую константу? А если объявлять константу внутри класса профессии, то какой тогда в этом смысл, если можно использовать названия класса? Корректно ли использовать такую конструкцию в качестве аргумента $departament->findEmployees(get_class (new Analyst)); ?
Можно использовать имя класса. Для получения имени класса есть константа SomeClass::CLASS
>>В общем-то эта строка не нужна.
> Почему не нужна? Если $analysts не определен, то данная итерация прервется, и цикл перейдет к другому департаменту, и не будет выполнятся код следующий за этой строкой.
Потому что если эту строку убрать результат будет тот же.
> Почему это ошибка именно инкапсуляции, а не логики?
Потому что инкапсуляция подразумевает что Департамент сам занимается всякими внутренними изменениями. Ты вызываешь функцию "поменять босса", а он уже решает как это сделать.
> Я переделал, теперь метод смены работника в департаменте, которому аргументом передают работника, который если есть в депе получает статус шефа. Но деп все также обращается к методу Employee->setСhief(0); Я исправил ошибку?
Да, это и требовалось, надо чтобы в департаменте был метод смены босса.
----------------
По коду:
> // Назначаем работника шефом
> $this->employees[$employeeKey]->setСhief(1);
Тут можно было писать $empolyee->setChief(1) так как это тот же объект.
> // Создание департамента
> public function createDepartament($name)
Здесь логично было бы еще возвращать объект этого департамента чтобы им можно было пользоваться.
> $engineers = $departament->findEmployees(get_class (new Engineer));
Если константа Engineer::CLASS, хранящая имя класса
> // Берем первые 40% через array_slice
> $dismissingEngineers = floor(count($engineers) * 0.6);
> $engineers = array_slice($engineers, $dismissingEngineers);
ЧТо-то странно. Почему 0.6, а не 0.4? Почему ты берешь последние 40%, а не первые?
> // Если в Департаменте нет аналитиков, переходим к след. департаменту
> if (!isset($analysts[0])) continue;
!count(...) или просто !$analysts
> public function liftManager($company)
> sort($employees);
Это не будет работать или будет работать криво. Нужен usort, а sort годится только для сортировки строк.
Книги для наичнающих есть, их много, но они все довольно плохие и учат быдокодингу. В Оп посте есть 2 хороших книги, но они не для начинающих.
>>778205
> Потому что эти поля (ставку, кофе) нужно переопределять походу выполнения программы, при повышении ставки для аналитика. Можно сделать как ты советовал, сделать переопределяемые поля в классе Employee, по умолчанию брать из класса Profession, а при смене профессии сбрасывать. > Будет норм?
Как сейчас сделано, годится. То есть абстрактные методы в классе Profession.
> Тогда нужно где-то хранить объекты профессии, чтобы потом их передать в качестве аргументов. А про константы не понятно, их нужно будет создавать в начале программы, а где гарантия, что при создании новой профессии программист создаст новую константу? А если объявлять константу внутри класса профессии, то какой тогда в этом смысл, если можно использовать названия класса? Корректно ли использовать такую конструкцию в качестве аргумента $departament->findEmployees(get_class (new Analyst)); ?
Можно использовать имя класса. Для получения имени класса есть константа SomeClass::CLASS
>>В общем-то эта строка не нужна.
> Почему не нужна? Если $analysts не определен, то данная итерация прервется, и цикл перейдет к другому департаменту, и не будет выполнятся код следующий за этой строкой.
Потому что если эту строку убрать результат будет тот же.
> Почему это ошибка именно инкапсуляции, а не логики?
Потому что инкапсуляция подразумевает что Департамент сам занимается всякими внутренними изменениями. Ты вызываешь функцию "поменять босса", а он уже решает как это сделать.
> Я переделал, теперь метод смены работника в департаменте, которому аргументом передают работника, который если есть в депе получает статус шефа. Но деп все также обращается к методу Employee->setСhief(0); Я исправил ошибку?
Да, это и требовалось, надо чтобы в департаменте был метод смены босса.
----------------
По коду:
> // Назначаем работника шефом
> $this->employees[$employeeKey]->setСhief(1);
Тут можно было писать $empolyee->setChief(1) так как это тот же объект.
> // Создание департамента
> public function createDepartament($name)
Здесь логично было бы еще возвращать объект этого департамента чтобы им можно было пользоваться.
> $engineers = $departament->findEmployees(get_class (new Engineer));
Если константа Engineer::CLASS, хранящая имя класса
> // Берем первые 40% через array_slice
> $dismissingEngineers = floor(count($engineers) * 0.6);
> $engineers = array_slice($engineers, $dismissingEngineers);
ЧТо-то странно. Почему 0.6, а не 0.4? Почему ты берешь последние 40%, а не первые?
> // Если в Департаменте нет аналитиков, переходим к след. департаменту
> if (!isset($analysts[0])) continue;
!count(...) или просто !$analysts
> public function liftManager($company)
> sort($employees);
Это не будет работать или будет работать криво. Нужен usort, а sort годится только для сортировки строк.
https://github.com/never3ver/students_list
> https://github.com/never3ver/students_list/blob/master/students_students.sql
Тут надо добавить уникальный ключ для email
> `birthyear` int(4)
есть тип YEAR
> `cookie` varchar(45) NOT NULL,
Надо добавить комментарий (COMMENT '....') чтобы пояснить что это за поле и как используется.
> https://github.com/never3ver/students_list/blob/master/public/bootstrap/styles.css
Не клади свои файлы в папку бутстрапа, клади их отдельно, иначе как понять где твой коД.а где не твой?
> .form {
> position: relative;
> top: 60px;
Для этого используют margin. Советую посмотреть мой курс по HTML/CSS из ОП поста.
> require_once __DIR__ . '/../app/init.php';
> require_once __DIR__ . '/../autoload.php';
Вызов autoload логично поместить в init.php
https://github.com/never3ver/students_list/blob/master/public/index.php
тут смешана в кучу контроллер и шаблон (view). Прочитай про отделение шаблонов от кода. HTML код должен быть в шаблонах.
> https://github.com/never3ver/students_list/blob/master/public/index.php#L47
> $pageList = $gateway->searchStudents($search);
При поиске надо бы поддерживать сортировку и постраничность тоже.
> <?php if (!isset($_COOKIE['name'])): ?>
Авторизацию хорошо бы вынести в отдельный класс или функции а не работать с кукой напрямую.
> https://github.com/never3ver/students_list/blob/master/public/regedit.php#L10
Тут смешана в кучу логика и подключение шаблонов. Шаблон с формой надо подключать один раз, в конце скрипта.
https://github.com/never3ver/students_list/blob/master/public/regedit.php#L10
> $row = $gateWay->getStudent($_COOKIE['name']);
> $oldEmail = $row[5];
Что за цифра 5? Откуда она взялась?
> if (isset($_POST['name']) && isset($_POST['secondname']) && isset($_POST['sex']) && isset($_POST['group']) && isset($_POST['email']) && isset($_POST['score']) && isset($_POST['birthyear']) && isset($_POST['local'])) {
Слишком длинно. Надо использовать цикл или функции а не копипастить код.
Редактирование сделано неудачно. Ты создаешь пустого студента, заполняешь его из формы и сохраняешь. Но правильнее загрузить студента, поменять те поля, которые переданы, и сохранить. Так надежнее. При твоем подходе легко потерять значения полей которых нет в форме.
> if ($errorsOfValidation && isset($student->name)) {
зачем проверка student->name?
> foreach ($errorsOfValidation as $value) {
> echo $value . "<br>";
Вывод должен быть в шаблоне. У тебя не MVC.
> if (!$gateWay->isEmailUnique($student->email) && $oldEmail != $student->email) {
> echo 'Введенный email уже используется';
Разве это не часть валидации?
> header("Refresh: 5; url = index.php");
Не стоит так делать уведомления. Что если человек отвечется, а потом вернется к вкладке и не увидит уведомление? Лучше вывести его на той странице, на которую делается редирект.
> header("Refresh: 5; url = index.php");
>echo 'Редактирование завершено. Если перенаправление не произойдет в течении 5 секунд, <a href="index.php">Главная страница</a>.';
Ты выводишь русские буквы, а где заголовок или метатег, задаюший кодировку? И где оформление?
Редактирование формы надо переделать так, как описано в моем уроке про работу с формами.
https://github.com/never3ver/students_list/blob/master/app/init.php
Не задается кодировка для mysql, есть риск что это окажется не utf8.
> https://github.com/never3ver/students_list/blob/master/app/StudentValidator.php#L10
> Имя может содержать латинские либо кириллические буквы, апострофы, пробелы и дефисы,
Но регулярка не разрешает пробелы. Также, регулярка не проверяет что длина не более 45 символов - проверь сам.
> Имя группы может содержать не более 10 латинских
В условии задачи не более 5
> if (! preg_match("/M|F/", $student->sex)) {
Это регулярка посчитает правильной строку abcdefMghijk так как не привязана к краям строки
> /([a-zA-Z0-9_+.-]+)@([a-z.-]+)/ui"
В имени домена могут быть цифры, но регулярка не разрешает.
> if ((! preg_match("/[0-9]{1,3}/", $student->score)) && $student->score <= 100) {
По моему тут ошибка в условии.
> https://github.com/never3ver/students_list/blob/master/app/Pager.php#L41
> public function getLimitAndOffset($pageNumber) {
тут логичнее сделать 2 отдельнх функции
https://github.com/never3ver/students_list/blob/master/app/Helper.php#L17
Для пометки есть тег <mark>
https://github.com/never3ver/students_list/blob/master/templates/editForm.html#L3
> <head>
> <link rel='stylesheet' href='/bootstrap/css/bootstrap.min.css'
> type='text/css' media='all'>
Это (тег head) скопировано в нескольких шаблонах. Надо убрать копипасту.
> <td class="textboldleft">Фамилия</td><td>
> <input class="column-wide" type="text" name='secondname'
> value='<?=$row[2]?>' required="required">
Что за странный формат результата? ЧТо такое row[2]? Откуда эта двойка? Почему $row это не объект-модель студента, а какой-то массив с цифрами?
Для числа баллов нужно использовать не текстовое, а числовое поле ввода. Для полей местный и пол надо использовать радиокнопки. Также, добавь побольше HTML5 валидации, например, по регулярке и по длине.
https://github.com/never3ver/students_list/blob/master/templates/editForm.html#L25
> value='<?=$row[2]?>'
Тут XSS. Почитай мой урок по этой теме.
> https://github.com/never3ver/students_list/blob/master/templates/editForm.html
> https://github.com/never3ver/students_list/blob/master/templates/registerForm.html
Эти файлы скопированы. Убери копипасту и объедини их в один файл.
https://github.com/never3ver/students_list/blob/master/templates/listOfStudents.html#L14
> <?php $value['name'] = Helper::highlightText($search, $value['name']); ?>
Не надо менять переданные из контроллера данные. Также, почему у тебя тут какие-то массивы а не объекты Student? Также, где экранирование спецсимволов?
Так как ты плохо разбираешься в экранировании, реши эту задачу: https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Экранирование
https://github.com/never3ver/students_list
> https://github.com/never3ver/students_list/blob/master/students_students.sql
Тут надо добавить уникальный ключ для email
> `birthyear` int(4)
есть тип YEAR
> `cookie` varchar(45) NOT NULL,
Надо добавить комментарий (COMMENT '....') чтобы пояснить что это за поле и как используется.
> https://github.com/never3ver/students_list/blob/master/public/bootstrap/styles.css
Не клади свои файлы в папку бутстрапа, клади их отдельно, иначе как понять где твой коД.а где не твой?
> .form {
> position: relative;
> top: 60px;
Для этого используют margin. Советую посмотреть мой курс по HTML/CSS из ОП поста.
> require_once __DIR__ . '/../app/init.php';
> require_once __DIR__ . '/../autoload.php';
Вызов autoload логично поместить в init.php
https://github.com/never3ver/students_list/blob/master/public/index.php
тут смешана в кучу контроллер и шаблон (view). Прочитай про отделение шаблонов от кода. HTML код должен быть в шаблонах.
> https://github.com/never3ver/students_list/blob/master/public/index.php#L47
> $pageList = $gateway->searchStudents($search);
При поиске надо бы поддерживать сортировку и постраничность тоже.
> <?php if (!isset($_COOKIE['name'])): ?>
Авторизацию хорошо бы вынести в отдельный класс или функции а не работать с кукой напрямую.
> https://github.com/never3ver/students_list/blob/master/public/regedit.php#L10
Тут смешана в кучу логика и подключение шаблонов. Шаблон с формой надо подключать один раз, в конце скрипта.
https://github.com/never3ver/students_list/blob/master/public/regedit.php#L10
> $row = $gateWay->getStudent($_COOKIE['name']);
> $oldEmail = $row[5];
Что за цифра 5? Откуда она взялась?
> if (isset($_POST['name']) && isset($_POST['secondname']) && isset($_POST['sex']) && isset($_POST['group']) && isset($_POST['email']) && isset($_POST['score']) && isset($_POST['birthyear']) && isset($_POST['local'])) {
Слишком длинно. Надо использовать цикл или функции а не копипастить код.
Редактирование сделано неудачно. Ты создаешь пустого студента, заполняешь его из формы и сохраняешь. Но правильнее загрузить студента, поменять те поля, которые переданы, и сохранить. Так надежнее. При твоем подходе легко потерять значения полей которых нет в форме.
> if ($errorsOfValidation && isset($student->name)) {
зачем проверка student->name?
> foreach ($errorsOfValidation as $value) {
> echo $value . "<br>";
Вывод должен быть в шаблоне. У тебя не MVC.
> if (!$gateWay->isEmailUnique($student->email) && $oldEmail != $student->email) {
> echo 'Введенный email уже используется';
Разве это не часть валидации?
> header("Refresh: 5; url = index.php");
Не стоит так делать уведомления. Что если человек отвечется, а потом вернется к вкладке и не увидит уведомление? Лучше вывести его на той странице, на которую делается редирект.
> header("Refresh: 5; url = index.php");
>echo 'Редактирование завершено. Если перенаправление не произойдет в течении 5 секунд, <a href="index.php">Главная страница</a>.';
Ты выводишь русские буквы, а где заголовок или метатег, задаюший кодировку? И где оформление?
Редактирование формы надо переделать так, как описано в моем уроке про работу с формами.
https://github.com/never3ver/students_list/blob/master/app/init.php
Не задается кодировка для mysql, есть риск что это окажется не utf8.
> https://github.com/never3ver/students_list/blob/master/app/StudentValidator.php#L10
> Имя может содержать латинские либо кириллические буквы, апострофы, пробелы и дефисы,
Но регулярка не разрешает пробелы. Также, регулярка не проверяет что длина не более 45 символов - проверь сам.
> Имя группы может содержать не более 10 латинских
В условии задачи не более 5
> if (! preg_match("/M|F/", $student->sex)) {
Это регулярка посчитает правильной строку abcdefMghijk так как не привязана к краям строки
> /([a-zA-Z0-9_+.-]+)@([a-z.-]+)/ui"
В имени домена могут быть цифры, но регулярка не разрешает.
> if ((! preg_match("/[0-9]{1,3}/", $student->score)) && $student->score <= 100) {
По моему тут ошибка в условии.
> https://github.com/never3ver/students_list/blob/master/app/Pager.php#L41
> public function getLimitAndOffset($pageNumber) {
тут логичнее сделать 2 отдельнх функции
https://github.com/never3ver/students_list/blob/master/app/Helper.php#L17
Для пометки есть тег <mark>
https://github.com/never3ver/students_list/blob/master/templates/editForm.html#L3
> <head>
> <link rel='stylesheet' href='/bootstrap/css/bootstrap.min.css'
> type='text/css' media='all'>
Это (тег head) скопировано в нескольких шаблонах. Надо убрать копипасту.
> <td class="textboldleft">Фамилия</td><td>
> <input class="column-wide" type="text" name='secondname'
> value='<?=$row[2]?>' required="required">
Что за странный формат результата? ЧТо такое row[2]? Откуда эта двойка? Почему $row это не объект-модель студента, а какой-то массив с цифрами?
Для числа баллов нужно использовать не текстовое, а числовое поле ввода. Для полей местный и пол надо использовать радиокнопки. Также, добавь побольше HTML5 валидации, например, по регулярке и по длине.
https://github.com/never3ver/students_list/blob/master/templates/editForm.html#L25
> value='<?=$row[2]?>'
Тут XSS. Почитай мой урок по этой теме.
> https://github.com/never3ver/students_list/blob/master/templates/editForm.html
> https://github.com/never3ver/students_list/blob/master/templates/registerForm.html
Эти файлы скопированы. Убери копипасту и объедини их в один файл.
https://github.com/never3ver/students_list/blob/master/templates/listOfStudents.html#L14
> <?php $value['name'] = Helper::highlightText($search, $value['name']); ?>
Не надо менять переданные из контроллера данные. Также, почему у тебя тут какие-то массивы а не объекты Student? Также, где экранирование спецсимволов?
Так как ты плохо разбираешься в экранировании, реши эту задачу: https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Экранирование
сама логика праивльная, но можно было обойтись без переменной $x (да и название полуше придумать).
> Не понял, каким образом можно было брать буквы с конца. Пришлось перед циклом сделать еще 1 переменную.
Ну например mb_substr($str, -2, 1) вернет 2-ю букву с конца. Почитай мануал.
> btw, оглашать две переменные в действии1\менять их в действии2 это плохо ?
Если код понятен и очевиден, то нет.
>>778794
>>778812
Костыльное у тебя решение, ведь в последний месяц ты уходишь в минус, а затем восстанавливаешь баланс до нуля. Лучше бы конечно изначально не уходить в минус.
Ответ правильный.
>>779256
> abstract class PersonelDepartment
> {
> public function addEmployee($employee)
Создание сотрудников не задача департамента и это надо сделать отдельно. Не надо включать эту функцию в него ни явно, ни через наследование. Нельзя наследовать Департамент от ОтделаКадров, так как наследование это отношение вида "A явлется Б" и Департамент не является ОтделомКадров.
> public function fireEmployee($employee)
> {
> $employeeKey = array_search($employee, $this->employees);
Почитай мануал по array_search, и по сравнению объектов, ты забыл указать важный параметр.
> public function findEmployee($position, $boss, $rank)
Вместо поиска с указанием кучи условий удобнее просто задавать условие с помощью анонимной функции.
> static public function firstSolution($company)
> printData($company, 1);
Антикризисный комитет не должен печатать результаты.
> $department->changeBoss($boss, $promotionApplicant);
Непонятно почему в функици смены босса надо указвать старого. Департамент сам не знает кто его босс?
сама логика праивльная, но можно было обойтись без переменной $x (да и название полуше придумать).
> Не понял, каким образом можно было брать буквы с конца. Пришлось перед циклом сделать еще 1 переменную.
Ну например mb_substr($str, -2, 1) вернет 2-ю букву с конца. Почитай мануал.
> btw, оглашать две переменные в действии1\менять их в действии2 это плохо ?
Если код понятен и очевиден, то нет.
>>778794
>>778812
Костыльное у тебя решение, ведь в последний месяц ты уходишь в минус, а затем восстанавливаешь баланс до нуля. Лучше бы конечно изначально не уходить в минус.
Ответ правильный.
>>779256
> abstract class PersonelDepartment
> {
> public function addEmployee($employee)
Создание сотрудников не задача департамента и это надо сделать отдельно. Не надо включать эту функцию в него ни явно, ни через наследование. Нельзя наследовать Департамент от ОтделаКадров, так как наследование это отношение вида "A явлется Б" и Департамент не является ОтделомКадров.
> public function fireEmployee($employee)
> {
> $employeeKey = array_search($employee, $this->employees);
Почитай мануал по array_search, и по сравнению объектов, ты забыл указать важный параметр.
> public function findEmployee($position, $boss, $rank)
Вместо поиска с указанием кучи условий удобнее просто задавать условие с помощью анонимной функции.
> static public function firstSolution($company)
> printData($company, 1);
Антикризисный комитет не должен печатать результаты.
> $department->changeBoss($boss, $promotionApplicant);
Непонятно почему в функици смены босса надо указвать старого. Департамент сам не знает кто его босс?
$word1 = array('Чудесных', 'Суровых', 'Занятных', 'Внезапных');
Надо достать из него случайное слово. Я использовал array_rand, но получил только число. Может мне кто-то объяснить, как получить слово? Не хочу плодить ещё один массив через array_flip.
Мы уже все сидим в новом треде >>793705 (OP) , тут только ответы на старые посты.
> Надо достать из него случайное слово. Я использовал array_rand, но получил только число.
array_rand возвращает случайный ключ (а не значение) из массива. Тебе надо взять значение по ключу с помощью квадратных скобок.
Чтобы изучить основы, как работать с таблицами и формами, как работать с базой данных, как разбивть код на классы и тд.
Фреймворки не для начинающих. Начинающий либо не поймет их, либо научится только повторять то, что он увидел в уроке и сделать шаг вправо или влево не сможет так как не понимает как это все внутри устроено.
Алсо мы давно уже в новом треде, перекатывайся.
>>796727
Гугли
Надо давать нормальные ирмена переменным. Если ты не можешь придумтаь нормальное имя, получается ты сам не можешь сформулировать, зачем тут эта переменная и что она значит?
Также, у тебя там ошибка- обращение к еще не существующей переменной:
> PHP Notice: Undefined variable: pureNum in /home/KZQmiP/prog.php on line 13
По алгоритму - не надо ничего разбивать на части. Надо просто удалить (заменить на пустую строку) все не подходящие символы с помощью preg_replace.
>>782394
Нет, не проще. Это костыли. Это не проще, а сложнее и больше шанс ошибиться. Где гарантия что ты перечислишь все пааки и ничего не забудешь? В команде, кто-то может добавить новый файл и не закрыть доступ к нему. Публичная папка потому и называется публичная что в нее кладется то, что предназначено для публичного распространения. Что не предназначено - не надо туда класть.
>>782503
>>782508
Не знаю, займсиь отладкой, смотри что приходит, что уходит.
>>783071
С "а" или "но" ненадежно сделано - перед ним может быть не только запятая, но и например двоеточие или другой знак. Пробел не обязательно будет ровно один.
В остальном верно.
Тут то же самое замечание, в остальном верно.
в общем верно, хотя у тебя он не подсветит вторую опечатку в том же слове вроде тOпOр
>>784017
http://ideone.com/0hmsEY // Кошки-мышки
Константы заводить не требуется - можно использовать имя класса и получать его как Cat::CLASS
> protected $xy = array();
Непонятно, зачем тут массив и какое у него преимущество перед 2 отдельными полями. Скорее наоборот, неудобно работать.
Ну и вроде по этой задаче я уже писал ниже: >>791267 >>792620
Надо давать нормальные ирмена переменным. Если ты не можешь придумтаь нормальное имя, получается ты сам не можешь сформулировать, зачем тут эта переменная и что она значит?
Также, у тебя там ошибка- обращение к еще не существующей переменной:
> PHP Notice: Undefined variable: pureNum in /home/KZQmiP/prog.php on line 13
По алгоритму - не надо ничего разбивать на части. Надо просто удалить (заменить на пустую строку) все не подходящие символы с помощью preg_replace.
>>782394
Нет, не проще. Это костыли. Это не проще, а сложнее и больше шанс ошибиться. Где гарантия что ты перечислишь все пааки и ничего не забудешь? В команде, кто-то может добавить новый файл и не закрыть доступ к нему. Публичная папка потому и называется публичная что в нее кладется то, что предназначено для публичного распространения. Что не предназначено - не надо туда класть.
>>782503
>>782508
Не знаю, займсиь отладкой, смотри что приходит, что уходит.
>>783071
С "а" или "но" ненадежно сделано - перед ним может быть не только запятая, но и например двоеточие или другой знак. Пробел не обязательно будет ровно один.
В остальном верно.
Тут то же самое замечание, в остальном верно.
в общем верно, хотя у тебя он не подсветит вторую опечатку в том же слове вроде тOпOр
>>784017
http://ideone.com/0hmsEY // Кошки-мышки
Константы заводить не требуется - можно использовать имя класса и получать его как Cat::CLASS
> protected $xy = array();
Непонятно, зачем тут массив и какое у него преимущество перед 2 отдельными полями. Скорее наоборот, неудобно работать.
Ну и вроде по этой задаче я уже писал ниже: >>791267 >>792620
Не знаю.
>>785859
>>785862
Надо использовать повторение. Ну например a{5} ищет 5 букв a подряд, \d{5} ищет 5 цифр подряд - тебе надо примерно то же.
> но я не могу понять как, если бы не было пробелов, скобок и -, я бы написал [\d]{10} но это не прокатит
Можно взять часть выражения в круглые скобки и применить повторение к ним.
>>785910
Молодец, верно.
>>785990
Я тоже не знаю.
>>786040
Если это метод вида "проверить что похоже на имя" то конечно надо передавать свойство так как этот метод можно испоьзовать и для фамилии. Если другой метод то надо смотреть как выгоднее.
>>786745
Не, там надо по-другому. Разбиваешь стих на строки. Сначала выводишь первую букву каждой строки, затем вторую, затем третью и тд.
Не знаю.
>>785859
>>785862
Надо использовать повторение. Ну например a{5} ищет 5 букв a подряд, \d{5} ищет 5 цифр подряд - тебе надо примерно то же.
> но я не могу понять как, если бы не было пробелов, скобок и -, я бы написал [\d]{10} но это не прокатит
Можно взять часть выражения в круглые скобки и применить повторение к ним.
>>785910
Молодец, верно.
>>785990
Я тоже не знаю.
>>786040
Если это метод вида "проверить что похоже на имя" то конечно надо передавать свойство так как этот метод можно испоьзовать и для фамилии. Если другой метод то надо смотреть как выгоднее.
>>786745
Не, там надо по-другому. Разбиваешь стих на строки. Сначала выводишь первую букву каждой строки, затем вторую, затем третью и тд.
Не пишите здесь больше, никто не прочтет. Переходите в новый тред.
Это копия, сохраненная 19 июля 2016 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.